OpenCVコード抽出cvtColor関数の実装

100314 ワード


OpenCVのcvtColor関数には多くの色フォーマット間の変換が含まれており、便利に使用できます.ここではcvtColor関数のcodeを抽出し、テストし、OpenCV 3を使用します.1結果は完全に一致した.
実装コードcvtColor.hpp:
// fbc_cv is free software and uses the same licence as OpenCV// Email: [email protected]#ifndef FBC_CV_CVTCOLOR_HPP_#define FBC_CV_CVTCOLOR_HPP_// reference: include/opencv2/imgproc.hpp#include "core/mat.hpp"#include "core/saturate.hpp"#include "imgproc.hpp"#include "core/core.hpp"namespace fbc {#define  FBC_DESCALE(x,n)     (((x) + (1 << ((n)-1))) >> (n))template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_RGB2RGB(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst, int bidx);template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_RGB2Gray(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst, int bidx);template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_Gray2RGB(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst);template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_RGB2YCrCb(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst, int bidx, const float* coeffs_f, const int* coeffs_i);template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_YCrCb2RGB(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst, int bidx, const float* coeffs_f, const int* coeffs_i);template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_RGB2XYZ(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst, int bidx);template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_XYZ2RGB(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst, int bidx);template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_RGB2HSV(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst, int bidx, int hrange);template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_RGB2HLS(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst, int bidx, int hrange);template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_HSV2RGB(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst, int bidx, int hrange);template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_HLS2RGB(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst, int bidx, int hrange);template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_RGB2Lab(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst, int bidx, const float* coeffs, const float* whitept, bool srgb);template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_RGB2Luv(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst, int bidx, const float* coeffs, const float* whitept, bool srgb);template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_Lab2RGB(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst, int bidx, const float* coeffs, const float* whitept, bool srgb);template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_Luv2RGB(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst, int bidx, const float* coeffs, const float* whitept, bool srgb);// Converts an image from one color space to another// support type: uchar/ushort/floattemplate<typename _Tp, int chs1, int chs2>int cvtColor(const Mat_<_tp chs1="">& src, Mat_<_tp chs2="">& dst, int code){ FBC_Assert(src.cols > 0 &&  src.rows > 0 && dst.cols > 0 && dst.rows > 0); FBC_Assert(src.cols == dst.cols); FBC_Assert(src.data != NULL && dst.data != NULL); FBC_Assert((sizeof(_Tp) == 1) || sizeof(_Tp) == 2 || sizeof(_Tp) == 4); // uchar || ushort || float int scn = src.channels; int dcn = dst.channels; // number of channels in the destination image Size sz = src.size(); Size dz = dst.size(); int bidx; switch (code) {  case CV_BGR2BGRA: case CV_RGB2BGRA: case CV_BGRA2BGR:  case CV_RGBA2BGR: case CV_RGB2BGR: case CV_BGRA2RGBA: {   FBC_Assert(scn == 3 || scn == 4);   dcn = code == CV_BGR2BGRA || code == CV_RGB2BGRA || code == CV_BGRA2RGBA ? 4 : 3;   FBC_Assert(dst.channels == dcn);   bidx = code == CV_BGR2BGRA || code == CV_BGRA2BGR ? 0 : 2;   CvtColorLoop_RGB2RGB(src, dst, bidx); // uchar/ushort/float   break;  }  case CV_BGR2GRAY: case CV_BGRA2GRAY: case CV_RGB2GRAY: case CV_RGBA2GRAY: {   FBC_Assert(scn == 3 || scn == 4);   FBC_Assert(dst.channels == 1);   bidx = code == CV_BGR2GRAY || code == CV_BGRA2GRAY ? 0 : 2;   CvtColorLoop_RGB2Gray(src, dst, bidx);   break;  }  case CV_GRAY2BGR: case CV_GRAY2BGRA: {   FBC_Assert(scn == 1 && (dcn == 3 || dcn == 4));   CvtColorLoop_Gray2RGB(src, dst);   break;  }  case CV_BGR2YCrCb: case CV_RGB2YCrCb:  case CV_BGR2YUV: case CV_RGB2YUV: {   FBC_Assert(scn == 3 || scn == 4);   bidx = code == CV_BGR2YCrCb || code == CV_BGR2YUV ? 0 : 2;   static const float yuv_f[] = { 0.114f, 0.587f, 0.299f, 0.492f, 0.877f };   static const int yuv_i[] = { B2Y, G2Y, R2Y, 8061, 14369 };   const float* coeffs_f = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? 0 : yuv_f;   const int* coeffs_i = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? 0 : yuv_i;   CvtColorLoop_RGB2YCrCb(src, dst, bidx, coeffs_f, coeffs_i);   break;  }  case CV_YCrCb2BGR: case CV_YCrCb2RGB:  case CV_YUV2BGR: case CV_YUV2RGB: {   FBC_Assert(scn == 3 && (dcn == 3 || dcn == 4));   bidx = code == CV_YCrCb2BGR || code == CV_YUV2BGR ? 0 : 2;   static const float yuv_f[] = { 2.032f, -0.395f, -0.581f, 1.140f };   static const int yuv_i[] = { 33292, -6472, -9519, 18678 };   const float* coeffs_f = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? 0 : yuv_f;   const int* coeffs_i = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? 0 : yuv_i;   CvtColorLoop_YCrCb2RGB(src, dst, bidx, coeffs_f, coeffs_i);   break;  }  case CV_BGR2XYZ: case CV_RGB2XYZ: {   FBC_Assert(scn == 3 || scn == 4);   bidx = code == CV_BGR2XYZ ? 0 : 2;   CvtColorLoop_RGB2XYZ(src, dst, bidx);   break;  }  case CV_XYZ2BGR: case CV_XYZ2RGB: {   FBC_Assert(scn == 3 && (dcn == 3 || dcn == 4));   bidx = code == CV_XYZ2BGR ? 0 : 2;   CvtColorLoop_XYZ2RGB(src, dst, bidx);   break;  }  case CV_BGR2HSV: case CV_RGB2HSV: case CV_BGR2HSV_FULL: case CV_RGB2HSV_FULL:  case CV_BGR2HLS: case CV_RGB2HLS: case CV_BGR2HLS_FULL: case CV_RGB2HLS_FULL: {   FBC_Assert(scn == 3 || scn == 4);   FBC_Assert(sizeof(_Tp) == 1 || sizeof(_Tp) == 4);   bidx = code == CV_BGR2HSV || code == CV_BGR2HLS ||    code == CV_BGR2HSV_FULL || code == CV_BGR2HLS_FULL ? 0 : 2;   int hrange = sizeof(_Tp) == 4 ? 360 : code == CV_BGR2HSV || code == CV_RGB2HSV ||    code == CV_BGR2HLS || code == CV_RGB2HLS ? 180 : 256;   if (code == CV_BGR2HSV || code == CV_RGB2HSV || code == CV_BGR2HSV_FULL || code == CV_RGB2HSV_FULL) {    CvtColorLoop_RGB2HSV(src, dst, bidx, hrange);   } else {    CvtColorLoop_RGB2HLS(src, dst, bidx, hrange);   }   break;  }  case CV_HSV2BGR: case CV_HSV2RGB: case CV_HSV2BGR_FULL: case CV_HSV2RGB_FULL:  case CV_HLS2BGR: case CV_HLS2RGB: case CV_HLS2BGR_FULL: case CV_HLS2RGB_FULL: {   FBC_Assert(scn == 3 && (dcn == 3 || dcn == 4));   FBC_Assert(sizeof(_Tp) == 1 || sizeof(_Tp) == 4);   bidx = code == CV_HSV2BGR || code == CV_HLS2BGR ||    code == CV_HSV2BGR_FULL || code == CV_HLS2BGR_FULL ? 0 : 2;   int hrange = sizeof(_Tp) == 4 ? 360 : code == CV_HSV2BGR || code == CV_HSV2RGB ||    code == CV_HLS2BGR || code == CV_HLS2RGB ? 180 : 255;   if (code == CV_HSV2BGR || code == CV_HSV2RGB || code == CV_HSV2BGR_FULL || code == CV_HSV2RGB_FULL) {    CvtColorLoop_HSV2RGB(src, dst, bidx, hrange);   } else {    CvtColorLoop_HLS2RGB(src, dst, bidx, hrange);   }   break;  }  case CV_BGR2Lab: case CV_RGB2Lab:  case CV_BGR2Luv: case CV_RGB2Luv: {   FBC_Assert(scn == 3 || scn == 4);   FBC_Assert(sizeof(_Tp) == 1 || sizeof(_Tp) == 4);   bidx = code == CV_BGR2Lab || code == CV_BGR2Luv ? 0 : 2;   bool srgb = code == CV_BGR2Lab || code == CV_RGB2Lab || code == CV_BGR2Luv || code == CV_RGB2Luv;   if (code == CV_BGR2Lab || code == CV_RGB2Lab) {    CvtColorLoop_RGB2Lab(src, dst, bidx, 0, 0, srgb);   } else {    CvtColorLoop_RGB2Luv(src, dst, bidx, 0, 0, srgb);   }   break;  }  case CV_Lab2BGR: case CV_Lab2RGB:  case CV_Luv2BGR: case CV_Luv2RGB: {   FBC_Assert(scn == 3 && (dcn == 3 || dcn == 4));   FBC_Assert(sizeof(_Tp) == 1 || sizeof(_Tp) == 4);   bidx = code == CV_Lab2BGR || code == CV_Luv2BGR ? 0 : 2;   bool srgb = code == CV_Lab2BGR || code == CV_Lab2RGB || code == CV_Luv2BGR || code == CV_Luv2RGB;   if (code == CV_Lab2BGR || code == CV_Lab2RGB) {    CvtColorLoop_Lab2RGB(src, dst, bidx, 0, 0, srgb);   } else {    CvtColorLoop_Luv2RGB(src, dst, bidx, 0, 0, srgb);   }   break;  }  case CV_YUV2BGR_NV21:  case CV_YUV2RGB_NV21:  case CV_YUV2BGR_NV12:  case CV_YUV2RGB_NV12:  case CV_YUV2BGRA_NV21: case CV_YUV2RGBA_NV21: case CV_YUV2BGRA_NV12: case CV_YUV2RGBA_NV12: {   // http://www.fourcc.org/yuv.php#NV21 == yuv420sp -> a plane of 8 bit Y samples followed by an interleaved V/U plane containing 8 bit 2x2 subsampled chroma samples   // http://www.fourcc.org/yuv.php#NV12 -> a plane of 8 bit Y samples followed by an interleaved U/V plane containing 8 bit 2x2 subsampled colour difference samples   dcn = (code == CV_YUV420sp2BGRA || code == CV_YUV420sp2RGBA || code == CV_YUV2BGRA_NV12 || code == CV_YUV2RGBA_NV12) ? 4 : 3;   FBC_Assert(dcn == dst.channels);   const int bIdx = (code == CV_YUV2BGR_NV21 || code == CV_YUV2BGRA_NV21 || code == CV_YUV2BGR_NV12 || code == CV_YUV2BGRA_NV12) ? 0 : 2;   const int uIdx = (code == CV_YUV2BGR_NV21 || code == CV_YUV2BGRA_NV21 || code == CV_YUV2RGB_NV21 || code == CV_YUV2RGBA_NV21) ? 1 : 0;   FBC_Assert(dcn == 3 || dcn == 4);   FBC_Assert(sz.width % 2 == 0 && sz.height % 3 == 0);   FBC_Assert(sizeof(_Tp) == 1);   //Size dstSz(sz.width, sz.height * 2 / 3);   FBC_Assert((sz.width == dz.width) && (dz.height = sz.height * 2 / 3));   int srcstep = (int)src.step;   const uchar* y = src.ptr();   const uchar* uv = y + srcstep * dz.height;   switch (dcn * 100 + bIdx * 10 + uIdx) {    case 300: cvtYUV420sp2RGB<_tp chs2="" class="hljs-number">0, 0>(dst, srcstep, y, uv); break;    case 301: cvtYUV420sp2RGB<_tp chs2="" class="hljs-number">0, 1>(dst, srcstep, y, uv); break;    case 320: cvtYUV420sp2RGB<_tp chs2="" class="hljs-number">2, 0>(dst, srcstep, y, uv); break;    case 321: cvtYUV420sp2RGB<_tp chs2="" class="hljs-number">2, 1>(dst, srcstep, y, uv); break;    case 400: cvtYUV420sp2RGBA<_tp chs2="" class="hljs-number">0, 0>(dst, srcstep, y, uv); break;    case 401: cvtYUV420sp2RGBA<_tp chs2="" class="hljs-number">0, 1>(dst, srcstep, y, uv); break;    case 420: cvtYUV420sp2RGBA<_tp chs2="" class="hljs-number">2, 0>(dst, srcstep, y, uv); break;    case 421: cvtYUV420sp2RGBA<_tp chs2="" class="hljs-number">2, 1>(dst, srcstep, y, uv); break;    default: FBC_Error("Unknown/unsupported color conversion code"); break;   };   break;  }  case CV_YUV2BGR_YV12: case CV_YUV2RGB_YV12: case CV_YUV2BGRA_YV12: case CV_YUV2RGBA_YV12:  case CV_YUV2BGR_IYUV: case CV_YUV2RGB_IYUV: case CV_YUV2BGRA_IYUV: case CV_YUV2RGBA_IYUV: {   //http://www.fourcc.org/yuv.php#YV12 == yuv420p -> It comprises an NxM Y plane followed by (N/2)x(M/2) V and U planes.   //http://www.fourcc.org/yuv.php#IYUV == I420 -> It comprises an NxN Y plane followed by (N/2)x(N/2) U and V planes   dcn = (code == CV_YUV2BGRA_YV12 || code == CV_YUV2RGBA_YV12 || code == CV_YUV2RGBA_IYUV || code == CV_YUV2BGRA_IYUV) ? 4 : 3;   FBC_Assert(dcn == dst.channels);   const int bIdx = (code == CV_YUV2BGR_YV12 || code == CV_YUV2BGRA_YV12 || code == CV_YUV2BGR_IYUV || code == CV_YUV2BGRA_IYUV) ? 0 : 2;   const int uIdx = (code == CV_YUV2BGR_YV12 || code == CV_YUV2RGB_YV12 || code == CV_YUV2BGRA_YV12 || code == CV_YUV2RGBA_YV12) ? 1 : 0;   FBC_Assert(dcn == 3 || dcn == 4);   FBC_Assert(sz.width % 2 == 0 && sz.height % 3 == 0);   FBC_Assert(sizeof(_Tp) == 1);   //Size dstSz(sz.width, sz.height * 2 / 3);   FBC_Assert((sz.width == dz.width) && (dz.height = sz.height * 2 / 3));   int srcstep = (int)src.step;   const uchar* y = src.ptr();   const uchar* u = y + srcstep * dz.height;   const uchar* v = y + srcstep * (dz.height + dz.height / 4) + (dz.width / 2) * ((dz.height % 4) / 2);   int ustepIdx = 0;   int vstepIdx = dz.height % 4 == 2 ? 1 : 0;   if (uIdx == 1) { std::swap(u, v), std::swap(ustepIdx, vstepIdx); }   switch (dcn * 10 + bIdx) {    case 30: cvtYUV420p2RGB<_tp chs2="" class="hljs-number">0>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break;    case 32: cvtYUV420p2RGB<_tp chs2="" class="hljs-number">2>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break;    case 40: cvtYUV420p2RGBA<_tp chs2="" class="hljs-number">0>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break;    case 42: cvtYUV420p2RGBA<_tp chs2="" class="hljs-number">2>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break;    default: FBC_Error("Unknown/unsupported color conversion code"); break;   };   break;  }  case CV_YUV2GRAY_420: {   FBC_Assert(dcn == 1 && scn == 1);   FBC_Assert(sz.width % 2 == 0 && sz.height % 3 == 0);   FBC_Assert(sizeof(_Tp) == 1);   //Size dstSz(sz.width, sz.height * 2 / 3);   FBC_Assert((sz.width == dz.width) && (dz.height = sz.height * 2 / 3));   //src.copyTo(dst, Rect(0, 0, sz.width, dz.height));   memcpy(dst.data, src.data, dz.area());   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: {   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;   FBC_Assert(scn == 3 || scn == 4);   FBC_Assert(sizeof(_Tp) == 1);   FBC_Assert(dcn == 1);   FBC_Assert(sz.width % 2 == 0 && sz.height % 2 == 0);   //Size dstSz(sz.width, sz.height / 2 * 3);   FBC_Assert((dz.width == sz.width) && (sz.height / 2 * 3 == dz.height));   switch (bIdx + uIdx * 10) {    case 10: cvtRGBtoYUV420p<_tp chs1="" chs2="" class="hljs-number">0, 1>(src, dst); break;    case 12: cvtRGBtoYUV420p<_tp chs1="" chs2="" class="hljs-number">2, 1>(src, dst); break;    case 20: cvtRGBtoYUV420p<_tp chs1="" chs2="" class="hljs-number">0, 2>(src, dst); break;    case 22: cvtRGBtoYUV420p<_tp chs1="" chs2="" class="hljs-number">2, 2>(src, dst); break;    default: FBC_Error("Unknown/unsupported color conversion code"); break;   };   break;  }  default:   FBC_Error("Unknown/unsupported color conversion code"); } return 0;}// computes cubic spline coefficients for a function: (xi=i, yi=f[i]), i=0..ntemplate<typename _Tp> static void splineBuild(const _Tp* f, int n, _Tp* tab){ _Tp cn = 0int i; tab[0] = tab[1] = (_Tp)0for (i = 1; i < n - 1; i++) {  _Tp t = 3 * (f[i + 1] - 2 * f[i] + f[i - 1]);  _Tp l = 1 / (4 - tab[(i - 1) * 4]);  tab[i * 4] = l; tab[i * 4 + 1] = (t - tab[(i - 1) * 4 + 1])*l; } for (i = n - 1; i >= 0; i--) {  _Tp c = tab[i * 4 + 1] - tab[i * 4] * cn;  _Tp b = f[i + 1] - f[i] - (cn + c * 2)*(_Tp)0.3333333333333333;  _Tp d = (cn - c)*(_Tp)0.3333333333333333;  tab[i * 4] = f[i]; tab[i * 4 + 1] = b;  tab[i * 4 + 2] = c; tab[i * 4 + 3] = d;  cn = c; }}// interpolates value of a function at x, 0 <= x <= n using a cubic spline.template<typename _Tp> static inline _Tp splineInterpolate(_Tp x, const _Tp* tab, int n)// don't touch this function without urgent need - some versions of gcc fail to inline it correctly int ix = std::min(std::max(int(x), 0), n - 1); x -= ix; tab += ix * 4return ((tab[3] * x + tab[2])*x + tab[1])*x + tab[0];}template<typename _Tp> struct ColorChannel{ typedef float worktype_f; static _Tp max() { return std::numeric_limits<_tp>::max(); } static _Tp half() { return (_Tp)(max() / 2 + 1); }};template<> struct ColorChannel{ typedef float worktype_f; static float max() { return 1.f; } static float half() { return 0.5f; }};#undef R2Y#undef G2Y#undef B2Yenum{ yuv_shift = 14, xyz_shift = 12, R2Y = 4899, G2Y = 9617, B2Y = 1868, BLOCK_SIZE = 256};template<typename _Tp> struct RGB2Gray{ typedef _Tp channel_type; RGB2Gray(int _srccn, int blueIdx, const float* _coeffs) : srccn(_srccn) {  static const float coeffs0[] = { 0.299f, 0.587f, 0.114f };  memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 3 * sizeof(coeffs[0]));  if (blueIdx == 0)   std::swap(coeffs[0], coeffs[2]); } void operator()(const _Tp* src, _Tp* dst, int n) const {  int scn = srccn;  float cb = coeffs[0], cg = coeffs[1], cr = coeffs[2];  for (int i = 0; i < n; i++, src += scn)   dst[i] = saturate_cast<_tp>(src[0] * cb + src[1] * cg + src[2] * cr); } int srccn; float coeffs[3];};template<> struct RGB2Gray{ typedef uchar channel_type; RGB2Gray(int _srccn, int blueIdx, const int* coeffs) : srccn(_srccn) {  const int coeffs0[] = { R2Y, G2Y, B2Y };  if (!coeffs) coeffs = coeffs0;  int b = 0, g = 0, r = (1 << (yuv_shift - 1));  int db = coeffs[blueIdx ^ 2], dg = coeffs[1], dr = coeffs[blueIdx];  for (int i = 0; i < 256; i++, b += db, g += dg, r += dr) {   tab[i] = b;   tab[i + 256] = g;   tab[i + 512] = r;  } } void operator()(const uchar* src, uchar* dst, int n) const {  int scn = srccn;  const int* _tab = tab;  for (int i = 0; i < n; i++, src += scn)   dst[i] = (uchar)((_tab[src[0]] + _tab[src[1] + 256] + _tab[src[2] + 512]) >> yuv_shift); } int srccn; int tab[256 * 3];};template<> struct RGB2Gray{ typedef ushort channel_type; RGB2Gray(int _srccn, int blueIdx, const int* _coeffs) : srccn(_srccn) {  static const int coeffs0[] = { R2Y, G2Y, B2Y };  memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 3 * sizeof(coeffs[0]));  if (blueIdx == 0)   std::swap(coeffs[0], coeffs[2]); } void operator()(const ushort* src, ushort* dst, int n) const {  int scn = srccn, cb = coeffs[0], cg = coeffs[1], cr = coeffs[2];  for (int i = 0; i < n; i++, src += scn)   dst[i] = (ushort)FBC_DESCALE((unsigned)(src[0] * cb + src[1] * cg + src[2] * cr), yuv_shift); } int srccn; int coeffs[3];};template<typename _Tp>struct Gray2RGB{ typedef _Tp channel_type; Gray2RGB(int _dstcn) : dstcn(_dstcn) {} void operator()(const _Tp* src, _Tp* dst, int n) const {  if (dstcn == 3) {   for (int i = 0; i < n; i++, dst += 3)    dst[0] = dst[1] = dst[2] = src[i];  } else {   _Tp alpha = ColorChannel<_tp>::max();   for (int i = 0; i < n; i++, dst += 4) {    dst[0] = dst[1] = dst[2] = src[i];    dst[3] = alpha;   }  } } int dstcn;};template<typename _Tp> struct RGB2YCrCb_f{ typedef _Tp channel_type; RGB2YCrCb_f(int _srccn, int _blueIdx, const float* _coeffs) : srccn(_srccn), blueIdx(_blueIdx) {  static const float coeffs0[] = { 0.299f, 0.587f, 0.114f, 0.713f, 0.564f };  memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5 * sizeof(coeffs[0]));  if (blueIdx == 0) std::swap(coeffs[0], coeffs[2]); } void operator()(const _Tp* src, _Tp* dst, int n) const {  int scn = srccn, bidx = blueIdx;  const _Tp delta = ColorChannel<_tp>::half();  float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];  n *= 3;  for (int i = 0; i < n; i += 3, src += scn) {   _Tp Y = saturate_cast<_tp>(src[0] * C0 + src[1] * C1 + src[2] * C2);   _Tp Cr = saturate_cast<_tp>((src[bidx ^ 2] - Y)*C3 + delta);   _Tp Cb = saturate_cast<_tp>((src[bidx] - Y)*C4 + delta);   dst[i] = Y; dst[i + 1] = Cr; dst[i + 2] = Cb;  } } int srccn, blueIdx; float coeffs[5];};template<typename _Tp> struct RGB2YCrCb_i{ typedef _Tp channel_type; RGB2YCrCb_i(int _srccn, int _blueIdx, const int* _coeffs) : srccn(_srccn), blueIdx(_blueIdx) {  static const int coeffs0[] = { R2Y, G2Y, B2Y, 11682, 9241 };  memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5 * sizeof(coeffs[0]));  if (blueIdx == 0) std::swap(coeffs[0], coeffs[2]); } void operator()(const _Tp* src, _Tp* dst, int n) const {  int scn = srccn, bidx = blueIdx;  int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];  int delta = ColorChannel<_tp>::half()*(1 << yuv_shift);  n *= 3;  for (int i = 0; i < n; i += 3, src += scn) {   int Y = FBC_DESCALE(src[0] * C0 + src[1] * C1 + src[2] * C2, yuv_shift);   int Cr = FBC_DESCALE((src[bidx ^ 2] - Y)*C3 + delta, yuv_shift);   int Cb = FBC_DESCALE((src[bidx] - Y)*C4 + delta, yuv_shift);   dst[i] = saturate_cast<_tp>(Y);   dst[i + 1] = saturate_cast<_tp>(Cr);   dst[i + 2] = saturate_cast<_tp>(Cb);  } } int srccn, blueIdx; int coeffs[5];};template<typename _Tp> struct YCrCb2RGB_f{ typedef _Tp channel_type; YCrCb2RGB_f(int _dstcn, int _blueIdx, const float* _coeffs)  : dstcn(_dstcn), blueIdx(_blueIdx) {  static const float coeffs0[] = { 1.403f, -0.714f, -0.344f, 1.773f };  memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 4 * sizeof(coeffs[0])); } void operator()(const _Tp* src, _Tp* dst, int n) const {  int dcn = dstcn, bidx = blueIdx;  const _Tp delta = ColorChannel<_tp>::half(), alpha = ColorChannel<_tp>::max();  float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];  n *= 3;  for (int i = 0; i < n; i += 3, dst += dcn) {   _Tp Y = src[i];   _Tp Cr = src[i + 1];   _Tp Cb = src[i + 2];   _Tp b = saturate_cast<_tp>(Y + (Cb - delta)*C3);   _Tp g = saturate_cast<_tp>(Y + (Cb - delta)*C2 + (Cr - delta)*C1);   _Tp r = saturate_cast<_tp>(Y + (Cr - delta)*C0);   dst[bidx] = b; dst[1] = g; dst[bidx ^ 2] = r;   if (dcn == 4)    dst[3] = alpha;  } } int dstcn, blueIdx; float coeffs[4];};template<typename _Tp> struct YCrCb2RGB_i{ typedef _Tp channel_type; YCrCb2RGB_i(int _dstcn, int _blueIdx, const int* _coeffs)  : dstcn(_dstcn), blueIdx(_blueIdx) {  static const int coeffs0[] = { 22987, -11698, -5636, 29049 };  memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 4 * sizeof(coeffs[0])); } void operator()(const _Tp* src, _Tp* dst, int n) const {  int dcn = dstcn, bidx = blueIdx;  const _Tp delta = ColorChannel<_tp>::half(), alpha = ColorChannel<_tp>::max();  int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];  n *= 3;  for (int i = 0; i < n; i += 3, dst += dcn) {   _Tp Y = src[i];   _Tp Cr = src[i + 1];   _Tp Cb = src[i + 2];   int b = Y + FBC_DESCALE((Cb - delta)*C3, yuv_shift);   int g = Y + FBC_DESCALE((Cb - delta)*C2 + (Cr - delta)*C1, yuv_shift);   int r = Y + FBC_DESCALE((Cr - delta)*C0, yuv_shift);   dst[bidx] = saturate_cast<_tp>(b);   dst[1] = saturate_cast<_tp>(g);   dst[bidx ^ 2] = saturate_cast<_tp>(r);   if (dcn == 4)    dst[3] = alpha;  } } int dstcn, blueIdx; int coeffs[4];};static const float sRGB2XYZ_D65[] ={ 0.412453f, 0.357580f, 0.180423f0.212671f, 0.715160f, 0.072169f0.019334f, 0.119193f, 0.950227f};static const float XYZ2sRGB_D65[] ={ 3.240479f, -1.53715f, -0.498535f-0.969256f, 1.875991f, 0.041556f0.055648f, -0.204043f, 1.057311f};template<typename _Tp> struct RGB2XYZ_f{ typedef _Tp channel_type; RGB2XYZ_f(int _srccn, int blueIdx, const float* _coeffs) : srccn(_srccn) {  memcpy(coeffs, _coeffs ? _coeffs : sRGB2XYZ_D65, 9 * sizeof(coeffs[0]));  if (blueIdx == 0) {   std::swap(coeffs[0], coeffs[2]);   std::swap(coeffs[3], coeffs[5]);   std::swap(coeffs[6], coeffs[8]);  } } void operator()(const _Tp* src, _Tp* dst, int n) const {  int scn = srccn;  float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2],   C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5],   C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8];  n *= 3;  for (int i = 0; i < n; i += 3, src += scn) {   _Tp X = saturate_cast<_tp>(src[0] * C0 + src[1] * C1 + src[2] * C2);   _Tp Y = saturate_cast<_tp>(src[0] * C3 + src[1] * C4 + src[2] * C5);   _Tp Z = saturate_cast<_tp>(src[0] * C6 + src[1] * C7 + src[2] * C8);   dst[i] = X; dst[i + 1] = Y; dst[i + 2] = Z;  } } int srccn; float coeffs[9];};template<typename _Tp> struct RGB2XYZ_i{ typedef _Tp channel_type; RGB2XYZ_i(int _srccn, int blueIdx, const float* _coeffs) : srccn(_srccn) {  static const int coeffs0[] = {   1689, 1465, 739,   871, 2929, 296,   79, 488, 3892  };  for (int i = 0; i < 9; i++)   coeffs[i] = _coeffs ? cvRound(_coeffs[i] * (1 << xyz_shift)) : coeffs0[i];  if (blueIdx == 0) {   std::swap(coeffs[0], coeffs[2]);   std::swap(coeffs[3], coeffs[5]);   std::swap(coeffs[6], coeffs[8]);  } } void operator()(const _Tp* src, _Tp* dst, int n) const {  int scn = srccn;  int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2],   C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5],   C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8];  n *= 3;  for (int i = 0; i < n; i += 3, src += scn) {   int X = FBC_DESCALE(src[0] * C0 + src[1] * C1 + src[2] * C2, xyz_shift);   int Y = FBC_DESCALE(src[0] * C3 + src[1] * C4 + src[2] * C5, xyz_shift);   int Z = FBC_DESCALE(src[0] * C6 + src[1] * C7 + src[2] * C8, xyz_shift);   dst[i] = saturate_cast<_tp>(X); dst[i + 1] = saturate_cast<_tp>(Y);   dst[i + 2] = saturate_cast<_tp>(Z);  } } int srccn; int coeffs[9];};template<typename _Tp> struct XYZ2RGB_f{ typedef _Tp channel_type; XYZ2RGB_f(int _dstcn, int _blueIdx, const float* _coeffs) : dstcn(_dstcn), blueIdx(_blueIdx) {  memcpy(coeffs, _coeffs ? _coeffs : XYZ2sRGB_D65, 9 * sizeof(coeffs[0]));  if (blueIdx == 0) {   std::swap(coeffs[0], coeffs[6]);   std::swap(coeffs[1], coeffs[7]);   std::swap(coeffs[2], coeffs[8]);  } } void operator()(const _Tp* src, _Tp* dst, int n) const {  int dcn = dstcn;  _Tp alpha = ColorChannel<_tp>::max();  float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2],   C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5],   C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8];  n *= 3;  for (int i = 0; i < n; i += 3, dst += dcn) {   _Tp B = saturate_cast<_tp>(src[i] * C0 + src[i + 1] * C1 + src[i + 2] * C2);   _Tp G = saturate_cast<_tp>(src[i] * C3 + src[i + 1] * C4 + src[i + 2] * C5);   _Tp R = saturate_cast<_tp>(src[i] * C6 + src[i + 1] * C7 + src[i + 2] * C8);   dst[0] = B; dst[1] = G; dst[2] = R;   if (dcn == 4)    dst[3] = alpha;  } } int dstcn, blueIdx; float coeffs[9];};template<typename _Tp> struct XYZ2RGB_i{ typedef _Tp channel_type; XYZ2RGB_i(int _dstcn, int _blueIdx, const int* _coeffs)  : dstcn(_dstcn), blueIdx(_blueIdx) {  static const int coeffs0[] = {   13273, -6296, -2042,   -3970, 7684, 170,   228, -836, 4331  };  for (int i = 0; i < 9; i++)   coeffs[i] = _coeffs ? cvRound(_coeffs[i] * (1 << xyz_shift)) : coeffs0[i];  if (blueIdx == 0) {   std::swap(coeffs[0], coeffs[6]);   std::swap(coeffs[1], coeffs[7]);   std::swap(coeffs[2], coeffs[8]);  } } void operator()(const _Tp* src, _Tp* dst, int n) const {  int dcn = dstcn;  _Tp alpha = ColorChannel<_tp>::max();  int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2],   C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5],   C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8];  n *= 3;  for (int i = 0; i < n; i += 3, dst += dcn) {   int B = FBC_DESCALE(src[i] * C0 + src[i + 1] * C1 + src[i + 2] * C2, xyz_shift);   int G = FBC_DESCALE(src[i] * C3 + src[i + 1] * C4 + src[i + 2] * C5, xyz_shift);   int R = FBC_DESCALE(src[i] * C6 + src[i + 1] * C7 + src[i + 2] * C8, xyz_shift);   dst[0] = saturate_cast<_tp>(B); dst[1] = saturate_cast<_tp>(G);   dst[2] = saturate_cast<_tp>(R);   if (dcn == 4)    dst[3] = alpha;  } } int dstcn, blueIdx; int coeffs[9];};struct RGB2HSV_b{ typedef uchar channel_type; RGB2HSV_b(int _srccn, int _blueIdx, int _hrange) : srccn(_srccn), blueIdx(_blueIdx), hrange(_hrange) {  FBC_Assert(hrange == 180 || hrange == 256); } void operator()(const uchar* src, uchar* dst, int n) const {  int i, bidx = blueIdx, scn = srccn;  const int hsv_shift = 12;  static int sdiv_table[256];  static int hdiv_table180[256];  static int hdiv_table256[256];  static volatile bool initialized = false;  int hr = hrange;  const int* hdiv_table = hr == 180 ? hdiv_table180 : hdiv_table256;  n *= 3;  if (!initialized) {   sdiv_table[0] = hdiv_table180[0] = hdiv_table256[0] = 0;   for (i = 1; i < 256; i++) {    sdiv_table[i] = saturate_cast<int>((255 << hsv_shift) / (1.*i));    hdiv_table180[i] = saturate_cast<int>((180 << hsv_shift) / (6.*i));    hdiv_table256[i] = saturate_cast<int>((256 << hsv_shift) / (6.*i));   }   initialized = true;  }  for (i = 0; i < n; i += 3, src += scn) {   int b = src[bidx], g = src[1], r = src[bidx ^ 2];   int h, s, v = b;   int vmin = b, diff;   int vr, vg;   FBC_CALC_MAX_8U(v, g);   FBC_CALC_MAX_8U(v, r);   FBC_CALC_MIN_8U(vmin, g);   FBC_CALC_MIN_8U(vmin, r);   diff = v - vmin;   vr = v == r ? -1 : 0;   vg = v == g ? -1 : 0;   s = (diff * sdiv_table[v] + (1 << (hsv_shift - 1))) >> hsv_shift;   h = (vr & (g - b)) + (~vr & ((vg & (b - r + 2 * diff)) + ((~vg) & (r - g + 4 * diff))));   h = (h * hdiv_table[diff] + (1 << (hsv_shift - 1))) >> hsv_shift;   h += h < 0 ? hr : 0;   dst[i] = saturate_cast(h);   dst[i + 1] = (uchar)s;   dst[i + 2] = (uchar)v;  } } int srccn, blueIdx, hrange;};struct RGB2HSV_f{ typedef float channel_type; RGB2HSV_f(int _srccn, int _blueIdx, float _hrange) : srccn(_srccn), blueIdx(_blueIdx), hrange(_hrange) {} void operator()(const float* src, float* dst, int n) const {  int i, bidx = blueIdx, scn = srccn;  float hscale = hrange*(1.f / 360.f);  n *= 3;  for (i = 0; i < n; i += 3, src += scn) {   float b = src[bidx], g = src[1], r = src[bidx ^ 2];   float h, s, v;   float vmin, diff;   v = vmin = r;   if (v < g) v = g;   if (v < b) v = b;   if (vmin > g) vmin = g;   if (vmin > b) vmin = b;   diff = v - vmin;   s = diff / (float)(fabs(v) + FLT_EPSILON);   diff = (float)(60. / (diff + FLT_EPSILON));   if (v == r)    h = (g - b)*diff;   else if (v == g)    h = (b - r)*diff + 120.f;   else    h = (r - g)*diff + 240.f;   if (h < 0) h += 360.f;   dst[i] = h*hscale;   dst[i + 1] = s;   dst[i + 2] = v;  } } int srccn, blueIdx; float hrange;};struct RGB2HLS_f{ typedef float channel_type; RGB2HLS_f(int _srccn, int _blueIdx, float _hrange) : srccn(_srccn), blueIdx(_blueIdx), hrange(_hrange) {} void operator()(const float* src, float* dst, int n) const {  int i, bidx = blueIdx, scn = srccn;  float hscale = hrange*(1.f / 360.f);  n *= 3;  for (i = 0; i < n; i += 3, src += scn) {   float b = src[bidx], g = src[1], r = src[bidx ^ 2];   float h = 0.f, s = 0.f, l;   float vmin, vmax, diff;   vmax = vmin = r;   if (vmax < g) vmax = g;   if (vmax < b) vmax = b;   if (vmin > g) vmin = g;   if (vmin > b) vmin = b;   diff = vmax - vmin;   l = (vmax + vmin)*0.5f;   if (diff > FLT_EPSILON) {    s = l < 0.5f ? diff / (vmax + vmin) : diff / (2 - vmax - vmin);    diff = 60.f / diff;    if (vmax == r)     h = (g - b)*diff;    else if (vmax == g)     h = (b - r)*diff + 120.f;    else     h = (r - g)*diff + 240.f;    if (h < 0.f) h += 360.f;   }   dst[i] = h*hscale;   dst[i + 1] = l;   dst[i + 2] = s;  } } int srccn, blueIdx; float hrange;};struct RGB2HLS_b{ typedef uchar channel_type; RGB2HLS_b(int _srccn, int _blueIdx, int _hrange) : srccn(_srccn), cvt(3, _blueIdx, (float)_hrange) { } void operator()(const uchar* src, uchar* dst, int n) const {  int i, j, scn = srccn;  float FBC_DECL_ALIGNED(16) buf[3 * BLOCK_SIZE];  for (i = 0; i < n; i += BLOCK_SIZE, dst += BLOCK_SIZE * 3) {   int dn = std::min(n - i, (int)BLOCK_SIZE);   j = 0;   for (; j < dn * 3; j += 3, src += scn) {    buf[j] = src[0] * (1.f / 255.f);    buf[j + 1] = src[1] * (1.f / 255.f);    buf[j + 2] = src[2] * (1.f / 255.f);   }   cvt(buf, buf, dn);   j = 0;   for (; j < dn * 3; j += 3) {    dst[j] = saturate_cast(buf[j]);    dst[j + 1] = saturate_cast(buf[j + 1] * 255.f);    dst[j + 2] = saturate_cast(buf[j + 2] * 255.f);   }  } } int srccn; RGB2HLS_f cvt;};struct HSV2RGB_f{ typedef float channel_type; HSV2RGB_f(int _dstcn, int _blueIdx, float _hrange)  : dstcn(_dstcn), blueIdx(_blueIdx), hscale(6.f / _hrange) {} void operator()(const float* src, float* dst, int n) const {  int i, bidx = blueIdx, dcn = dstcn;  float _hscale = hscale;  float alpha = ColorChannel<float>::max();  n *= 3;  for (i = 0; i < n; i += 3, dst += dcn) {   float h = src[i], s = src[i + 1], v = src[i + 2];   float b, g, r;   if (s == 0)    b = g = r = v;   else {    static const int sector_data[][3] =    { { 1, 3, 0 }, { 1, 0, 2 }, { 3, 0, 1 }, { 0, 2, 1 }, { 0, 1, 3 }, { 2, 1, 0 } };    float tab[4];    int sector;    h *= _hscale;    if (h < 0)     do h += 6; while (h < 0);    else if (h >= 6)     do h -= 6; while (h >= 6);    sector = fbcFloor(h);    h -= sector;    if ((unsigned)sector >= 6u) {     sector = 0;     h = 0.f;    }    tab[0] = v;    tab[1] = v*(1.f - s);    tab[2] = v*(1.f - s*h);    tab[3] = v*(1.f - s*(1.f - h));    b = tab[sector_data[sector][0]];    g = tab[sector_data[sector][1]];    r = tab[sector_data[sector][2]];   }   dst[bidx] = b;   dst[1] = g;   dst[bidx ^ 2] = r;   if (dcn == 4)    dst[3] = alpha;  } } int dstcn, blueIdx; float hscale;};struct HSV2RGB_b{ typedef uchar channel_type; HSV2RGB_b(int _dstcn, int _blueIdx, int _hrange) : dstcn(_dstcn), cvt(3, _blueIdx, (float)_hrange) {} void operator()(const uchar* src, uchar* dst, int n) const {  int i, j, dcn = dstcn;  uchar alpha = ColorChannel::max();  float FBC_DECL_ALIGNED(16) buf[3 * BLOCK_SIZE];  for (i = 0; i < n; i += BLOCK_SIZE, src += BLOCK_SIZE * 3) {   int dn = std::min(n - i, (int)BLOCK_SIZE);   j = 0;   for (; j < dn * 3; j += 3) {    buf[j] = src[j];    buf[j + 1] = src[j + 1] * (1.f / 255.f);    buf[j + 2] = src[j + 2] * (1.f / 255.f);   }   cvt(buf, buf, dn);   j = 0;   for (; j < dn * 3; j += 3, dst += dcn) {    dst[0] = saturate_cast(buf[j] * 255.f);    dst[1] = saturate_cast(buf[j + 1] * 255.f);    dst[2] = saturate_cast(buf[j + 2] * 255.f);    if (dcn == 4)     dst[3] = alpha;   }  } } int dstcn; HSV2RGB_f cvt;};struct HLS2RGB_f{ typedef float channel_type; HLS2RGB_f(int _dstcn, int _blueIdx, float _hrange) : dstcn(_dstcn), blueIdx(_blueIdx), hscale(6.f / _hrange) {} void operator()(const float* src, float* dst, int n) const {  int i, bidx = blueIdx, dcn = dstcn;  float _hscale = hscale;  float alpha = ColorChannel<float>::max();  n *= 3;  for (i = 0; i < n; i += 3, dst += dcn) {   float h = src[i], l = src[i + 1], s = src[i + 2 。 ! ! ! ! !https://blog.csdn.net/jiangjunshow