这里以CV_BGR2YUV_I420来讲
1. opencv244
core.cpp
void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn ) { ... case COLOR_RGB2YUV_YV12: case COLOR_BGR2YUV_YV12: case COLOR_RGBA2YUV_YV12: case COLOR_BGRA2YUV_YV12: case COLOR_RGB2YUV_IYUV: case COLOR_BGR2YUV_IYUV: case COLOR_RGBA2YUV_IYUV: case COLOR_BGRA2YUV_IYUV: if (dcn <= 0) dcn = 1; uidx = (code == COLOR_BGR2YUV_IYUV || code == COLOR_BGRA2YUV_IYUV || code == COLOR_RGB2YUV_IYUV || code == COLOR_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 ); _dst.create(Size(sz.width, sz.height / 2 * 3), CV_MAKETYPE(depth, dcn)); dst = _dst.getMat(); hal::cvtBGRtoThreePlaneYUV(src.data, src.step, dst.data, dst.step, src.cols, src.rows, scn, swapBlue(code), uidx); break; ... }
color.cpp
void cvtBGRtoThreePlaneYUV(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int scn, bool swapBlue, int uIdx) { CV_INSTRUMENT_REGION() CALL_HAL(cvtBGRtoThreePlaneYUV, cv_hal_cvtBGRtoThreePlaneYUV, src_data, src_step, dst_data, dst_step, width, height, scn, swapBlue, uIdx); uchar * uv_data = dst_data + dst_step * height; RGB888toYUV420pInvoker(src_data, src_step, dst_data, uv_data, dst_step, width, height, scn, swapBlue, uIdx == 2, false).convert(); }
color.cpp
struct RGB888toYUV420pInvoker: public ParallelLoopBody { RGB888toYUV420pInvoker(const uchar * _src_data, size_t _src_step, uchar * _y_data, uchar * _uv_data, size_t _dst_step, int _src_width, int _src_height, int _scn, bool swapBlue_, bool swapUV_, bool interleaved_) : src_data(_src_data), src_step(_src_step), y_data(_y_data), uv_data(_uv_data), dst_step(_dst_step), src_width(_src_width), src_height(_src_height), scn(_scn), swapBlue(swapBlue_), swapUV(swapUV_), interleaved(interleaved_) { } void operator()(const Range& rowRange) const { const int w = src_width; const int h = src_height; const int cn = scn; for( int i = rowRange.start; i < rowRange.end; i++ ) { const uchar* brow0 = src_data + src_step * (2 * i); const uchar* grow0 = brow0 + 1; const uchar* rrow0 = brow0 + 2; const uchar* brow1 = src_data + src_step * (2 * i + 1); const uchar* grow1 = brow1 + 1; const uchar* rrow1 = brow1 + 2; if (swapBlue) { std::swap(brow0, rrow0); std::swap(brow1, rrow1); } uchar* y = y_data + dst_step * (2*i); uchar* u; uchar* v; if (interleaved) { u = uv_data + dst_step * i; v = uv_data + dst_step * i + 1; } else { u = uv_data + dst_step * (i/2) + (i % 2) * (w/2); v = uv_data + dst_step * ((i + h/2)/2) + ((i + h/2) % 2) * (w/2); } if (swapUV) { std::swap(u, v); } for( int j = 0, k = 0; j < w * cn; j += 2 * cn, k++ ) { int r00 = rrow0[j]; int g00 = grow0[j]; int b00 = brow0[j]; int r01 = rrow0[cn + j]; int g01 = grow0[cn + j]; int b01 = brow0[cn + j]; int r10 = rrow1[j]; int g10 = grow1[j]; int b10 = brow1[j]; int r11 = rrow1[cn + j]; int g11 = grow1[cn + j]; int b11 = brow1[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; if (interleaved) { u[k*2] = saturate_cast<uchar>(u00 >> ITUR_BT_601_SHIFT); v[k*2] = saturate_cast<uchar>(v00 >> ITUR_BT_601_SHIFT); } else { u[k] = saturate_cast<uchar>(u00 >> ITUR_BT_601_SHIFT); v[k] = saturate_cast<uchar>(v00 >> ITUR_BT_601_SHIFT); } } } } void convert() const { if( src_width * src_height >= 320*240 ) parallel_for_(Range(0, src_height/2), *this); else operator()(Range(0, src_height/2)); } private: RGB888toYUV420pInvoker& operator=(const RGB888toYUV420pInvoker&); const uchar * src_data; size_t src_step; uchar *y_data, *uv_data; size_t dst_step; int src_width; int src_height; const int scn; bool swapBlue; bool swapUV; bool interleaved; };
2. opencv347 使用opencl
bool oclCvtColorTwoPlaneYUV2BGR( InputArray _src, OutputArray _dst, int dcn, int bidx, int uidx ) { OclHelper< Set<1>, Set<3, 4>, Set<CV_8U>, FROM_YUV > h(_src, _dst, dcn); if(!h.createKernel("YUV2RGB_NVx", ocl::imgproc::color_yuv_oclsrc, format("-D dcn=%d -D bidx=%d -D uidx=%d", dcn, bidx, uidx))) { return false; } return h.run(); }