OpenCV中的cvtColor函数包括了很多颜色格式之间的转换,用起来很方便,这里对cvtColor函数的code进行了提取,经测试,和OpenCV3.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, 0, 0>(dst, srcstep, y, uv); break; case 301: cvtYUV420sp2RGB<_Tp, chs2, 0, 1>(dst, srcstep, y, uv); break; case 320: cvtYUV420sp2RGB<_Tp, chs2, 2, 0>(dst, srcstep, y, uv); break; case 321: cvtYUV420sp2RGB<_Tp, chs2, 2, 1>(dst, srcstep, y, uv); break; case 400: cvtYUV420sp2RGBA<_Tp, chs2, 0, 0>(dst, srcstep, y, uv); break; case 401: cvtYUV420sp2RGBA<_Tp, chs2, 0, 1>(dst, srcstep, y, uv); break; case 420: cvtYUV420sp2RGBA<_Tp, chs2, 2, 0>(dst, srcstep, y, uv); break; case 421: cvtYUV420sp2RGBA<_Tp, chs2, 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, 0>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break; case 32: cvtYUV420p2RGB<_Tp, chs2, 2>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break; case 40: cvtYUV420p2RGBA<_Tp, chs2, 0>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break; case 42: cvtYUV420p2RGBA<_Tp, chs2, 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, 0, 1>(src, dst); break; case 12: cvtRGBtoYUV420p<_Tp, chs1, chs2, 2, 1>(src, dst); break; case 20: cvtRGBtoYUV420p<_Tp, chs1, chs2, 0, 2>(src, dst); break; case 22: cvtRGBtoYUV420p<_Tp, chs1, chs2, 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 = 0; int i; tab[0] = tab[1] = (_Tp)0; for (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 * 4; return ((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.180423f, 0.212671f, 0.715160f, 0.072169f, 0.019334f, 0.119193f, 0.950227f};static const float XYZ2sRGB_D65[] ={ 3.240479f, -1.53715f, -0.498535f, -0.969256f, 1.875991f, 0.041556f, 0.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