mirror of
https://github.com/opencv/opencv.git
synced 2026-07-30 07:43:03 +04: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:
@@ -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 );
|
||||
|
||||
|
||||
Reference in New Issue
Block a user