mirror of
https://github.com/opencv/opencv.git
synced 2024-11-27 12:40:05 +08:00
Merge pull request #25809 from zihaomu:imread_rgb_flag
imgcodecs: Add rgb flag for imread and imdecode #25809 Try to `imread` images by RGB to save R-B swapping costs. ## How to use it? ``` img_rgb = cv2.imread("PATH", IMREAD_COLOR_RGB) # OpenCV decode the image by RGB format. ``` ## TODO - [x] Fix the broken code - [x] Add imread rgb test - [x] Speed test of rgb mode. ## Performance test | file name | IMREAD_COLOR | IMREAD_COLOR_RGB | | --------- | ------ | --------- | | jpg01 | 284 ms | 277 ms | | jpg02 | 376 ms | 366 ms | | png01 | 62 ms | 60 ms | | Png02 | 97 ms | 94 ms | Test with [image_test.zip](https://github.com/user-attachments/files/15982949/image_test.zip) ```.cpp string img_path = "/Users/mzh/work/data/image_test/png02.png"; int loop = 20; TickMeter t; double t0 = 10000; for (int i = 0; i < loop; i++) { t.reset(); t.start(); img_bgr = imread(img_path, IMREAD_COLOR); t.stop(); if (t.getTimeMilli() < t0) t0 = t.getTimeMilli(); } std::cout<<"bgr time = "<<t0<<std::endl; t0 = 10000; for (int i = 0; i < loop; i++) { t.reset(); t.start(); img_rgb = imread(img_path, IMREAD_COLOR_RGB); t.stop(); if (t.getTimeMilli() < t0) t0 = t.getTimeMilli(); } std::cout<<"rgb time = "<<t0<<std::endl; ``` ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [ ] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
parent
a7fd9446cf
commit
934e6899f8
@ -68,7 +68,8 @@ namespace cv
|
||||
enum ImreadModes {
|
||||
IMREAD_UNCHANGED = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped). Ignore EXIF orientation.
|
||||
IMREAD_GRAYSCALE = 0, //!< If set, always convert image to the single channel grayscale image (codec internal conversion).
|
||||
IMREAD_COLOR = 1, //!< If set, always convert image to the 3 channel BGR color image.
|
||||
IMREAD_COLOR_BGR = 1, //!< If set, always convert image to the 3 channel BGR color image.
|
||||
IMREAD_COLOR = 1, //!< Same as IMREAD_COLOR_BGR.
|
||||
IMREAD_ANYDEPTH = 2, //!< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
|
||||
IMREAD_ANYCOLOR = 4, //!< If set, the image is read in any possible color format.
|
||||
IMREAD_LOAD_GDAL = 8, //!< If set, use the gdal driver for loading the image.
|
||||
@ -78,7 +79,8 @@ enum ImreadModes {
|
||||
IMREAD_REDUCED_COLOR_4 = 33, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4.
|
||||
IMREAD_REDUCED_GRAYSCALE_8 = 64, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/8.
|
||||
IMREAD_REDUCED_COLOR_8 = 65, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8.
|
||||
IMREAD_IGNORE_ORIENTATION = 128 //!< If set, do not rotate the image according to EXIF's orientation flag.
|
||||
IMREAD_IGNORE_ORIENTATION = 128, //!< If set, do not rotate the image according to EXIF's orientation flag.
|
||||
IMREAD_COLOR_RGB = 256, //!< If set, always convert image to the 3 channel RGB color image.
|
||||
};
|
||||
|
||||
//! Imwrite flags
|
||||
@ -268,7 +270,7 @@ Currently, the following file formats are supported:
|
||||
@param filename Name of file to be loaded.
|
||||
@param flags Flag that can take values of cv::ImreadModes
|
||||
*/
|
||||
CV_EXPORTS_W Mat imread( const String& filename, int flags = IMREAD_COLOR );
|
||||
CV_EXPORTS_W Mat imread( const String& filename, int flags = IMREAD_COLOR_BGR );
|
||||
|
||||
/** @brief Loads an image from a file.
|
||||
|
||||
@ -279,7 +281,7 @@ This is an overloaded member function, provided for convenience. It differs from
|
||||
@note
|
||||
The image passing through the img parameter can be pre-allocated. The memory is reused if the shape and the type match with the load image.
|
||||
*/
|
||||
CV_EXPORTS_W void imread( const String& filename, OutputArray dst, int flags = IMREAD_COLOR );
|
||||
CV_EXPORTS_W void imread( const String& filename, OutputArray dst, int flags = IMREAD_COLOR_BGR );
|
||||
|
||||
/** @brief Loads a multi-page image from a file.
|
||||
|
||||
|
@ -27,6 +27,23 @@ PERF_TEST(JPEG, Decode)
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST(JPEG, Decode_rgb)
|
||||
{
|
||||
String filename = getDataPath("stitching/boat1.jpg");
|
||||
|
||||
FILE *f = fopen(filename.c_str(), "rb");
|
||||
fseek(f, 0, SEEK_END);
|
||||
long len = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
vector<uchar> file_buf((size_t)len);
|
||||
EXPECT_EQ(len, (long)fread(&file_buf[0], 1, (size_t)len, f));
|
||||
fclose(f); f = NULL;
|
||||
|
||||
TEST_CYCLE() imdecode(file_buf, IMREAD_COLOR_RGB);
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST(JPEG, Encode)
|
||||
{
|
||||
String filename = getDataPath("stitching/boat1.jpg");
|
||||
|
@ -30,6 +30,23 @@ PERF_TEST(PNG, decode)
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST(PNG, decode_rgb)
|
||||
{
|
||||
String filename = getDataPath("perf/2560x1600.png");
|
||||
|
||||
FILE *f = fopen(filename.c_str(), "rb");
|
||||
fseek(f, 0, SEEK_END);
|
||||
long len = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
vector<uchar> file_buf((size_t)len);
|
||||
EXPECT_EQ(len, (long)fread(&file_buf[0], 1, (size_t)len, f));
|
||||
fclose(f); f = NULL;
|
||||
|
||||
TEST_CYCLE() imdecode(file_buf, IMREAD_COLOR_RGB);
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST(PNG, encode)
|
||||
{
|
||||
String filename = getDataPath("perf/2560x1600.png");
|
||||
|
@ -33,7 +33,7 @@ struct AvifImageDeleter {
|
||||
|
||||
using AvifImageUniquePtr = std::unique_ptr<avifImage, AvifImageDeleter>;
|
||||
|
||||
avifResult CopyToMat(const avifImage *image, int channels, Mat *mat) {
|
||||
avifResult CopyToMat(const avifImage *image, int channels, bool useRGB , Mat *mat) {
|
||||
CV_Assert((int)image->height == mat->rows);
|
||||
CV_Assert((int)image->width == mat->cols);
|
||||
if (channels == 1) {
|
||||
@ -53,7 +53,10 @@ avifResult CopyToMat(const avifImage *image, int channels, Mat *mat) {
|
||||
avifRGBImage rgba;
|
||||
avifRGBImageSetDefaults(&rgba, image);
|
||||
if (channels == 3) {
|
||||
rgba.format = AVIF_RGB_FORMAT_BGR;
|
||||
if (useRGB)
|
||||
rgba.format = AVIF_RGB_FORMAT_RGB;
|
||||
else
|
||||
rgba.format = AVIF_RGB_FORMAT_BGR;
|
||||
} else {
|
||||
CV_Assert(channels == 4);
|
||||
rgba.format = AVIF_RGB_FORMAT_BGRA;
|
||||
@ -227,7 +230,7 @@ bool AvifDecoder::readData(Mat &img) {
|
||||
is_first_image_ = false;
|
||||
}
|
||||
|
||||
if (CopyToMat(decoder_->image, channels_, &read_img) != AVIF_RESULT_OK) {
|
||||
if (CopyToMat(decoder_->image, channels_, m_use_rgb, &read_img) != AVIF_RESULT_OK) {
|
||||
CV_Error(Error::StsInternal, "Cannot convert from AVIF to Mat");
|
||||
return false;
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ BaseImageDecoder::BaseImageDecoder()
|
||||
m_type = -1;
|
||||
m_buf_supported = false;
|
||||
m_scale_denom = 1;
|
||||
m_use_rgb = false;
|
||||
}
|
||||
|
||||
|
||||
@ -94,6 +95,11 @@ int BaseImageDecoder::setScale( const int& scale_denom )
|
||||
return temp;
|
||||
}
|
||||
|
||||
void BaseImageDecoder::setRGB(bool useRGB)
|
||||
{
|
||||
m_use_rgb = useRGB;
|
||||
}
|
||||
|
||||
ImageDecoder BaseImageDecoder::newDecoder() const
|
||||
{
|
||||
return ImageDecoder();
|
||||
|
@ -73,6 +73,8 @@ public:
|
||||
virtual bool readHeader() = 0;
|
||||
virtual bool readData( Mat& img ) = 0;
|
||||
|
||||
virtual void setRGB(bool useRGB);
|
||||
|
||||
/// Called after readData to advance to the next page, if any.
|
||||
virtual bool nextPage() { return false; }
|
||||
|
||||
@ -89,6 +91,7 @@ protected:
|
||||
String m_signature;
|
||||
Mat m_buf;
|
||||
bool m_buf_supported;
|
||||
bool m_use_rgb; // flag of decode image as RGB order instead of BGR.
|
||||
ExifReader m_exif;
|
||||
};
|
||||
|
||||
|
@ -544,6 +544,11 @@ decode_rle8_bad: ;
|
||||
throw;
|
||||
}
|
||||
|
||||
if (m_use_rgb && color && img.channels() == 3)
|
||||
{
|
||||
cv::cvtColor(img, img, cv::COLOR_BGR2RGB);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -373,18 +373,35 @@ bool ExrDecoder::readData( Mat& img )
|
||||
|
||||
if( m_iscolor )
|
||||
{
|
||||
if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
|
||||
UpSample( data, channelstoread, step / xstep, m_blue->xSampling, m_blue->ySampling );
|
||||
if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
|
||||
UpSample( data + xstep, channelstoread, step / xstep, m_green->xSampling, m_green->ySampling );
|
||||
if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
|
||||
UpSample( data + 2 * xstep, channelstoread, step / xstep, m_red->xSampling, m_red->ySampling );
|
||||
if (m_use_rgb)
|
||||
{
|
||||
if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
|
||||
UpSample( data, channelstoread, step / xstep, m_red->xSampling, m_red->ySampling );
|
||||
if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
|
||||
UpSample( data + xstep, channelstoread, step / xstep, m_green->xSampling, m_green->ySampling );
|
||||
if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
|
||||
UpSample( data + 2 * xstep, channelstoread, step / xstep, m_blue->xSampling, m_blue->ySampling );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
|
||||
UpSample( data, channelstoread, step / xstep, m_blue->xSampling, m_blue->ySampling );
|
||||
if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
|
||||
UpSample( data + xstep, channelstoread, step / xstep, m_green->xSampling, m_green->ySampling );
|
||||
if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
|
||||
UpSample( data + 2 * xstep, channelstoread, step / xstep, m_red->xSampling, m_red->ySampling );
|
||||
}
|
||||
}
|
||||
else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
|
||||
UpSample( data, channelstoread, step / xstep, m_green->xSampling, m_green->ySampling );
|
||||
|
||||
if( chromatorgb )
|
||||
ChromaToBGR( (float *)data, m_height, channelstoread, step / xstep );
|
||||
{
|
||||
if (m_use_rgb)
|
||||
ChromaToRGB( (float *)data, m_height, channelstoread, step / xstep );
|
||||
else
|
||||
ChromaToBGR( (float *)data, m_height, channelstoread, step / xstep );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -406,7 +423,12 @@ bool ExrDecoder::readData( Mat& img )
|
||||
else
|
||||
{
|
||||
if( chromatorgb )
|
||||
ChromaToBGR( (float *)buffer, 1, defaultchannels, step );
|
||||
{
|
||||
if (m_use_rgb)
|
||||
ChromaToRGB( (float *)buffer, 1, defaultchannels, step );
|
||||
else
|
||||
ChromaToBGR( (float *)buffer, 1, defaultchannels, step );
|
||||
}
|
||||
|
||||
if( m_type == FLOAT )
|
||||
{
|
||||
@ -430,12 +452,24 @@ bool ExrDecoder::readData( Mat& img )
|
||||
}
|
||||
if( color )
|
||||
{
|
||||
if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
|
||||
UpSampleY( data, defaultchannels, step / xstep, m_blue->ySampling );
|
||||
if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
|
||||
UpSampleY( data + xstep, defaultchannels, step / xstep, m_green->ySampling );
|
||||
if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
|
||||
UpSampleY( data + 2 * xstep, defaultchannels, step / xstep, m_red->ySampling );
|
||||
if (m_use_rgb)
|
||||
{
|
||||
if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
|
||||
UpSampleY( data, defaultchannels, step / xstep, m_red->ySampling );
|
||||
if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
|
||||
UpSampleY( data + xstep, defaultchannels, step / xstep, m_green->ySampling );
|
||||
if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
|
||||
UpSampleY( data + 2 * xstep, defaultchannels, step / xstep, m_blue->ySampling );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
|
||||
UpSampleY( data, defaultchannels, step / xstep, m_blue->ySampling );
|
||||
if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
|
||||
UpSampleY( data + xstep, defaultchannels, step / xstep, m_green->ySampling );
|
||||
if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
|
||||
UpSampleY( data + 2 * xstep, defaultchannels, step / xstep, m_red->ySampling );
|
||||
}
|
||||
}
|
||||
else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
|
||||
UpSampleY( data, 1, step / xstep, m_green->ySampling );
|
||||
@ -558,6 +592,47 @@ void ExrDecoder::ChromaToBGR( float *data, int numlines, int xstep, int ystep )
|
||||
}
|
||||
}
|
||||
|
||||
void ExrDecoder::ChromaToRGB(float *data, int numlines, int xstep, int ystep)
|
||||
{
|
||||
for( int y = 0; y < numlines; y++ )
|
||||
{
|
||||
for( int x = 0; x < m_width; x++ )
|
||||
{
|
||||
double b, Y, r;
|
||||
if( m_type == FLOAT )
|
||||
{
|
||||
b = data[y * ystep + x * xstep];
|
||||
Y = data[y * ystep + x * xstep + 1];
|
||||
r = data[y * ystep + x * xstep + 2];
|
||||
}
|
||||
else
|
||||
{
|
||||
b = ((unsigned *)data)[y * ystep + x * xstep];
|
||||
Y = ((unsigned *)data)[y * ystep + x * xstep + 1];
|
||||
r = ((unsigned *)data)[y * ystep + x * xstep + 2];
|
||||
}
|
||||
r = (r + 1) * Y;
|
||||
b = (b + 1) * Y;
|
||||
Y = (Y - b * m_chroma.blue[1] - r * m_chroma.red[1]) / m_chroma.green[1];
|
||||
|
||||
if( m_type == FLOAT )
|
||||
{
|
||||
data[y * ystep + x * xstep] = (float)r;
|
||||
data[y * ystep + x * xstep + 1] = (float)Y;
|
||||
data[y * ystep + x * xstep + 2] = (float)b;
|
||||
}
|
||||
else
|
||||
{
|
||||
int t = cvRound(r);
|
||||
((unsigned *)data)[y * ystep + x * xstep + 0] = (unsigned)MAX(t, 0);
|
||||
t = cvRound(Y);
|
||||
((unsigned *)data)[y * ystep + x * xstep + 1] = (unsigned)MAX(t, 0);
|
||||
t = cvRound(b);
|
||||
((unsigned *)data)[y * ystep + x * xstep + 2] = (unsigned)MAX(t, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
// convert one row to gray
|
||||
|
@ -83,6 +83,7 @@ protected:
|
||||
void UpSampleX( float *data, int xstep, int xsample );
|
||||
void UpSampleY( uchar *data, int xstep, int ystep, int ysample );
|
||||
void ChromaToBGR( float *data, int numlines, int xstep, int ystep );
|
||||
void ChromaToRGB( float *data, int numlines, int xstep, int ystep );
|
||||
void RGBToGray( float *in, float *out );
|
||||
|
||||
InputFile *m_file;
|
||||
|
@ -397,13 +397,13 @@ bool GdalDecoder::readData( Mat& img ){
|
||||
case GCI_PaletteIndex:
|
||||
case GCI_GrayIndex:
|
||||
case GCI_BlueBand:
|
||||
color = 0;
|
||||
color = m_use_rgb ? 2 : 0;
|
||||
break;
|
||||
case GCI_GreenBand:
|
||||
color = 1;
|
||||
break;
|
||||
case GCI_RedBand:
|
||||
color = 2;
|
||||
color = m_use_rgb ? 0 : 2;
|
||||
break;
|
||||
case GCI_AlphaBand:
|
||||
color = 3;
|
||||
|
@ -106,7 +106,13 @@ bool HdrDecoder::readData(Mat& _img)
|
||||
switch (_img.channels())
|
||||
{
|
||||
case 1: cvtColor(img, _img, COLOR_BGR2GRAY); break;
|
||||
case 3: img.copyTo(_img); break;
|
||||
case 3:
|
||||
// TODO, try to modify RGBE_ReadPixels_RLE to load rgb data directly.
|
||||
if (m_use_rgb)
|
||||
cv::cvtColor(img, _img, cv::COLOR_BGR2RGB);
|
||||
else
|
||||
img.copyTo(_img);
|
||||
break;
|
||||
default: CV_Error(Error::StsError, "Wrong expected image channels, allowed: 1 and 3");
|
||||
}
|
||||
return true;
|
||||
|
@ -437,13 +437,13 @@ bool JpegDecoder::readData( Mat& img )
|
||||
if( cinfo->num_components != 4 )
|
||||
{
|
||||
#ifdef JCS_EXTENSIONS
|
||||
cinfo->out_color_space = JCS_EXT_BGR;
|
||||
cinfo->out_color_space = m_use_rgb ? JCS_EXT_RGB : JCS_EXT_BGR;
|
||||
cinfo->out_color_components = 3;
|
||||
doDirectRead = true; // BGR -> BGR
|
||||
#else
|
||||
cinfo->out_color_space = JCS_RGB;
|
||||
cinfo->out_color_components = 3;
|
||||
doDirectRead = false; // RGB -> BGR
|
||||
doDirectRead = m_use_rgb ? true : false; // RGB -> BGR
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@ -514,10 +514,20 @@ bool JpegDecoder::readData( Mat& img )
|
||||
|
||||
if( color )
|
||||
{
|
||||
if( cinfo->out_color_components == 3 )
|
||||
icvCvt_RGB2BGR_8u_C3R( buffer[0], 0, data, 0, Size(m_width,1) );
|
||||
if (m_use_rgb)
|
||||
{
|
||||
if( cinfo->out_color_components == 3 )
|
||||
icvCvt_BGR2RGB_8u_C3R( buffer[0], 0, data, 0, Size(m_width,1) );
|
||||
else
|
||||
icvCvt_CMYK2RGB_8u_C4C3R( buffer[0], 0, data, 0, Size(m_width,1) );
|
||||
}
|
||||
else
|
||||
icvCvt_CMYK2BGR_8u_C4C3R( buffer[0], 0, data, 0, Size(m_width,1) );
|
||||
{
|
||||
if( cinfo->out_color_components == 3 )
|
||||
icvCvt_RGB2BGR_8u_C3R( buffer[0], 0, data, 0, Size(m_width,1) );
|
||||
else
|
||||
icvCvt_CMYK2BGR_8u_C4C3R( buffer[0], 0, data, 0, Size(m_width,1) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -286,11 +286,12 @@ bool Jpeg2KDecoder::readData( Mat& img )
|
||||
{
|
||||
int ncmpts;
|
||||
int cmptlut[3];
|
||||
int swap_rb = m_use_rgb ? 0 : 2;
|
||||
if( color )
|
||||
{
|
||||
cmptlut[0] = jas_image_getcmptbytype( image, JAS_IMAGE_CT_RGB_B );
|
||||
cmptlut[1] = jas_image_getcmptbytype( image, JAS_IMAGE_CT_RGB_G );
|
||||
cmptlut[2] = jas_image_getcmptbytype( image, JAS_IMAGE_CT_RGB_R );
|
||||
cmptlut[0] = jas_image_getcmptbytype( image, swap_rb );
|
||||
cmptlut[1] = jas_image_getcmptbytype( image, 1 );
|
||||
cmptlut[2] = jas_image_getcmptbytype( image, swap_rb^2 );
|
||||
if( cmptlut[0] < 0 || cmptlut[1] < 0 || cmptlut[2] < 0 )
|
||||
result = false;
|
||||
ncmpts = 3;
|
||||
|
@ -350,7 +350,7 @@ opj_cparameters setupEncoderParameters(const std::vector<int>& params)
|
||||
return parameters;
|
||||
}
|
||||
|
||||
bool decodeSRGBData(const opj_image_t& inImg, cv::Mat& outImg, uint8_t shift)
|
||||
bool decodeSRGBData(const opj_image_t& inImg, cv::Mat& outImg, uint8_t shift, bool use_rgb)
|
||||
{
|
||||
using ImageComponents = std::vector<const OPJ_INT32*>;
|
||||
|
||||
@ -377,8 +377,9 @@ bool decodeSRGBData(const opj_image_t& inImg, cv::Mat& outImg, uint8_t shift)
|
||||
|
||||
if (inChannels >= 3)
|
||||
{
|
||||
int swap_rb = use_rgb ? 0 : 2;
|
||||
// Assume RGB (+ alpha) for 3 channels -> BGR
|
||||
ImageComponents incomps { inImg.comps[2].data, inImg.comps[1].data, inImg.comps[0].data };
|
||||
ImageComponents incomps { inImg.comps[swap_rb].data, inImg.comps[1].data, inImg.comps[swap_rb^2].data };
|
||||
// Assume RGBA for 4 channels -> BGRA
|
||||
if (outChannels > 3)
|
||||
{
|
||||
@ -393,7 +394,7 @@ bool decodeSRGBData(const opj_image_t& inImg, cv::Mat& outImg, uint8_t shift)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool decodeGrayscaleData(const opj_image_t& inImg, cv::Mat& outImg, uint8_t shift)
|
||||
bool decodeGrayscaleData(const opj_image_t& inImg, cv::Mat& outImg, uint8_t shift, bool)
|
||||
{
|
||||
using ImageComponents = std::vector<const OPJ_INT32*>;
|
||||
|
||||
@ -411,7 +412,7 @@ bool decodeGrayscaleData(const opj_image_t& inImg, cv::Mat& outImg, uint8_t shif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool decodeSYCCData(const opj_image_t& inImg, cv::Mat& outImg, uint8_t shift)
|
||||
bool decodeSYCCData(const opj_image_t& inImg, cv::Mat& outImg, uint8_t shift, bool use_rgb)
|
||||
{
|
||||
using ImageComponents = std::vector<const OPJ_INT32*>;
|
||||
|
||||
@ -426,7 +427,10 @@ bool decodeSYCCData(const opj_image_t& inImg, cv::Mat& outImg, uint8_t shift)
|
||||
if (outChannels == 3 && inChannels >= 3) {
|
||||
copyToMat(ImageComponents { inImg.comps[0].data, inImg.comps[1].data, inImg.comps[2].data },
|
||||
outImg, shift);
|
||||
cvtColor(outImg, outImg, COLOR_YUV2BGR);
|
||||
if (use_rgb)
|
||||
cvtColor(outImg, outImg, COLOR_YUV2RGB);
|
||||
else
|
||||
cvtColor(outImg, outImg, COLOR_YUV2BGR);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -585,7 +589,7 @@ bool Jpeg2KOpjDecoderBase::readHeader()
|
||||
|
||||
bool Jpeg2KOpjDecoderBase::readData( Mat& img )
|
||||
{
|
||||
using DecodeFunc = bool(*)(const opj_image_t&, cv::Mat&, uint8_t shift);
|
||||
using DecodeFunc = bool(*)(const opj_image_t&, cv::Mat&, uint8_t shift, bool use_rgb);
|
||||
|
||||
if (!opj_decode(codec_.get(), stream_.get(), image_.get()))
|
||||
{
|
||||
@ -647,7 +651,7 @@ bool Jpeg2KOpjDecoderBase::readData( Mat& img )
|
||||
CV_Assert(comp.data && "OpenJPEG2000: missing component data (unsupported / broken input)");
|
||||
}
|
||||
|
||||
return decode(*image_, img, shift);
|
||||
return decode(*image_, img, shift, m_use_rgb);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
@ -90,7 +90,7 @@ const static struct pam_header_field fields[] = {
|
||||
#define PAM_FIELDS_NO (sizeof (fields) / sizeof ((fields)[0]))
|
||||
|
||||
typedef bool (*cvtFunc) (void *src, void *target, int width, int target_channels,
|
||||
int target_depth);
|
||||
int target_depth, bool use_rgb);
|
||||
|
||||
struct channel_layout {
|
||||
uint rchan, gchan, bchan, graychan;
|
||||
@ -108,7 +108,7 @@ struct pam_format {
|
||||
};
|
||||
|
||||
static bool rgb_convert (void *src, void *target, int width, int target_channels,
|
||||
int target_depth);
|
||||
int target_depth, bool use_rgb);
|
||||
|
||||
const static struct pam_format formats[] = {
|
||||
{IMWRITE_PAM_FORMAT_NULL, "", NULL, {0, 0, 0, 0} },
|
||||
@ -125,19 +125,25 @@ const static struct pam_format formats[] = {
|
||||
*/
|
||||
|
||||
static bool
|
||||
rgb_convert (void *src, void *target, int width, int target_channels, int target_depth)
|
||||
rgb_convert (void *src, void *target, int width, int target_channels, int target_depth, bool use_rgb)
|
||||
{
|
||||
bool ret = false;
|
||||
if (target_channels == 3) {
|
||||
switch (target_depth) {
|
||||
case CV_8U:
|
||||
icvCvt_RGB2BGR_8u_C3R( (uchar*) src, 0, (uchar*) target, 0,
|
||||
Size(width,1) );
|
||||
if (use_rgb)
|
||||
memcpy(target, src, sizeof(uchar) * width);
|
||||
else
|
||||
icvCvt_RGB2BGR_8u_C3R( (uchar*) src, 0, (uchar*) target, 0,
|
||||
Size(width,1) );
|
||||
ret = true;
|
||||
break;
|
||||
case CV_16U:
|
||||
icvCvt_RGB2BGR_16u_C3R( (ushort *)src, 0, (ushort *)target, 0,
|
||||
Size(width,1) );
|
||||
if (use_rgb)
|
||||
memcpy(target, src, sizeof(ushort) * width);
|
||||
else
|
||||
icvCvt_RGB2BGR_16u_C3R( (ushort *)src, 0, (ushort *)target, 0,
|
||||
Size(width,1) );
|
||||
ret = true;
|
||||
break;
|
||||
default:
|
||||
@ -169,7 +175,7 @@ rgb_convert (void *src, void *target, int width, int target_channels, int target
|
||||
|
||||
static void
|
||||
basic_conversion (void *src, const struct channel_layout *layout, int src_sampe_size,
|
||||
int src_width, void *target, int target_channels, int target_depth)
|
||||
int src_width, void *target, int target_channels, int target_depth, bool use_rgb)
|
||||
{
|
||||
switch (target_depth) {
|
||||
case CV_8U:
|
||||
@ -182,11 +188,18 @@ basic_conversion (void *src, const struct channel_layout *layout, int src_sampe_
|
||||
d[0] = d[1] = d[2] = s[layout->graychan];
|
||||
break;
|
||||
case 3:
|
||||
for( ; s < end; d += 3, s += src_sampe_size ) {
|
||||
d[0] = s[layout->bchan];
|
||||
d[1] = s[layout->gchan];
|
||||
d[2] = s[layout->rchan];
|
||||
}
|
||||
if (use_rgb)
|
||||
for( ; s < end; d += 3, s += src_sampe_size ) {
|
||||
d[0] = s[layout->rchan];
|
||||
d[1] = s[layout->gchan];
|
||||
d[2] = s[layout->bchan];
|
||||
}
|
||||
else
|
||||
for( ; s < end; d += 3, s += src_sampe_size ) {
|
||||
d[0] = s[layout->bchan];
|
||||
d[1] = s[layout->gchan];
|
||||
d[2] = s[layout->rchan];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsInternal, "");
|
||||
@ -203,11 +216,18 @@ basic_conversion (void *src, const struct channel_layout *layout, int src_sampe_
|
||||
d[0] = d[1] = d[2] = s[layout->graychan];
|
||||
break;
|
||||
case 3:
|
||||
for( ; s < end; d += 3, s += src_sampe_size ) {
|
||||
d[0] = s[layout->bchan];
|
||||
d[1] = s[layout->gchan];
|
||||
d[2] = s[layout->rchan];
|
||||
}
|
||||
if (use_rgb)
|
||||
for( ; s < end; d += 3, s += src_sampe_size ) {
|
||||
d[0] = s[layout->rchan];
|
||||
d[1] = s[layout->gchan];
|
||||
d[2] = s[layout->bchan];
|
||||
}
|
||||
else
|
||||
for( ; s < end; d += 3, s += src_sampe_size ) {
|
||||
d[0] = s[layout->bchan];
|
||||
d[1] = s[layout->gchan];
|
||||
d[2] = s[layout->rchan];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsInternal, "");
|
||||
@ -610,18 +630,18 @@ bool PAMDecoder::readData(Mat& img)
|
||||
bool funcout = false;
|
||||
if (fmt->cvt_func)
|
||||
funcout = fmt->cvt_func (src, data, m_width, target_channels,
|
||||
img.depth());
|
||||
img.depth(), m_use_rgb);
|
||||
/* fall back to default if there is no conversion function or it
|
||||
* can't handle the specified characteristics
|
||||
*/
|
||||
if (!funcout)
|
||||
basic_conversion (src, &fmt->layout, m_channels,
|
||||
m_width, data, target_channels, img.depth());
|
||||
m_width, data, target_channels, img.depth(), m_use_rgb);
|
||||
|
||||
/* default to selecting the first available channels */
|
||||
} else {
|
||||
basic_conversion (src, &layout, m_channels,
|
||||
m_width, data, target_channels, img.depth());
|
||||
m_width, data, target_channels, img.depth(), m_use_rgb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ bool PFMDecoder::readData(Mat& mat)
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer.channels() == 3) {
|
||||
if (buffer.channels() == 3 && !m_use_rgb) {
|
||||
cv::cvtColor(buffer, buffer, cv::COLOR_BGR2RGB);
|
||||
}
|
||||
|
||||
|
@ -261,7 +261,7 @@ bool PngDecoder::readData( Mat& img )
|
||||
png_set_gray_1_2_4_to_8( png_ptr );
|
||||
#endif
|
||||
|
||||
if( (m_color_type & PNG_COLOR_MASK_COLOR) && color )
|
||||
if( (m_color_type & PNG_COLOR_MASK_COLOR) && color && !m_use_rgb)
|
||||
png_set_bgr( png_ptr ); // convert RGB to BGR
|
||||
else if( color )
|
||||
png_set_gray_to_rgb( png_ptr ); // Gray->RGB
|
||||
|
@ -340,7 +340,9 @@ bool PxMDecoder::readData( Mat& img )
|
||||
{
|
||||
if( color )
|
||||
{
|
||||
if( img.depth() == CV_8U )
|
||||
if (m_use_rgb)
|
||||
memcpy(data, src, m_width * CV_ELEM_SIZE(img.type()));
|
||||
else if( img.depth() == CV_8U )
|
||||
icvCvt_RGB2BGR_8u_C3R( src, 0, data, 0, Size(m_width,1) );
|
||||
else
|
||||
icvCvt_RGB2BGR_16u_C3R( (ushort *)src, 0, (ushort *)data, 0, Size(m_width,1) );
|
||||
|
@ -381,14 +381,14 @@ bool SPngDecoder::readData(Mat &img)
|
||||
break;
|
||||
|
||||
ret = spng_decode_row(png_ptr, buffer[row_info.row_num], image_width);
|
||||
if (ihdr.interlace_method == 0)
|
||||
if (ihdr.interlace_method == 0 && !m_use_rgb)
|
||||
{
|
||||
icvCvt_RGBA2BGRA_16u_C4R(reinterpret_cast<const ushort *>(buffer[row_info.row_num]), 0,
|
||||
reinterpret_cast<ushort *>(buffer[row_info.row_num]), 0,
|
||||
Size(m_width, 1));
|
||||
}
|
||||
} while (ret == SPNG_OK);
|
||||
if (ihdr.interlace_method)
|
||||
if (ihdr.interlace_method && !m_use_rgb)
|
||||
{
|
||||
icvCvt_RGBA2BGRA_16u_C4R(reinterpret_cast<const ushort *>(img.data), step * 2, reinterpret_cast<ushort *>(img.data), step * 2, Size(m_width, m_height));
|
||||
}
|
||||
@ -402,12 +402,12 @@ bool SPngDecoder::readData(Mat &img)
|
||||
break;
|
||||
|
||||
ret = spng_decode_row(png_ptr, buffer[row_info.row_num], image_width);
|
||||
if (ihdr.interlace_method == 0)
|
||||
if (ihdr.interlace_method == 0 && !m_use_rgb)
|
||||
{
|
||||
icvCvt_RGBA2BGRA_8u_C4R(buffer[row_info.row_num], 0, buffer[row_info.row_num], 0, Size(m_width, 1));
|
||||
}
|
||||
} while (ret == SPNG_OK);
|
||||
if (ihdr.interlace_method)
|
||||
if (ihdr.interlace_method && !m_use_rgb)
|
||||
{
|
||||
icvCvt_RGBA2BGRA_8u_C4R(img.data, step, img.data, step, Size(m_width, m_height));
|
||||
}
|
||||
@ -421,13 +421,13 @@ bool SPngDecoder::readData(Mat &img)
|
||||
break;
|
||||
|
||||
ret = spng_decode_row(png_ptr, buffer[row_info.row_num], image_width);
|
||||
if (ihdr.interlace_method == 0)
|
||||
if (ihdr.interlace_method == 0 && !m_use_rgb)
|
||||
{
|
||||
icvCvt_RGB2BGR_16u_C3R(reinterpret_cast<const ushort *>(buffer[row_info.row_num]), 0,
|
||||
reinterpret_cast<ushort *>(buffer[row_info.row_num]), 0, Size(m_width, 1));
|
||||
}
|
||||
} while (ret == SPNG_OK);
|
||||
if (ihdr.interlace_method)
|
||||
if (ihdr.interlace_method && !m_use_rgb)
|
||||
{
|
||||
icvCvt_RGB2BGR_16u_C3R(reinterpret_cast<const ushort *>(img.data), step,
|
||||
reinterpret_cast<ushort *>(img.data), step, Size(m_width, m_height));
|
||||
@ -442,12 +442,12 @@ bool SPngDecoder::readData(Mat &img)
|
||||
break;
|
||||
|
||||
ret = spng_decode_row(png_ptr, buffer[row_info.row_num], image_width);
|
||||
if (ihdr.interlace_method == 0)
|
||||
if (ihdr.interlace_method == 0 && !m_use_rgb)
|
||||
{
|
||||
icvCvt_RGB2BGR_8u_C3R(buffer[row_info.row_num], 0, buffer[row_info.row_num], 0, Size(m_width, 1));
|
||||
}
|
||||
} while (ret == SPNG_OK);
|
||||
if (ihdr.interlace_method)
|
||||
if (ihdr.interlace_method && !m_use_rgb)
|
||||
{
|
||||
icvCvt_RGB2BGR_8u_C3R(img.data, step, img.data, step, Size(m_width, m_height));
|
||||
}
|
||||
|
@ -342,7 +342,7 @@ bad_decoding_end:
|
||||
|
||||
if( color )
|
||||
{
|
||||
if( m_type == RAS_FORMAT_RGB )
|
||||
if( m_type == RAS_FORMAT_RGB || m_use_rgb)
|
||||
icvCvt_RGB2BGR_8u_C3R(src, 0, data, 0, Size(m_width,1) );
|
||||
else
|
||||
memcpy(data, src, std::min(step, (size_t)src_pitch));
|
||||
@ -365,7 +365,7 @@ bad_decoding_end:
|
||||
|
||||
if( color )
|
||||
icvCvt_BGRA2BGR_8u_C4C3R( src + 4, 0, data, 0, Size(m_width,1),
|
||||
m_type == RAS_FORMAT_RGB ? 2 : 0 );
|
||||
(m_type == RAS_FORMAT_RGB || m_use_rgb) ? 2 : 0 );
|
||||
else
|
||||
icvCvt_BGRA2Gray_8u_C4C1R( src + 4, 0, data, 0, Size(m_width,1),
|
||||
m_type == RAS_FORMAT_RGB ? 2 : 0 );
|
||||
|
@ -865,9 +865,14 @@ bool TiffDecoder::readData( Mat& img )
|
||||
break;
|
||||
|
||||
case MAKE_FLAG( 3, 3 ): // RGB to BGR
|
||||
icvCvt_BGR2RGB_8u_C3R( bstart, 0,
|
||||
img_line_buffer, 0,
|
||||
Size(tile_width, 1) );
|
||||
if (m_use_rgb)
|
||||
memcpy( (void*) img_line_buffer,
|
||||
(void*) bstart,
|
||||
tile_width * sizeof(uchar) );
|
||||
else
|
||||
icvCvt_BGR2RGB_8u_C3R( bstart, 0,
|
||||
img_line_buffer, 0,
|
||||
Size(tile_width, 1) );
|
||||
break;
|
||||
|
||||
case MAKE_FLAG( 4, 1 ): // RGBA to GRAY
|
||||
@ -879,7 +884,7 @@ bool TiffDecoder::readData( Mat& img )
|
||||
case MAKE_FLAG( 4, 3 ): // RGBA to BGR
|
||||
icvCvt_BGRA2BGR_8u_C4C3R( bstart, 0,
|
||||
img_line_buffer, 0,
|
||||
Size(tile_width, 1), 2 );
|
||||
Size(tile_width, 1), m_use_rgb ? 0 : 2);
|
||||
break;
|
||||
|
||||
case MAKE_FLAG( 4, 4 ): // RGBA to BGRA
|
||||
@ -909,7 +914,7 @@ bool TiffDecoder::readData( Mat& img )
|
||||
CV_CheckEQ(wanted_channels, 3, "TIFF-8bpp: BGR/BGRA images are supported only");
|
||||
icvCvt_BGRA2BGR_8u_C4C3R(bstart + i*tile_width0*4, 0,
|
||||
img.ptr(img_y + tile_height - i - 1, x), 0,
|
||||
Size(tile_width, 1), 2);
|
||||
Size(tile_width, 1), m_use_rgb ? 0 : 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -972,9 +977,12 @@ bool TiffDecoder::readData( Mat& img )
|
||||
else if (ncn == 3)
|
||||
{
|
||||
CV_CheckEQ(wanted_channels, 3, "");
|
||||
icvCvt_RGB2BGR_16u_C3R(buffer16, 0,
|
||||
img.ptr<ushort>(img_y + i, x), 0,
|
||||
Size(tile_width, 1));
|
||||
if (m_use_rgb)
|
||||
memcpy(buffer16, img.ptr<ushort>(img_y + i, x), tile_width * sizeof(ushort));
|
||||
else
|
||||
icvCvt_RGB2BGR_16u_C3R(buffer16, 0,
|
||||
img.ptr<ushort>(img_y + i, x), 0,
|
||||
Size(tile_width, 1));
|
||||
}
|
||||
else if (ncn == 4)
|
||||
{
|
||||
@ -989,7 +997,7 @@ bool TiffDecoder::readData( Mat& img )
|
||||
CV_CheckEQ(wanted_channels, 3, "TIFF-16bpp: BGR/BGRA images are supported only");
|
||||
icvCvt_BGRA2BGR_16u_C4C3R(buffer16, 0,
|
||||
img.ptr<ushort>(img_y + i, x), 0,
|
||||
Size(tile_width, 1), 2);
|
||||
Size(tile_width, 1), m_use_rgb ? 0 : 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1032,7 +1040,7 @@ bool TiffDecoder::readData( Mat& img )
|
||||
Mat m_tile(Size(tile_width0, tile_height0), CV_MAKETYPE((dst_bpp == 32) ? (depth == CV_32S ? CV_32S : CV_32F) : CV_64F, ncn), src_buffer);
|
||||
Rect roi_tile(0, 0, tile_width, tile_height);
|
||||
Rect roi_img(x, img_y, tile_width, tile_height);
|
||||
if (!m_hdr && ncn == 3)
|
||||
if (!m_hdr && ncn == 3 && !m_use_rgb)
|
||||
extend_cvtColor(m_tile(roi_tile), img(roi_img), COLOR_RGB2BGR);
|
||||
else if (!m_hdr && ncn == 4)
|
||||
extend_cvtColor(m_tile(roi_tile), img(roi_img), COLOR_RGBA2BGRA);
|
||||
@ -1060,7 +1068,10 @@ bool TiffDecoder::readData( Mat& img )
|
||||
if (m_hdr && depth >= CV_32F)
|
||||
{
|
||||
CV_Assert(photometric == PHOTOMETRIC_LOGLUV);
|
||||
cvtColor(img, img, COLOR_XYZ2BGR);
|
||||
if (m_use_rgb)
|
||||
cvtColor(img, img, COLOR_XYZ2RGB);
|
||||
else
|
||||
cvtColor(img, img, COLOR_XYZ2BGR);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -184,14 +184,22 @@ bool WebPDecoder::readData(Mat &img)
|
||||
if (channels == 3)
|
||||
{
|
||||
CV_CheckTypeEQ(read_img.type(), CV_8UC3, "");
|
||||
res_ptr = WebPDecodeBGRInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
if (m_use_rgb)
|
||||
res_ptr = WebPDecodeRGBInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
else
|
||||
res_ptr = WebPDecodeBGRInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
}
|
||||
else if (channels == 4)
|
||||
{
|
||||
CV_CheckTypeEQ(read_img.type(), CV_8UC4, "");
|
||||
res_ptr = WebPDecodeBGRAInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
if (m_use_rgb)
|
||||
res_ptr = WebPDecodeRGBAInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
else
|
||||
res_ptr = WebPDecodeBGRAInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
}
|
||||
|
||||
if (res_ptr != out_data)
|
||||
|
@ -88,7 +88,7 @@ static inline int calcType(int type, int flags)
|
||||
if( (flags & IMREAD_ANYDEPTH) == 0 )
|
||||
type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
|
||||
|
||||
if( (flags & IMREAD_COLOR) != 0 ||
|
||||
if( (flags & IMREAD_COLOR) != 0 || (flags & IMREAD_COLOR_RGB) != 0 ||
|
||||
((flags & IMREAD_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1) )
|
||||
type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);
|
||||
else
|
||||
@ -432,6 +432,12 @@ imread_( const String& filename, int flags, OutputArray mat )
|
||||
scale_denom = 8;
|
||||
}
|
||||
|
||||
// Try to decode image by RGB instead of BGR.
|
||||
if (flags & IMREAD_COLOR_RGB && flags != IMREAD_UNCHANGED)
|
||||
{
|
||||
decoder->setRGB(true);
|
||||
}
|
||||
|
||||
/// set the scale_denom in the driver
|
||||
decoder->setScale( scale_denom );
|
||||
|
||||
@ -542,6 +548,9 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats, int star
|
||||
count = std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
if (flags & IMREAD_COLOR_RGB && flags != IMREAD_UNCHANGED)
|
||||
decoder->setRGB(true);
|
||||
|
||||
/// set the filename in the driver
|
||||
decoder->setSource(filename);
|
||||
|
||||
@ -829,6 +838,12 @@ imdecode_( const Mat& buf, int flags, Mat& mat )
|
||||
scale_denom = 8;
|
||||
}
|
||||
|
||||
// Try to decode image by RGB instead of BGR.
|
||||
if (flags & IMREAD_COLOR_RGB && flags != IMREAD_UNCHANGED)
|
||||
{
|
||||
decoder->setRGB(true);
|
||||
}
|
||||
|
||||
/// set the scale_denom in the driver
|
||||
decoder->setScale( scale_denom );
|
||||
|
||||
@ -965,6 +980,12 @@ imdecodemulti_(const Mat& buf, int flags, std::vector<Mat>& mats, int start, int
|
||||
if (!decoder)
|
||||
return 0;
|
||||
|
||||
// Try to decode image by RGB instead of BGR.
|
||||
if (flags & IMREAD_COLOR_RGB && flags != IMREAD_UNCHANGED)
|
||||
{
|
||||
decoder->setRGB(true);
|
||||
}
|
||||
|
||||
if (count < 0) {
|
||||
count = std::numeric_limits<int>::max();
|
||||
}
|
||||
|
@ -352,6 +352,25 @@ void icvCvt_CMYK2BGR_8u_C4C3R( const uchar* cmyk, int cmyk_step,
|
||||
}
|
||||
}
|
||||
|
||||
void icvCvt_CMYK2RGB_8u_C4C3R( const uchar* cmyk, int cmyk_step,
|
||||
uchar* rgb, int rgb_step, Size size )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; )
|
||||
{
|
||||
for( i = 0; i < size.width; i++, rgb += 3, cmyk += 4 )
|
||||
{
|
||||
int c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3];
|
||||
c = k - ((255 - c)*k>>8);
|
||||
m = k - ((255 - m)*k>>8);
|
||||
y = k - ((255 - y)*k>>8);
|
||||
rgb[0] = (uchar)c; rgb[1] = (uchar)m; rgb[2] = (uchar)y;
|
||||
}
|
||||
rgb += rgb_step - size.width*3;
|
||||
cmyk += cmyk_step - size.width*4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void icvCvt_CMYK2Gray_8u_C4C1R( const uchar* cmyk, int cmyk_step,
|
||||
uchar* gray, int gray_step, Size size )
|
||||
|
@ -115,6 +115,8 @@ void icvCvt_BGR5652BGR_8u_C2C3R( const uchar* bgr565, int bgr565_step,
|
||||
uchar* bgr, int bgr_step, Size size );
|
||||
void icvCvt_CMYK2BGR_8u_C4C3R( const uchar* cmyk, int cmyk_step,
|
||||
uchar* bgr, int bgr_step, Size size );
|
||||
void icvCvt_CMYK2RGB_8u_C4C3R( const uchar* cmyk, int cmyk_step,
|
||||
uchar* rgb, int rgb_step, Size size );
|
||||
void icvCvt_CMYK2Gray_8u_C4C1R( const uchar* ycck, int ycck_step,
|
||||
uchar* gray, int gray_step, Size size );
|
||||
|
||||
|
@ -150,7 +150,7 @@ INSTANTIATE_TEST_CASE_P(
|
||||
::testing::ValuesIn({1, 3, 4}),
|
||||
::testing::ValuesIn({0, 50, 100}),
|
||||
::testing::ValuesIn({IMREAD_UNCHANGED, IMREAD_GRAYSCALE,
|
||||
IMREAD_COLOR})));
|
||||
IMREAD_COLOR, IMREAD_COLOR_RGB})));
|
||||
|
||||
class Imgcodecs_Avif_Image_EncodeDecodeSuite
|
||||
: public Imgcodecs_Avif_Image_RoundTripSuite {};
|
||||
@ -183,7 +183,7 @@ INSTANTIATE_TEST_CASE_P(
|
||||
::testing::ValuesIn({1, 3, 4}),
|
||||
::testing::ValuesIn({0, 50, 100}),
|
||||
::testing::ValuesIn({IMREAD_UNCHANGED, IMREAD_GRAYSCALE,
|
||||
IMREAD_COLOR})));
|
||||
IMREAD_COLOR, IMREAD_COLOR_RGB})));
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -311,7 +311,7 @@ INSTANTIATE_TEST_CASE_P(
|
||||
::testing::Combine(::testing::ValuesIn({8, 10, 12}),
|
||||
::testing::ValuesIn({1, 3}), ::testing::ValuesIn({50}),
|
||||
::testing::ValuesIn({IMREAD_UNCHANGED, IMREAD_GRAYSCALE,
|
||||
IMREAD_COLOR})));
|
||||
IMREAD_COLOR, IMREAD_COLOR_RGB})));
|
||||
class Imgcodecs_Avif_Animation_WriteDecodeSuite
|
||||
: public Imgcodecs_Avif_Animation_RoundTripSuite {};
|
||||
|
||||
@ -347,7 +347,7 @@ INSTANTIATE_TEST_CASE_P(
|
||||
::testing::Combine(::testing::ValuesIn({8, 10, 12}),
|
||||
::testing::ValuesIn({1, 3}), ::testing::ValuesIn({50}),
|
||||
::testing::ValuesIn({IMREAD_UNCHANGED, IMREAD_GRAYSCALE,
|
||||
IMREAD_COLOR})));
|
||||
IMREAD_COLOR, IMREAD_COLOR_RGB})));
|
||||
|
||||
} // namespace
|
||||
} // namespace opencv_test
|
||||
|
@ -192,6 +192,15 @@ TEST(Imgcodecs_EXR, read_YC_changeDepth)
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_8UC3, img.type());
|
||||
|
||||
const Mat img_rgb = cv::imread(filenameInput, IMREAD_COLOR_RGB);
|
||||
|
||||
ASSERT_FALSE(img_rgb.empty());
|
||||
ASSERT_EQ(CV_8UC3, img_rgb.type());
|
||||
|
||||
cvtColor(img_rgb, img_rgb, COLOR_RGB2BGR);
|
||||
|
||||
EXPECT_TRUE(cvtest::norm(img, img_rgb, NORM_INF) == 0);
|
||||
|
||||
// Cannot test writing, EXR encoder doesn't support 8U depth
|
||||
}
|
||||
|
||||
|
@ -108,6 +108,7 @@ const int basic_modes[] =
|
||||
IMREAD_UNCHANGED,
|
||||
IMREAD_GRAYSCALE,
|
||||
IMREAD_COLOR,
|
||||
IMREAD_COLOR_RGB,
|
||||
IMREAD_ANYDEPTH,
|
||||
IMREAD_ANYCOLOR
|
||||
};
|
||||
@ -356,6 +357,10 @@ TEST(Imgcodecs_Bmp, rgba_scale)
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_8UC3, img.type());
|
||||
|
||||
img = cv::imread(filenameInput, IMREAD_COLOR_RGB);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_8UC3, img.type());
|
||||
|
||||
data = img.ptr();
|
||||
ASSERT_EQ(data[0], 255);
|
||||
ASSERT_EQ(data[1], 255);
|
||||
|
@ -217,6 +217,7 @@ TEST_P(Imgcodecs_Jpeg_decode_cmyk, regression25274)
|
||||
INSTANTIATE_TEST_CASE_P( /* nothing */,
|
||||
Imgcodecs_Jpeg_decode_cmyk,
|
||||
testing::Values(cv::IMREAD_COLOR,
|
||||
cv::IMREAD_COLOR_RGB,
|
||||
cv::IMREAD_GRAYSCALE,
|
||||
cv::IMREAD_ANYCOLOR));
|
||||
|
||||
@ -327,6 +328,13 @@ TEST_P(Imgcodecs_Jpeg_encode_withLumaChromaQuality, basic)
|
||||
cv::Mat src = imread(fname, cv::IMREAD_COLOR);
|
||||
ASSERT_FALSE(src.empty());
|
||||
|
||||
// Add imread RGB test
|
||||
cv::Mat src_rgb = imread(fname, cv::IMREAD_COLOR_RGB);
|
||||
ASSERT_FALSE(src_rgb.empty());
|
||||
|
||||
cvtColor(src_rgb, src_rgb, COLOR_RGB2BGR);
|
||||
EXPECT_TRUE(cvtest::norm(src, src_rgb, NORM_INF) == 0);
|
||||
|
||||
std::vector<uint8_t> jpegNormal;
|
||||
ASSERT_NO_THROW(cv::imencode(".jpg", src, jpegNormal));
|
||||
|
||||
|
@ -83,6 +83,14 @@ TEST(Imgcodecs_Png, read_color_palette_with_alpha)
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(0, 0, 255));
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(0, 0, 255));
|
||||
|
||||
img = imread(root + "readwrite/color_palette_alpha.png", IMREAD_COLOR_RGB);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(img.channels() == 3);
|
||||
|
||||
// pixel is red in RGB
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(255, 0, 0));
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(255, 0, 0));
|
||||
|
||||
// Fourth Test : Read PNG without alpha, imread flag 1
|
||||
img = imread(root + "readwrite/color_palette_no_alpha.png", IMREAD_COLOR);
|
||||
ASSERT_FALSE(img.empty());
|
||||
@ -91,6 +99,14 @@ TEST(Imgcodecs_Png, read_color_palette_with_alpha)
|
||||
// pixel is red in BGR
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(0, 0, 255));
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(0, 0, 255));
|
||||
|
||||
img = imread(root + "readwrite/color_palette_no_alpha.png", IMREAD_COLOR_RGB);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(img.channels() == 3);
|
||||
|
||||
// pixel is red in RGB
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(255, 0, 0));
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(255, 0, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,6 +51,11 @@ void PrintTo(const ImreadModes& val, std::ostream* os)
|
||||
v &= ~IMREAD_IGNORE_ORIENTATION;
|
||||
*os << "IMREAD_IGNORE_ORIENTATION" << (v == 0 ? "" : " | ");
|
||||
}
|
||||
if ((v & IMREAD_COLOR_RGB) != 0)
|
||||
{
|
||||
v &= ~IMREAD_COLOR_RGB;
|
||||
*os << "IMREAD_COLOR_RGB" << (v == 0 ? "" : " | ");
|
||||
}
|
||||
switch (v)
|
||||
{
|
||||
case IMREAD_UNCHANGED: return;
|
||||
@ -66,6 +71,7 @@ void PrintTo(const ImreadModes& val, std::ostream* os)
|
||||
case IMREAD_REDUCED_GRAYSCALE_8: // fallthru
|
||||
case IMREAD_REDUCED_COLOR_8: *os << "REDUCED_8"; return;
|
||||
case IMREAD_IGNORE_ORIENTATION: return;
|
||||
case IMREAD_COLOR_RGB: return;
|
||||
} // don't use "default:" to emit compiler warnings
|
||||
*os << "IMREAD_UNKNOWN(" << (int)v << ")";
|
||||
}
|
||||
|
@ -196,9 +196,19 @@ void test_image_io(const Mat& image, const std::string& fname, const std::string
|
||||
Mat buf_loaded = imdecode(Mat(buf), imreadFlag);
|
||||
EXPECT_FALSE(buf_loaded.empty());
|
||||
|
||||
if (imreadFlag & IMREAD_COLOR_RGB && imreadFlag != -1)
|
||||
{
|
||||
cvtColor(buf_loaded, buf_loaded, COLOR_RGB2BGR);
|
||||
}
|
||||
|
||||
Mat loaded = imread(fname, imreadFlag);
|
||||
EXPECT_FALSE(loaded.empty());
|
||||
|
||||
if (imreadFlag & IMREAD_COLOR_RGB && imreadFlag != -1)
|
||||
{
|
||||
cvtColor(loaded, loaded, COLOR_RGB2BGR);
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, cv::norm(loaded, buf_loaded, NORM_INF)) << "imread() and imdecode() calls must provide the same result (bit-exact)";
|
||||
|
||||
double psnr = cvtest::PSNR(loaded, image);
|
||||
@ -238,6 +248,7 @@ TEST_P(Imgcodecs_Image, read_write_BGR)
|
||||
|
||||
Mat image = generateTestImageBGR();
|
||||
EXPECT_NO_THROW(test_image_io(image, fname, ext, IMREAD_COLOR, psnrThreshold));
|
||||
EXPECT_NO_THROW(test_image_io(image, fname, ext, IMREAD_COLOR_RGB, psnrThreshold));
|
||||
|
||||
EXPECT_EQ(0, remove(fname.c_str()));
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ enum ImreadMixModes
|
||||
{
|
||||
IMREAD_MIX_UNCHANGED = IMREAD_UNCHANGED ,
|
||||
IMREAD_MIX_GRAYSCALE = IMREAD_GRAYSCALE ,
|
||||
IMREAD_MIX_COLOR = IMREAD_COLOR ,
|
||||
IMREAD_MIX_COLOR = IMREAD_COLOR | IMREAD_COLOR_RGB ,
|
||||
IMREAD_MIX_GRAYSCALE_ANYDEPTH = IMREAD_GRAYSCALE | IMREAD_ANYDEPTH ,
|
||||
IMREAD_MIX_GRAYSCALE_ANYCOLOR = IMREAD_GRAYSCALE | IMREAD_ANYCOLOR,
|
||||
IMREAD_MIX_GRAYSCALE_ANYDEPTH_ANYCOLOR = IMREAD_GRAYSCALE | IMREAD_ANYDEPTH | IMREAD_ANYCOLOR,
|
||||
@ -125,7 +125,7 @@ TEST_P(Imgcodecs_Tiff_decode_Huge, regression)
|
||||
case IMREAD_GRAYSCALE | IMREAD_ANYCOLOR | IMREAD_ANYDEPTH:
|
||||
ncn = (ncn == 1)?1:3;
|
||||
break;
|
||||
case IMREAD_COLOR:
|
||||
case IMREAD_COLOR | IMREAD_COLOR_RGB:
|
||||
ncn = 3;
|
||||
depth = 1;
|
||||
break;
|
||||
@ -818,6 +818,24 @@ TEST(Imgcodecs_Tiff, read_palette_color_image)
|
||||
ASSERT_EQ(CV_8UC3, img.type());
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Tiff, read_palette_color_image_rgb_and_bgr)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test_palette_color_image.tif";
|
||||
|
||||
Mat img_rgb, img_bgr;
|
||||
ASSERT_NO_THROW(img_rgb = cv::imread(filenameInput, IMREAD_COLOR_RGB));
|
||||
ASSERT_NO_THROW(img_bgr = cv::imread(filenameInput, IMREAD_COLOR_BGR));
|
||||
ASSERT_FALSE(img_rgb.empty());
|
||||
ASSERT_EQ(CV_8UC3, img_rgb.type());
|
||||
|
||||
ASSERT_FALSE(img_bgr.empty());
|
||||
ASSERT_EQ(CV_8UC3, img_bgr.type());
|
||||
|
||||
EXPECT_EQ(img_rgb.at<Vec3b>(32, 24), Vec3b(255, 0, 0));
|
||||
EXPECT_EQ(img_bgr.at<Vec3b>(32, 24), Vec3b(0, 0, 255));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Tiff, read_4_bit_palette_color_image)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
@ -1066,6 +1084,7 @@ const int all_modes[] =
|
||||
IMREAD_UNCHANGED,
|
||||
IMREAD_GRAYSCALE,
|
||||
IMREAD_COLOR,
|
||||
IMREAD_COLOR_RGB,
|
||||
IMREAD_ANYDEPTH,
|
||||
IMREAD_ANYCOLOR
|
||||
};
|
||||
|
@ -51,6 +51,12 @@ TEST(Imgcodecs_WebP, encode_decode_lossless_webp)
|
||||
ASSERT_FALSE(decode.empty());
|
||||
EXPECT_TRUE(cvtest::norm(decode, img_webp, NORM_INF) == 0);
|
||||
|
||||
cv::Mat decode_rgb = cv::imdecode(buf, IMREAD_COLOR_RGB);
|
||||
ASSERT_FALSE(decode_rgb.empty());
|
||||
|
||||
cvtColor(decode_rgb, decode_rgb, COLOR_RGB2BGR);
|
||||
EXPECT_TRUE(cvtest::norm(decode_rgb, img_webp, NORM_INF) == 0);
|
||||
|
||||
ASSERT_FALSE(img_webp.empty());
|
||||
|
||||
EXPECT_TRUE(cvtest::norm(img, img_webp, NORM_INF) == 0);
|
||||
|
Loading…
Reference in New Issue
Block a user