Commit 470f6faf authored by Andrey Kamaev's avatar Andrey Kamaev

Fixed conversions from YV12 and IYUV on non-continuous input. Added accuracy and performance tests.

parent a22641aa
...@@ -106,7 +106,9 @@ CV_ENUM(CvtMode, ...@@ -106,7 +106,9 @@ CV_ENUM(CvtMode,
CV_YUV2BGR, CV_YUV2RGB, CX_YUV2BGRA, CX_YUV2RGBA CV_YUV2BGR, CV_YUV2RGB, CX_YUV2BGRA, CX_YUV2RGBA
) )
CV_ENUM(CvtMode2, CV_YUV2BGR_NV12, CV_YUV2BGRA_NV12, CV_YUV2RGB_NV12, CV_YUV2RGBA_NV12, CV_YUV420sp2BGR, CV_YUV420sp2BGRA, CV_YUV420sp2RGB, CV_YUV420sp2RGBA) CV_ENUM(CvtMode2, CV_YUV2BGR_NV12, CV_YUV2BGRA_NV12, CV_YUV2RGB_NV12, CV_YUV2RGBA_NV12, CV_YUV2BGR_NV21, CV_YUV2BGRA_NV21, CV_YUV2RGB_NV21, CV_YUV2RGBA_NV21,
CV_YUV2BGR_YV12, CV_YUV2BGRA_YV12, CV_YUV2RGB_YV12, CV_YUV2RGBA_YV12, CV_YUV2BGR_IYUV, CV_YUV2BGRA_IYUV, CV_YUV2RGB_IYUV, CV_YUV2RGBA_IYUV,
COLOR_YUV2GRAY_420)
struct ChPair struct ChPair
{ {
...@@ -120,6 +122,7 @@ ChPair getConversionInfo(int cvtMode) ...@@ -120,6 +122,7 @@ ChPair getConversionInfo(int cvtMode)
{ {
case CV_BayerBG2GRAY: case CV_BayerGB2GRAY: case CV_BayerBG2GRAY: case CV_BayerGB2GRAY:
case CV_BayerGR2GRAY: case CV_BayerRG2GRAY: case CV_BayerGR2GRAY: case CV_BayerRG2GRAY:
case CV_YUV2GRAY_420:
return ChPair(1,1); return ChPair(1,1);
case CV_GRAY2BGR555: case CV_GRAY2BGR565: case CV_GRAY2BGR555: case CV_GRAY2BGR565:
return ChPair(1,2); return ChPair(1,2);
...@@ -127,13 +130,17 @@ ChPair getConversionInfo(int cvtMode) ...@@ -127,13 +130,17 @@ ChPair getConversionInfo(int cvtMode)
case CV_BayerGB2BGR: case CV_BayerGB2BGR_VNG: case CV_BayerGB2BGR: case CV_BayerGB2BGR_VNG:
case CV_BayerGR2BGR: case CV_BayerGR2BGR_VNG: case CV_BayerGR2BGR: case CV_BayerGR2BGR_VNG:
case CV_BayerRG2BGR: case CV_BayerRG2BGR_VNG: case CV_BayerRG2BGR: case CV_BayerRG2BGR_VNG:
case CV_GRAY2BGR: case CV_YUV2BGR_NV12: case CV_GRAY2BGR:
case CV_YUV2RGB_NV12: case CV_YUV420sp2BGR: case CV_YUV2BGR_NV12: case CV_YUV2RGB_NV12:
case CV_YUV420sp2RGB: case CV_YUV2BGR_NV21: case CV_YUV2RGB_NV21:
case CV_YUV2BGR_YV12: case CV_YUV2RGB_YV12:
case CV_YUV2BGR_IYUV: case CV_YUV2RGB_IYUV:
return ChPair(1,3); return ChPair(1,3);
case CV_GRAY2BGRA: case CV_YUV2BGRA_NV12: case CV_GRAY2BGRA:
case CV_YUV2RGBA_NV12: case CV_YUV420sp2BGRA: case CV_YUV2BGRA_NV12: case CV_YUV2RGBA_NV12:
case CV_YUV420sp2RGBA: case CV_YUV2BGRA_NV21: case CV_YUV2RGBA_NV21:
case CV_YUV2BGRA_YV12: case CV_YUV2RGBA_YV12:
case CV_YUV2BGRA_IYUV: case CV_YUV2RGBA_IYUV:
return ChPair(1,4); return ChPair(1,4);
case CV_BGR5552GRAY: case CV_BGR5652GRAY: case CV_BGR5552GRAY: case CV_BGR5652GRAY:
return ChPair(2,1); return ChPair(2,1);
......
...@@ -2829,22 +2829,18 @@ struct YUV420p2RGB888Invoker ...@@ -2829,22 +2829,18 @@ struct YUV420p2RGB888Invoker
Mat* dst; Mat* dst;
const uchar* my1, *mu, *mv; const uchar* my1, *mu, *mv;
int width, stride; int width, stride;
int ustepIdx, vstepIdx;
YUV420p2RGB888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v) YUV420p2RGB888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int _ustepIdx, int _vstepIdx)
: dst(_dst), my1(_y1), mu(_u), mv(_v), width(_dst->cols), stride(_stride) {} : dst(_dst), my1(_y1), mu(_u), mv(_v), width(_dst->cols), stride(_stride), ustepIdx(_ustepIdx), vstepIdx(_vstepIdx) {}
void operator()(const BlockedRange& range) const void operator()(const BlockedRange& range) const
{ {
const int rangeBegin = range.begin() * 2; const int rangeBegin = range.begin() * 2;
const int rangeEnd = range.end() * 2; const int rangeEnd = range.end() * 2;
//R = 1.164(Y - 16) + 1.596(V - 128) size_t uvsteps[2] = {width/2, stride - width/2};
//G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128) int usIdx = ustepIdx, vsIdx = vstepIdx;
//B = 1.164(Y - 16) + 2.018(U - 128)
//R = (1220542(Y - 16) + 1673527(V - 128) + (1 << 19)) >> 20
//G = (1220542(Y - 16) - 852492(V - 128) - 409993(U - 128) + (1 << 19)) >> 20
//B = (1220542(Y - 16) + 2116026(U - 128) + (1 << 19)) >> 20
const int cY = 1220542; const int cY = 1220542;
const int cUB = 2116026; const int cUB = 2116026;
...@@ -2854,10 +2850,16 @@ struct YUV420p2RGB888Invoker ...@@ -2854,10 +2850,16 @@ struct YUV420p2RGB888Invoker
const int YUV420_SHIFT = 20; const int YUV420_SHIFT = 20;
const uchar* y1 = my1 + rangeBegin * stride; const uchar* y1 = my1 + rangeBegin * stride;
const uchar* u1 = mu + (range.begin() / 2) * stride + (range.begin() % 2) * width/2; const uchar* u1 = mu + (range.begin() / 2) * stride;
const uchar* v1 = mv + (range.begin() / 2) * stride + (range.begin() % 2) * width/2; const uchar* v1 = mv + (range.begin() / 2) * stride;
for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, u1 += width / 2, v1 += width / 2) if(range.begin() % 2 == 1)
{
u1 += uvsteps[(usIdx++) & 1];
v1 += uvsteps[(vsIdx++) & 1];
}
for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, u1 += uvsteps[(usIdx++) & 1], v1 += uvsteps[(vsIdx++) & 1])
{ {
uchar* row1 = dst->ptr<uchar>(j); uchar* row1 = dst->ptr<uchar>(j);
uchar* row2 = dst->ptr<uchar>(j + 1); uchar* row2 = dst->ptr<uchar>(j + 1);
...@@ -2892,12 +2894,6 @@ struct YUV420p2RGB888Invoker ...@@ -2892,12 +2894,6 @@ struct YUV420p2RGB888Invoker
row2[4] = saturate_cast<uchar>((y11 + guv) >> YUV420_SHIFT); row2[4] = saturate_cast<uchar>((y11 + guv) >> YUV420_SHIFT);
row2[3+bIdx] = saturate_cast<uchar>((y11 + buv) >> YUV420_SHIFT); row2[3+bIdx] = saturate_cast<uchar>((y11 + buv) >> YUV420_SHIFT);
} }
if(j % 4 == 2)
{
u1 += stride - width;
v1 += stride - width;
}
} }
} }
}; };
...@@ -2908,23 +2904,16 @@ struct YUV420p2RGBA8888Invoker ...@@ -2908,23 +2904,16 @@ struct YUV420p2RGBA8888Invoker
Mat* dst; Mat* dst;
const uchar* my1, *mu, *mv; const uchar* my1, *mu, *mv;
int width, stride; int width, stride;
int ustepIdx, vstepIdx;
YUV420p2RGBA8888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v) YUV420p2RGBA8888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int _ustepIdx, int _vstepIdx)
: dst(_dst), my1(_y1), mu(_u), mv(_v), width(_dst->cols), stride(_stride) {} : dst(_dst), my1(_y1), mu(_u), mv(_v), width(_dst->cols), stride(_stride), ustepIdx(_ustepIdx), vstepIdx(_vstepIdx) {}
void operator()(const BlockedRange& range) const void operator()(const BlockedRange& range) const
{ {
int rangeBegin = range.begin() * 2; int rangeBegin = range.begin() * 2;
int rangeEnd = range.end() * 2; int rangeEnd = range.end() * 2;
//R = 1.164(Y - 16) + 1.596(V - 128)
//G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
//B = 1.164(Y - 16) + 2.018(U - 128)
//R = (1220542(Y - 16) + 1673527(V - 128) + (1 << 19)) >> 20
//G = (1220542(Y - 16) - 852492(V - 128) - 409993(U - 128) + (1 << 19)) >> 20
//B = (1220542(Y - 16) + 2116026(U - 128) + (1 << 19)) >> 20
const int cY = 1220542; const int cY = 1220542;
const int cUB = 2116026; const int cUB = 2116026;
const int cUG = -409993; const int cUG = -409993;
...@@ -2932,11 +2921,20 @@ struct YUV420p2RGBA8888Invoker ...@@ -2932,11 +2921,20 @@ struct YUV420p2RGBA8888Invoker
const int cVR = 1673527; const int cVR = 1673527;
const int YUV420_SHIFT = 20; const int YUV420_SHIFT = 20;
size_t uvsteps[2] = {width/2, stride - width/2};
int usIdx = ustepIdx, vsIdx = vstepIdx;
const uchar* y1 = my1 + rangeBegin * stride; const uchar* y1 = my1 + rangeBegin * stride;
const uchar* u1 = mu + (range.begin() / 2) * stride + (range.begin() % 2) * width/2; const uchar* u1 = mu + (range.begin() / 2) * stride;
const uchar* v1 = mv + (range.begin() / 2) * stride + (range.begin() % 2) * width/2; const uchar* v1 = mv + (range.begin() / 2) * stride;
for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, u1 += width / 2, v1 += width / 2) if(range.begin() % 2 == 1)
{
u1 += uvsteps[(usIdx++) & 1];
v1 += uvsteps[(vsIdx++) & 1];
}
for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, u1 += uvsteps[(usIdx++) & 1], v1 += uvsteps[(vsIdx++) & 1])
{ {
uchar* row1 = dst->ptr<uchar>(j); uchar* row1 = dst->ptr<uchar>(j);
uchar* row2 = dst->ptr<uchar>(j + 1); uchar* row2 = dst->ptr<uchar>(j + 1);
...@@ -2975,12 +2973,6 @@ struct YUV420p2RGBA8888Invoker ...@@ -2975,12 +2973,6 @@ struct YUV420p2RGBA8888Invoker
row2[4+bIdx] = saturate_cast<uchar>((y11 + buv) >> YUV420_SHIFT); row2[4+bIdx] = saturate_cast<uchar>((y11 + buv) >> YUV420_SHIFT);
row2[7] = uchar(0xff); row2[7] = uchar(0xff);
} }
if(j % 4 == 2)
{
u1 += stride - width;
v1 += stride - width;
}
} }
} }
}; };
...@@ -3012,9 +3004,9 @@ inline void cvtYUV420sp2RGBA(Mat& _dst, int _stride, const uchar* _y1, const uch ...@@ -3012,9 +3004,9 @@ inline void cvtYUV420sp2RGBA(Mat& _dst, int _stride, const uchar* _y1, const uch
} }
template<int bIdx> template<int bIdx>
inline void cvtYUV420p2RGB(Mat& _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v) inline void cvtYUV420p2RGB(Mat& _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int ustepIdx, int vstepIdx)
{ {
YUV420p2RGB888Invoker<bIdx> converter(&_dst, _stride, _y1, _u, _v); YUV420p2RGB888Invoker<bIdx> converter(&_dst, _stride, _y1, _u, _v, ustepIdx, vstepIdx);
#ifdef HAVE_TBB #ifdef HAVE_TBB
if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION) if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION)
parallel_for(BlockedRange(0, _dst.rows/2), converter); parallel_for(BlockedRange(0, _dst.rows/2), converter);
...@@ -3024,9 +3016,9 @@ inline void cvtYUV420p2RGB(Mat& _dst, int _stride, const uchar* _y1, const uchar ...@@ -3024,9 +3016,9 @@ inline void cvtYUV420p2RGB(Mat& _dst, int _stride, const uchar* _y1, const uchar
} }
template<int bIdx> template<int bIdx>
inline void cvtYUV420p2RGBA(Mat& _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v) inline void cvtYUV420p2RGBA(Mat& _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int ustepIdx, int vstepIdx)
{ {
YUV420p2RGBA8888Invoker<bIdx> converter(&_dst, _stride, _y1, _u, _v); YUV420p2RGBA8888Invoker<bIdx> converter(&_dst, _stride, _y1, _u, _v, ustepIdx, vstepIdx);
#ifdef HAVE_TBB #ifdef HAVE_TBB
if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION) if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION)
parallel_for(BlockedRange(0, _dst.rows/2), converter); parallel_for(BlockedRange(0, _dst.rows/2), converter);
...@@ -3461,15 +3453,19 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn ) ...@@ -3461,15 +3453,19 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
int srcstep = (int)src.step; int srcstep = (int)src.step;
const uchar* y = src.ptr(); const uchar* y = src.ptr();
const uchar* u = y + srcstep * dstSz.height; const uchar* u = y + srcstep * dstSz.height;
const uchar* v = u + (srcstep * dstSz.height / 4); const uchar* v = y + srcstep * (dstSz.height + dstSz.height/4) + (dstSz.width/2) * ((dstSz.height % 4)/2);
if(uidx == 1) std::swap(u ,v);
int ustepIdx = 0;
int vstepIdx = dstSz.height % 4 == 2 ? 1 : 0;
if(uidx == 1) { std::swap(u ,v), std::swap(ustepIdx, vstepIdx); };
switch(dcn*10 + bidx) switch(dcn*10 + bidx)
{ {
case 30: cvtYUV420p2RGB<0>(dst, srcstep, y, u, v); break; case 30: cvtYUV420p2RGB<0>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break;
case 32: cvtYUV420p2RGB<2>(dst, srcstep, y, u, v); break; case 32: cvtYUV420p2RGB<2>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break;
case 40: cvtYUV420p2RGBA<0>(dst, srcstep, y, u, v); break; case 40: cvtYUV420p2RGBA<0>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break;
case 42: cvtYUV420p2RGBA<2>(dst, srcstep, y, u, v); break; case 42: cvtYUV420p2RGBA<2>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break;
default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break; default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break;
}; };
} }
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment