Merge pull request #491 from Daniil-Osokin:cvtRGB2YUV420p

This commit is contained in:
Andrey Kamaev 2013-03-05 15:26:15 +04:00 committed by OpenCV Buildbot
commit bbac4bc4cf
4 changed files with 419 additions and 36 deletions

View File

@ -309,8 +309,22 @@ enum
// alpha premultiplication // alpha premultiplication
CV_RGBA2mRGBA = 125, CV_RGBA2mRGBA = 125,
CV_mRGBA2RGBA = 126, CV_mRGBA2RGBA = 126,
CV_RGB2YUV_I420 = 127,
CV_BGR2YUV_I420 = 128,
CV_RGB2YUV_IYUV = CV_RGB2YUV_I420,
CV_BGR2YUV_IYUV = CV_BGR2YUV_I420,
CV_COLORCVT_MAX = 127 CV_RGBA2YUV_I420 = 129,
CV_BGRA2YUV_I420 = 130,
CV_RGBA2YUV_IYUV = CV_RGBA2YUV_I420,
CV_BGRA2YUV_IYUV = CV_BGRA2YUV_I420,
CV_RGB2YUV_YV12 = 131,
CV_BGR2YUV_YV12 = 132,
CV_RGBA2YUV_YV12 = 133,
CV_BGRA2YUV_YV12 = 134,
CV_COLORCVT_MAX = 135
}; };

View File

@ -115,6 +115,9 @@ CV_ENUM(CvtMode2, CV_YUV2BGR_NV12, CV_YUV2BGRA_NV12, CV_YUV2RGB_NV12, CV_YUV2RGB
COLOR_YUV2GRAY_420, CV_YUV2RGB_UYVY, CV_YUV2BGR_UYVY, CV_YUV2RGBA_UYVY, CV_YUV2BGRA_UYVY, CV_YUV2RGB_YUY2, CV_YUV2BGR_YUY2, CV_YUV2RGB_YVYU, COLOR_YUV2GRAY_420, CV_YUV2RGB_UYVY, CV_YUV2BGR_UYVY, CV_YUV2RGBA_UYVY, CV_YUV2BGRA_UYVY, CV_YUV2RGB_YUY2, CV_YUV2BGR_YUY2, CV_YUV2RGB_YVYU,
CV_YUV2BGR_YVYU, CV_YUV2RGBA_YUY2, CV_YUV2BGRA_YUY2, CV_YUV2RGBA_YVYU, CV_YUV2BGRA_YVYU) CV_YUV2BGR_YVYU, CV_YUV2RGBA_YUY2, CV_YUV2BGRA_YUY2, CV_YUV2RGBA_YVYU, CV_YUV2BGRA_YVYU)
CV_ENUM(CvtMode3, CV_RGB2YUV_IYUV, CV_BGR2YUV_IYUV, CV_RGBA2YUV_IYUV, CV_BGRA2YUV_IYUV,
CV_RGB2YUV_YV12, CV_BGR2YUV_YV12, CV_RGBA2YUV_YV12, CV_BGRA2YUV_YV12)
struct ChPair struct ChPair
{ {
ChPair(int _scn, int _dcn): scn(_scn), dcn(_dcn) {} ChPair(int _scn, int _dcn): scn(_scn), dcn(_dcn) {}
@ -162,6 +165,8 @@ ChPair getConversionInfo(int cvtMode)
case CV_BGR5652BGRA: case CV_BGR5652RGBA: case CV_BGR5652BGRA: case CV_BGR5652RGBA:
return ChPair(2,4); return ChPair(2,4);
case CV_BGR2GRAY: case CV_RGB2GRAY: case CV_BGR2GRAY: case CV_RGB2GRAY:
case CV_RGB2YUV_IYUV: case CV_RGB2YUV_YV12:
case CV_BGR2YUV_IYUV: case CV_BGR2YUV_YV12:
return ChPair(3,1); return ChPair(3,1);
case CV_BGR2BGR555: case CV_BGR2BGR565: case CV_BGR2BGR555: case CV_BGR2BGR565:
case CV_RGB2BGR555: case CV_RGB2BGR565: case CV_RGB2BGR555: case CV_RGB2BGR565:
@ -204,6 +209,8 @@ ChPair getConversionInfo(int cvtMode)
case CX_YUV2BGRA: case CX_YUV2RGBA: case CX_YUV2BGRA: case CX_YUV2RGBA:
return ChPair(3,4); return ChPair(3,4);
case CV_BGRA2GRAY: case CV_RGBA2GRAY: case CV_BGRA2GRAY: case CV_RGBA2GRAY:
case CV_RGBA2YUV_IYUV: case CV_RGBA2YUV_YV12:
case CV_BGRA2YUV_IYUV: case CV_BGRA2YUV_YV12:
return ChPair(4,1); return ChPair(4,1);
case CV_BGRA2BGR555: case CV_BGRA2BGR565: case CV_BGRA2BGR555: case CV_BGRA2BGR565:
case CV_RGBA2BGR555: case CV_RGBA2BGR565: case CV_RGBA2BGR555: case CV_RGBA2BGR565:
@ -306,3 +313,28 @@ PERF_TEST_P(Size_CvtMode2, cvtColorYUV420,
SANITY_CHECK(dst, 1); SANITY_CHECK(dst, 1);
} }
typedef std::tr1::tuple<Size, CvtMode3> Size_CvtMode3_t;
typedef perf::TestBaseWithParam<Size_CvtMode3_t> Size_CvtMode3;
PERF_TEST_P(Size_CvtMode3, cvtColorRGB2YUV420p,
testing::Combine(
testing::Values(szVGA, sz720p, sz1080p, Size(130, 60)),
testing::ValuesIn(CvtMode3::all())
)
)
{
Size sz = get<0>(GetParam());
int mode = get<1>(GetParam());
ChPair ch = getConversionInfo(mode);
Mat src(sz, CV_8UC(ch.scn));
Mat dst(sz.height + sz.height / 2, sz.width, CV_8UC(ch.dcn));
declare.time(100);
declare.in(src, WARMUP_RNG).out(dst);
TEST_CYCLE() cvtColor(src, dst, mode, ch.dcn);
SANITY_CHECK(dst, 1);
}

View File

@ -2744,6 +2744,16 @@ const int ITUR_BT_601_CVG = -852492;
const int ITUR_BT_601_CVR = 1673527; const int ITUR_BT_601_CVR = 1673527;
const int ITUR_BT_601_SHIFT = 20; const int ITUR_BT_601_SHIFT = 20;
// Coefficients for RGB to YUV420p conversion
const int ITUR_BT_601_CRY = 269484;
const int ITUR_BT_601_CGY = 528482;
const int ITUR_BT_601_CBY = 102760;
const int ITUR_BT_601_CRU = -155188;
const int ITUR_BT_601_CGU = -305135;
const int ITUR_BT_601_CBU = 460324;
const int ITUR_BT_601_CGV = -385875;
const int ITUR_BT_601_CBV = -74448;
template<int bIdx, int uIdx> template<int bIdx, int uIdx>
struct YUV420sp2RGB888Invoker struct YUV420sp2RGB888Invoker
{ {
@ -3076,6 +3086,84 @@ inline void cvtYUV420p2RGBA(Mat& _dst, int _stride, const uchar* _y1, const ucha
converter(BlockedRange(0, _dst.rows/2)); converter(BlockedRange(0, _dst.rows/2));
} }
///////////////////////////////////// RGB -> YUV420p /////////////////////////////////////
template<int bIdx>
struct RGB888toYUV420pInvoker: public ParallelLoopBody
{
RGB888toYUV420pInvoker( const Mat& src, Mat* dst, const int uIdx )
: src_(src),
dst_(dst),
uIdx_(uIdx) { }
void operator()(const Range& rowRange) const
{
const int w = src_.cols;
const int h = src_.rows;
const int cn = src_.channels();
for( int i = rowRange.start; i < rowRange.end; i++ )
{
const uchar* row0 = src_.ptr<uchar>(2 * i);
const uchar* row1 = src_.ptr<uchar>(2 * i + 1);
uchar* y = dst_->ptr<uchar>(2*i);
uchar* u = dst_->ptr<uchar>(h + i/2) + (i % 2) * (w/2);
uchar* v = dst_->ptr<uchar>(h + (i + h/2)/2) + ((i + h/2) % 2) * (w/2);
if( uIdx_ == 2 ) std::swap(u, v);
for( int j = 0, k = 0; j < w * cn; j += 2 * cn, k++ )
{
int r00 = row0[2-bIdx + j]; int g00 = row0[1 + j]; int b00 = row0[bIdx + j];
int r01 = row0[2-bIdx + cn + j]; int g01 = row0[1 + cn + j]; int b01 = row0[bIdx + cn + j];
int r10 = row1[2-bIdx + j]; int g10 = row1[1 + j]; int b10 = row1[bIdx + j];
int r11 = row1[2-bIdx + cn + j]; int g11 = row1[1 + cn + j]; int b11 = row1[bIdx + cn + j];
const int shifted16 = (16 << ITUR_BT_601_SHIFT);
const int halfShift = (1 << (ITUR_BT_601_SHIFT - 1));
int y00 = ITUR_BT_601_CRY * r00 + ITUR_BT_601_CGY * g00 + ITUR_BT_601_CBY * b00 + halfShift + shifted16;
int y01 = ITUR_BT_601_CRY * r01 + ITUR_BT_601_CGY * g01 + ITUR_BT_601_CBY * b01 + halfShift + shifted16;
int y10 = ITUR_BT_601_CRY * r10 + ITUR_BT_601_CGY * g10 + ITUR_BT_601_CBY * b10 + halfShift + shifted16;
int y11 = ITUR_BT_601_CRY * r11 + ITUR_BT_601_CGY * g11 + ITUR_BT_601_CBY * b11 + halfShift + shifted16;
y[2*k + 0] = saturate_cast<uchar>(y00 >> ITUR_BT_601_SHIFT);
y[2*k + 1] = saturate_cast<uchar>(y01 >> ITUR_BT_601_SHIFT);
y[2*k + dst_->step + 0] = saturate_cast<uchar>(y10 >> ITUR_BT_601_SHIFT);
y[2*k + dst_->step + 1] = saturate_cast<uchar>(y11 >> ITUR_BT_601_SHIFT);
const int shifted128 = (128 << ITUR_BT_601_SHIFT);
int u00 = ITUR_BT_601_CRU * r00 + ITUR_BT_601_CGU * g00 + ITUR_BT_601_CBU * b00 + halfShift + shifted128;
int v00 = ITUR_BT_601_CBU * r00 + ITUR_BT_601_CGV * g00 + ITUR_BT_601_CBV * b00 + halfShift + shifted128;
u[k] = saturate_cast<uchar>(u00 >> ITUR_BT_601_SHIFT);
v[k] = saturate_cast<uchar>(v00 >> ITUR_BT_601_SHIFT);
}
}
}
static bool isFit( const Mat& src )
{
return (src.total() >= 320*240);
}
private:
RGB888toYUV420pInvoker& operator=(const RGB888toYUV420pInvoker&);
const Mat& src_;
Mat* const dst_;
const int uIdx_;
};
template<int bIdx, int uIdx>
static void cvtRGBtoYUV420p(const Mat& src, Mat& dst)
{
RGB888toYUV420pInvoker<bIdx> colorConverter(src, &dst, uIdx);
if( RGB888toYUV420pInvoker<bIdx>::isFit(src) )
parallel_for_(Range(0, src.rows/2), colorConverter);
else
colorConverter(Range(0, src.rows/2));
}
///////////////////////////////////// YUV422 -> RGB ///////////////////////////////////// ///////////////////////////////////// YUV422 -> RGB /////////////////////////////////////
template<int bIdx, int uIdx, int yIdx> template<int bIdx, int uIdx, int yIdx>
@ -3713,6 +3801,31 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
src(Range(0, dstSz.height), Range::all()).copyTo(dst); src(Range(0, dstSz.height), Range::all()).copyTo(dst);
} }
break; break;
case CV_RGB2YUV_YV12: case CV_BGR2YUV_YV12: case CV_RGBA2YUV_YV12: case CV_BGRA2YUV_YV12:
case CV_RGB2YUV_IYUV: case CV_BGR2YUV_IYUV: case CV_RGBA2YUV_IYUV: case CV_BGRA2YUV_IYUV:
{
if (dcn <= 0) dcn = 1;
const int bIdx = (code == CV_BGR2YUV_IYUV || code == CV_BGRA2YUV_IYUV || code == CV_BGR2YUV_YV12 || code == CV_BGRA2YUV_YV12) ? 0 : 2;
const int uIdx = (code == CV_BGR2YUV_IYUV || code == CV_BGRA2YUV_IYUV || code == CV_RGB2YUV_IYUV || code == CV_RGBA2YUV_IYUV) ? 1 : 2;
CV_Assert( (scn == 3 || scn == 4) && depth == CV_8U );
CV_Assert( dcn == 1 );
CV_Assert( sz.width % 2 == 0 && sz.height % 2 == 0 );
Size dstSz(sz.width, sz.height / 2 * 3);
_dst.create(dstSz, CV_MAKETYPE(depth, dcn));
dst = _dst.getMat();
switch(bIdx + uIdx*10)
{
case 10: cvtRGBtoYUV420p<0, 1>(src, dst); break;
case 12: cvtRGBtoYUV420p<2, 1>(src, dst); break;
case 20: cvtRGBtoYUV420p<0, 2>(src, dst); break;
case 22: cvtRGBtoYUV420p<2, 2>(src, dst); break;
default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break;
};
}
break;
case CV_YUV2RGB_UYVY: case CV_YUV2BGR_UYVY: case CV_YUV2RGBA_UYVY: case CV_YUV2BGRA_UYVY: case CV_YUV2RGB_UYVY: case CV_YUV2BGR_UYVY: case CV_YUV2RGBA_UYVY: case CV_YUV2BGRA_UYVY:
case CV_YUV2RGB_YUY2: case CV_YUV2BGR_YUY2: case CV_YUV2RGB_YVYU: case CV_YUV2BGR_YVYU: case CV_YUV2RGB_YUY2: case CV_YUV2BGR_YUY2: case CV_YUV2RGB_YVYU: case CV_YUV2BGR_YVYU:
case CV_YUV2RGBA_YUY2: case CV_YUV2BGRA_YUY2: case CV_YUV2RGBA_YVYU: case CV_YUV2BGRA_YVYU: case CV_YUV2RGBA_YUY2: case CV_YUV2BGRA_YUY2: case CV_YUV2RGBA_YVYU: case CV_YUV2BGRA_YVYU:
@ -3795,7 +3908,7 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
CV_Error( CV_StsBadArg, "Unsupported image depth" ); CV_Error( CV_StsBadArg, "Unsupported image depth" );
} }
} }
break; break;
default: default:
CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" );
} }

View File

@ -30,6 +30,16 @@ public:
static YUVreader* getReader(int code); static YUVreader* getReader(int code);
}; };
class RGBreader
{
public:
virtual ~RGBreader() {}
virtual RGB read(const Mat& rgb, int row, int col) = 0;
virtual int channels() = 0;
static RGBreader* getReader(int code);
};
class RGBwriter class RGBwriter
{ {
public: public:
@ -56,6 +66,21 @@ public:
static GRAYwriter* getWriter(int code); static GRAYwriter* getWriter(int code);
}; };
class YUVwriter
{
public:
virtual ~YUVwriter() {}
virtual void write(Mat& yuv, int row, int col, const YUV& val) = 0;
virtual int channels() = 0;
virtual Size size(Size imgSize) = 0;
virtual bool requiresEvenHeight() { return true; }
virtual bool requiresEvenWidth() { return true; }
static YUVwriter* getWriter(int code);
};
class RGB888Writer : public RGBwriter class RGB888Writer : public RGBwriter
{ {
void write(Mat& rgb, int row, int col, const RGB& val) void write(Mat& rgb, int row, int col, const RGB& val)
@ -99,6 +124,42 @@ class BGRA8888Writer : public RGBwriter
int channels() { return 4; } int channels() { return 4; }
}; };
class YUV420pWriter: public YUVwriter
{
int channels() { return 1; }
Size size(Size imgSize) { return Size(imgSize.width, imgSize.height + imgSize.height/2); }
};
class YV12Writer: public YUV420pWriter
{
void write(Mat& yuv, int row, int col, const YUV& val)
{
int h = yuv.rows * 2 / 3;
yuv.ptr<uchar>(row)[col] = val[0];
if( row % 2 == 0 && col % 2 == 0 )
{
yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)] = val[2];
yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)] = val[1];
}
}
};
class I420Writer: public YUV420pWriter
{
void write(Mat& yuv, int row, int col, const YUV& val)
{
int h = yuv.rows * 2 / 3;
yuv.ptr<uchar>(row)[col] = val[0];
if( row % 2 == 0 && col % 2 == 0 )
{
yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)] = val[1];
yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)] = val[2];
}
}
};
class YUV420Reader: public YUVreader class YUV420Reader: public YUVreader
{ {
int channels() { return 1; } int channels() { return 1; }
@ -212,6 +273,49 @@ class YUV888Reader : public YUVreader
bool requiresEvenWidth() { return false; } bool requiresEvenWidth() { return false; }
}; };
class RGB888Reader : public RGBreader
{
RGB read(const Mat& rgb, int row, int col)
{
return rgb.at<RGB>(row, col);
}
int channels() { return 3; }
};
class BGR888Reader : public RGBreader
{
RGB read(const Mat& rgb, int row, int col)
{
RGB tmp = rgb.at<RGB>(row, col);
return RGB(tmp[2], tmp[1], tmp[0]);
}
int channels() { return 3; }
};
class RGBA8888Reader : public RGBreader
{
RGB read(const Mat& rgb, int row, int col)
{
Vec4b rgba = rgb.at<Vec4b>(row, col);
return RGB(rgba[0], rgba[1], rgba[2]);
}
int channels() { return 4; }
};
class BGRA8888Reader : public RGBreader
{
RGB read(const Mat& rgb, int row, int col)
{
Vec4b rgba = rgb.at<Vec4b>(row, col);
return RGB(rgba[2], rgba[1], rgba[0]);
}
int channels() { return 4; }
};
class YUV2RGB_Converter class YUV2RGB_Converter
{ {
public: public:
@ -237,6 +341,23 @@ public:
} }
}; };
class RGB2YUV_Converter
{
public:
YUV convert(RGB rgb)
{
int r = rgb[0];
int g = rgb[1];
int b = rgb[2];
uchar y = saturate_cast<uchar>((int)( 0.257f*r + 0.504f*g + 0.098f*b + 0.5f) + 16);
uchar u = saturate_cast<uchar>((int)(-0.148f*r - 0.291f*g + 0.439f*b + 0.5f) + 128);
uchar v = saturate_cast<uchar>((int)( 0.439f*r - 0.368f*g - 0.071f*b + 0.5f) + 128);
return YUV(y, u, v);
}
};
YUVreader* YUVreader::getReader(int code) YUVreader* YUVreader::getReader(int code)
{ {
switch(code) switch(code)
@ -295,6 +416,27 @@ YUVreader* YUVreader::getReader(int code)
} }
} }
RGBreader* RGBreader::getReader(int code)
{
switch(code)
{
case CV_RGB2YUV_YV12:
case CV_RGB2YUV_I420:
return new RGB888Reader();
case CV_BGR2YUV_YV12:
case CV_BGR2YUV_I420:
return new BGR888Reader();
case CV_RGBA2YUV_I420:
case CV_RGBA2YUV_YV12:
return new RGBA8888Reader();
case CV_BGRA2YUV_YV12:
case CV_BGRA2YUV_I420:
return new BGRA8888Reader();
default:
return 0;
};
}
RGBwriter* RGBwriter::getWriter(int code) RGBwriter* RGBwriter::getWriter(int code)
{ {
switch(code) switch(code)
@ -355,6 +497,25 @@ GRAYwriter* GRAYwriter::getWriter(int code)
} }
} }
YUVwriter* YUVwriter::getWriter(int code)
{
switch(code)
{
case CV_RGB2YUV_YV12:
case CV_BGR2YUV_YV12:
case CV_RGBA2YUV_YV12:
case CV_BGRA2YUV_YV12:
return new YV12Writer();
case CV_RGB2YUV_I420:
case CV_BGR2YUV_I420:
case CV_RGBA2YUV_I420:
case CV_BGRA2YUV_I420:
return new I420Writer();
default:
return 0;
};
}
template<class convertor> template<class convertor>
void referenceYUV2RGB(const Mat& yuv, Mat& rgb, YUVreader* yuvReader, RGBwriter* rgbWriter) void referenceYUV2RGB(const Mat& yuv, Mat& rgb, YUVreader* yuvReader, RGBwriter* rgbWriter)
{ {
@ -375,6 +536,64 @@ void referenceYUV2GRAY(const Mat& yuv, Mat& rgb, YUVreader* yuvReader, GRAYwrite
grayWriter->write(rgb, row, col, cvt.convert(yuvReader->read(yuv, row, col))); grayWriter->write(rgb, row, col, cvt.convert(yuvReader->read(yuv, row, col)));
} }
template<class convertor>
void referenceRGB2YUV(const Mat& rgb, Mat& yuv, RGBreader* rgbReader, YUVwriter* yuvWriter)
{
convertor cvt;
for(int row = 0; row < rgb.rows; ++row)
for(int col = 0; col < rgb.cols; ++col)
yuvWriter->write(yuv, row, col, cvt.convert(rgbReader->read(rgb, row, col)));
}
struct ConversionYUV
{
ConversionYUV( const int code )
{
yuvReader_ = YUVreader :: getReader(code);
yuvWriter_ = YUVwriter :: getWriter(code);
rgbReader_ = RGBreader :: getReader(code);
rgbWriter_ = RGBwriter :: getWriter(code);
grayWriter_ = GRAYwriter:: getWriter(code);
}
int getDcn()
{
return (rgbWriter_ != 0) ? rgbWriter_->channels() : ((grayWriter_ != 0) ? grayWriter_->channels() : yuvWriter_->channels());
}
int getScn()
{
return (yuvReader_ != 0) ? yuvReader_->channels() : rgbReader_->channels();
}
Size getSrcSize( const Size& imgSize )
{
return (yuvReader_ != 0) ? yuvReader_->size(imgSize) : imgSize;
}
Size getDstSize( const Size& imgSize )
{
return (yuvWriter_ != 0) ? yuvWriter_->size(imgSize) : imgSize;
}
bool requiresEvenHeight()
{
return (yuvReader_ != 0) ? yuvReader_->requiresEvenHeight() : ((yuvWriter_ != 0) ? yuvWriter_->requiresEvenHeight() : false);
}
bool requiresEvenWidth()
{
return (yuvReader_ != 0) ? yuvReader_->requiresEvenWidth() : ((yuvWriter_ != 0) ? yuvWriter_->requiresEvenWidth() : false);
}
YUVreader* yuvReader_;
YUVwriter* yuvWriter_;
RGBreader* rgbReader_;
RGBwriter* rgbWriter_;
GRAYwriter* grayWriter_;
};
CV_ENUM(YUVCVTS, CV_YUV2RGB_NV12, CV_YUV2BGR_NV12, CV_YUV2RGB_NV21, CV_YUV2BGR_NV21, CV_ENUM(YUVCVTS, CV_YUV2RGB_NV12, CV_YUV2BGR_NV12, CV_YUV2RGB_NV21, CV_YUV2BGR_NV21,
CV_YUV2RGBA_NV12, CV_YUV2BGRA_NV12, CV_YUV2RGBA_NV21, CV_YUV2BGRA_NV21, CV_YUV2RGBA_NV12, CV_YUV2BGRA_NV12, CV_YUV2RGBA_NV21, CV_YUV2BGRA_NV21,
CV_YUV2RGB_YV12, CV_YUV2BGR_YV12, CV_YUV2RGB_IYUV, CV_YUV2BGR_IYUV, CV_YUV2RGB_YV12, CV_YUV2BGR_YV12, CV_YUV2RGB_IYUV, CV_YUV2BGR_IYUV,
@ -383,7 +602,8 @@ CV_ENUM(YUVCVTS, CV_YUV2RGB_NV12, CV_YUV2BGR_NV12, CV_YUV2RGB_NV21, CV_YUV2BGR_N
CV_YUV2RGB_YUY2, CV_YUV2BGR_YUY2, CV_YUV2RGB_YVYU, CV_YUV2BGR_YVYU, CV_YUV2RGB_YUY2, CV_YUV2BGR_YUY2, CV_YUV2RGB_YVYU, CV_YUV2BGR_YVYU,
CV_YUV2RGBA_YUY2, CV_YUV2BGRA_YUY2, CV_YUV2RGBA_YVYU, CV_YUV2BGRA_YVYU, CV_YUV2RGBA_YUY2, CV_YUV2BGRA_YUY2, CV_YUV2RGBA_YVYU, CV_YUV2BGRA_YVYU,
CV_YUV2GRAY_420, CV_YUV2GRAY_UYVY, CV_YUV2GRAY_YUY2, CV_YUV2GRAY_420, CV_YUV2GRAY_UYVY, CV_YUV2GRAY_YUY2,
CV_YUV2BGR, CV_YUV2RGB); CV_YUV2BGR, CV_YUV2RGB, CV_RGB2YUV_YV12, CV_BGR2YUV_YV12, CV_RGBA2YUV_YV12,
CV_BGRA2YUV_YV12, CV_RGB2YUV_I420, CV_BGR2YUV_I420, CV_RGBA2YUV_I420, CV_BGRA2YUV_I420);
typedef ::testing::TestWithParam<YUVCVTS> Imgproc_ColorYUV; typedef ::testing::TestWithParam<YUVCVTS> Imgproc_ColorYUV;
@ -392,31 +612,32 @@ TEST_P(Imgproc_ColorYUV, accuracy)
int code = GetParam(); int code = GetParam();
RNG& random = theRNG(); RNG& random = theRNG();
YUVreader* yuvReader = YUVreader::getReader(code); ConversionYUV cvt(code);
RGBwriter* rgbWriter = RGBwriter::getWriter(code);
GRAYwriter* grayWriter = GRAYwriter::getWriter(code);
int dcn = (rgbWriter == 0) ? grayWriter->channels() : rgbWriter->channels();
const int scn = cvt.getScn();
const int dcn = cvt.getDcn();
for(int iter = 0; iter < 30; ++iter) for(int iter = 0; iter < 30; ++iter)
{ {
Size sz(random.uniform(1, 641), random.uniform(1, 481)); Size sz(random.uniform(1, 641), random.uniform(1, 481));
if(yuvReader->requiresEvenWidth()) sz.width += sz.width % 2; if(cvt.requiresEvenWidth()) sz.width += sz.width % 2;
if(yuvReader->requiresEvenHeight()) sz.height += sz.height % 2; if(cvt.requiresEvenHeight()) sz.height += sz.height % 2;
Size ysz = yuvReader->size(sz); Size srcSize = cvt.getSrcSize(sz);
Mat src = Mat(ysz.height, ysz.width * yuvReader->channels(), CV_8UC1).reshape(yuvReader->channels()); Mat src = Mat(srcSize.height, srcSize.width * scn, CV_8UC1).reshape(scn);
Mat dst = Mat(sz.height, sz.width * dcn, CV_8UC1).reshape(dcn); Size dstSize = cvt.getDstSize(sz);
Mat gold(sz, CV_8UC(dcn)); Mat dst = Mat(dstSize.height, dstSize.width * dcn, CV_8UC1).reshape(dcn);
Mat gold(dstSize, CV_8UC(dcn));
random.fill(src, RNG::UNIFORM, 0, 256); random.fill(src, RNG::UNIFORM, 0, 256);
if(rgbWriter) if(cvt.rgbWriter_)
referenceYUV2RGB<YUV2RGB_Converter>(src, gold, yuvReader, rgbWriter); referenceYUV2RGB<YUV2RGB_Converter> (src, gold, cvt.yuvReader_, cvt.rgbWriter_);
else else if(cvt.grayWriter_)
referenceYUV2GRAY<YUV2GRAY_Converter>(src, gold, yuvReader, grayWriter); referenceYUV2GRAY<YUV2GRAY_Converter>(src, gold, cvt.yuvReader_, cvt.grayWriter_);
else if(cvt.yuvWriter_)
referenceRGB2YUV<RGB2YUV_Converter> (src, gold, cvt.rgbReader_, cvt.yuvWriter_);
cv::cvtColor(src, dst, code, -1); cv::cvtColor(src, dst, code, -1);
@ -429,40 +650,41 @@ TEST_P(Imgproc_ColorYUV, roi_accuracy)
int code = GetParam(); int code = GetParam();
RNG& random = theRNG(); RNG& random = theRNG();
YUVreader* yuvReader = YUVreader::getReader(code); ConversionYUV cvt(code);
RGBwriter* rgbWriter = RGBwriter::getWriter(code);
GRAYwriter* grayWriter = GRAYwriter::getWriter(code);
int dcn = (rgbWriter == 0) ? grayWriter->channels() : rgbWriter->channels();
const int scn = cvt.getScn();
const int dcn = cvt.getDcn();
for(int iter = 0; iter < 30; ++iter) for(int iter = 0; iter < 30; ++iter)
{ {
Size sz(random.uniform(1, 641), random.uniform(1, 481)); Size sz(random.uniform(1, 641), random.uniform(1, 481));
if(yuvReader->requiresEvenWidth()) sz.width += sz.width % 2; if(cvt.requiresEvenWidth()) sz.width += sz.width % 2;
if(yuvReader->requiresEvenHeight()) sz.height += sz.height % 2; if(cvt.requiresEvenHeight()) sz.height += sz.height % 2;
int roi_offset_top = random.uniform(0, 6); int roi_offset_top = random.uniform(0, 6);
int roi_offset_bottom = random.uniform(0, 6); int roi_offset_bottom = random.uniform(0, 6);
int roi_offset_left = random.uniform(0, 6); int roi_offset_left = random.uniform(0, 6);
int roi_offset_right = random.uniform(0, 6); int roi_offset_right = random.uniform(0, 6);
Size ysz = yuvReader->size(sz); Size srcSize = cvt.getSrcSize(sz);
Mat src_full(srcSize.height + roi_offset_top + roi_offset_bottom, srcSize.width + roi_offset_left + roi_offset_right, CV_8UC(scn));
Mat src_full(ysz.height + roi_offset_top + roi_offset_bottom, ysz.width + roi_offset_left + roi_offset_right, CV_8UC(yuvReader->channels())); Size dstSize = cvt.getDstSize(sz);
Mat dst_full(sz.height + roi_offset_left + roi_offset_right, sz.width + roi_offset_top + roi_offset_bottom, CV_8UC(dcn), Scalar::all(0)); Mat dst_full(dstSize.height + roi_offset_left + roi_offset_right, dstSize.width + roi_offset_top + roi_offset_bottom, CV_8UC(dcn), Scalar::all(0));
Mat gold_full(dst_full.size(), CV_8UC(dcn), Scalar::all(0)); Mat gold_full(dst_full.size(), CV_8UC(dcn), Scalar::all(0));
random.fill(src_full, RNG::UNIFORM, 0, 256); random.fill(src_full, RNG::UNIFORM, 0, 256);
Mat src = src_full(Range(roi_offset_top, roi_offset_top + ysz.height), Range(roi_offset_left, roi_offset_left + ysz.width)); Mat src = src_full(Range(roi_offset_top, roi_offset_top + srcSize.height), Range(roi_offset_left, roi_offset_left + srcSize.width));
Mat dst = dst_full(Range(roi_offset_left, roi_offset_left + sz.height), Range(roi_offset_top, roi_offset_top + sz.width)); Mat dst = dst_full(Range(roi_offset_left, roi_offset_left + dstSize.height), Range(roi_offset_top, roi_offset_top + dstSize.width));
Mat gold = gold_full(Range(roi_offset_left, roi_offset_left + sz.height), Range(roi_offset_top, roi_offset_top + sz.width)); Mat gold = gold_full(Range(roi_offset_left, roi_offset_left + dstSize.height), Range(roi_offset_top, roi_offset_top + dstSize.width));
if(rgbWriter) if(cvt.rgbWriter_)
referenceYUV2RGB<YUV2RGB_Converter>(src, gold, yuvReader, rgbWriter); referenceYUV2RGB<YUV2RGB_Converter> (src, gold, cvt.yuvReader_, cvt.rgbWriter_);
else else if(cvt.grayWriter_)
referenceYUV2GRAY<YUV2GRAY_Converter>(src, gold, yuvReader, grayWriter); referenceYUV2GRAY<YUV2GRAY_Converter>(src, gold, cvt.yuvReader_, cvt.grayWriter_);
else if(cvt.yuvWriter_)
referenceRGB2YUV<RGB2YUV_Converter> (src, gold, cvt.rgbReader_, cvt.yuvWriter_);
cv::cvtColor(src, dst, code, -1); cv::cvtColor(src, dst, code, -1);
@ -475,7 +697,9 @@ INSTANTIATE_TEST_CASE_P(cvt420, Imgproc_ColorYUV,
(int)CV_YUV2RGBA_NV12, (int)CV_YUV2BGRA_NV12, (int)CV_YUV2RGBA_NV21, (int)CV_YUV2BGRA_NV21, (int)CV_YUV2RGBA_NV12, (int)CV_YUV2BGRA_NV12, (int)CV_YUV2RGBA_NV21, (int)CV_YUV2BGRA_NV21,
(int)CV_YUV2RGB_YV12, (int)CV_YUV2BGR_YV12, (int)CV_YUV2RGB_IYUV, (int)CV_YUV2BGR_IYUV, (int)CV_YUV2RGB_YV12, (int)CV_YUV2BGR_YV12, (int)CV_YUV2RGB_IYUV, (int)CV_YUV2BGR_IYUV,
(int)CV_YUV2RGBA_YV12, (int)CV_YUV2BGRA_YV12, (int)CV_YUV2RGBA_IYUV, (int)CV_YUV2BGRA_IYUV, (int)CV_YUV2RGBA_YV12, (int)CV_YUV2BGRA_YV12, (int)CV_YUV2RGBA_IYUV, (int)CV_YUV2BGRA_IYUV,
(int)CV_YUV2GRAY_420)); (int)CV_YUV2GRAY_420, (int)CV_RGB2YUV_YV12, (int)CV_BGR2YUV_YV12, (int)CV_RGBA2YUV_YV12,
(int)CV_BGRA2YUV_YV12, (int)CV_RGB2YUV_I420, (int)CV_BGR2YUV_I420, (int)CV_RGBA2YUV_I420,
(int)CV_BGRA2YUV_I420));
INSTANTIATE_TEST_CASE_P(cvt422, Imgproc_ColorYUV, INSTANTIATE_TEST_CASE_P(cvt422, Imgproc_ColorYUV,
::testing::Values((int)CV_YUV2RGB_UYVY, (int)CV_YUV2BGR_UYVY, (int)CV_YUV2RGBA_UYVY, (int)CV_YUV2BGRA_UYVY, ::testing::Values((int)CV_YUV2RGB_UYVY, (int)CV_YUV2BGR_UYVY, (int)CV_YUV2RGBA_UYVY, (int)CV_YUV2BGRA_UYVY,