diff --git a/3rdparty/libjpeg/jerror.c b/3rdparty/libjpeg/jerror.c index 3da7be86a0..a44463cf18 100644 --- a/3rdparty/libjpeg/jerror.c +++ b/3rdparty/libjpeg/jerror.c @@ -23,6 +23,7 @@ #include "jpeglib.h" #include "jversion.h" #include "jerror.h" +#include <stdlib.h> #ifdef USE_WINDOWS_MESSAGEBOX #include <windows.h> diff --git a/modules/core/include/opencv2/core/operations.hpp b/modules/core/include/opencv2/core/operations.hpp index 92c4c7b815..5a902bf2a3 100644 --- a/modules/core/include/opencv2/core/operations.hpp +++ b/modules/core/include/opencv2/core/operations.hpp @@ -3266,6 +3266,41 @@ partition( const vector<_Tp>& _vec, vector<int>& labels, return nclasses; } +// computes cubic spline coefficients for a function: (xi=i, yi=f[i]), i=0..n +template<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) +{ + int ix = cvFloor(x); + ix = std::min(std::max(ix, 0), n-1); + x -= ix; + tab += ix*4; + return ((tab[3]*x + tab[2])*x + tab[1])*x + tab[0]; +} + ////////////////////////////////////////////////////////////////////////////// // bridge C++ => C Seq API diff --git a/modules/imgproc/include/opencv2/imgproc/types_c.h b/modules/imgproc/include/opencv2/imgproc/types_c.h index 182c22b4a4..c652a5609a 100644 --- a/modules/imgproc/include/opencv2/imgproc/types_c.h +++ b/modules/imgproc/include/opencv2/imgproc/types_c.h @@ -206,6 +206,21 @@ enum CV_HLS2BGR_FULL = 72, CV_HLS2RGB_FULL = 73, + CV_LBGR2Lab = 74, + CV_LRGB2Lab = 75, + CV_LBGR2Luv = 76, + CV_LRGB2Luv = 77, + + CV_Lab2LBGR = 78, + CV_Lab2LRGB = 79, + CV_Luv2LBGR = 80, + CV_Luv2LRGB = 81, + + CV_BGR2YUV = 82, + CV_RGB2YUV = 83, + CV_YUV2BGR = 84, + CV_YUV2RGB = 85, + CV_COLORCVT_MAX =100 }; diff --git a/modules/imgproc/src/color.cpp b/modules/imgproc/src/color.cpp index 6ad0db2671..2baf3024c8 100644 --- a/modules/imgproc/src/color.cpp +++ b/modules/imgproc/src/color.cpp @@ -6,10 +6,12 @@ // If you do not agree to this license, do not download, install, // copy or use the software. // -// Intel License Agreement +// +// License Agreement // For Open Source Computer Vision Library // -// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2010, Willow Garage Inc., all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, @@ -22,7 +24,7 @@ // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // -// * The name of Intel Corporation may not be used to endorse or promote products +// * The name of the copyright holders may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and @@ -88,1157 +90,769 @@ \**********************************************************************************/ #include "precomp.hpp" +#include <limits> -typedef CvStatus (CV_STDCALL * CvColorCvtFunc0)( - const void* src, int srcstep, void* dst, int dststep, CvSize size ); - -typedef CvStatus (CV_STDCALL * CvColorCvtFunc1)( - const void* src, int srcstep, void* dst, int dststep, - CvSize size, int param0 ); - -typedef CvStatus (CV_STDCALL * CvColorCvtFunc2)( - const void* src, int srcstep, void* dst, int dststep, - CvSize size, int param0, int param1 ); - -typedef CvStatus (CV_STDCALL * CvColorCvtFunc3)( - const void* src, int srcstep, void* dst, int dststep, - CvSize size, int param0, int param1, int param2 ); - -/****************************************************************************************\ -* Various 3/4-channel to 3/4-channel RGB transformations * -\****************************************************************************************/ - -#define CV_IMPL_BGRX2BGR( flavor, arrtype ) \ -static CvStatus CV_STDCALL \ -icvBGRx2BGR_##flavor##_CnC3R( const arrtype* src, int srcstep, \ - arrtype* dst, int dststep, \ - CvSize size, int src_cn, int blue_idx ) \ -{ \ - int i; \ - \ - srcstep /= sizeof(src[0]); \ - dststep /= sizeof(dst[0]); \ - srcstep -= size.width*src_cn; \ - size.width *= 3; \ - \ - for( ; size.height--; src += srcstep, dst += dststep ) \ - { \ - for( i = 0; i < size.width; i += 3, src += src_cn ) \ - { \ - arrtype t0=src[blue_idx], t1=src[1], t2=src[blue_idx^2]; \ - dst[i] = t0; \ - dst[i+1] = t1; \ - dst[i+2] = t2; \ - } \ - } \ - \ - return CV_OK; \ -} +namespace cv +{ + +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<float> +{ + typedef float worktype_f; + static float max() { return 1.f; } + static float half() { return 0.5f; } +}; -#define CV_IMPL_BGR2BGRX( flavor, arrtype ) \ -static CvStatus CV_STDCALL \ -icvBGR2BGRx_##flavor##_C3C4R( const arrtype* src, int srcstep, \ - arrtype* dst, int dststep, \ - CvSize size, int blue_idx ) \ -{ \ - int i; \ - \ - srcstep /= sizeof(src[0]); \ - dststep /= sizeof(dst[0]); \ - srcstep -= size.width*3; \ - size.width *= 4; \ - \ - for( ; size.height--; src += srcstep, dst += dststep ) \ - { \ - for( i = 0; i < size.width; i += 4, src += 3 ) \ - { \ - arrtype t0=src[blue_idx], t1=src[1], t2=src[blue_idx^2]; \ - dst[i] = t0; \ - dst[i+1] = t1; \ - dst[i+2] = t2; \ - dst[i+3] = 0; \ - } \ - } \ - \ - return CV_OK; \ -} +/*template<> struct ColorChannel<double> +{ + typedef double worktype_f; + static double max() { return 1.; } + static double half() { return 0.5; } +};*/ + +///////////////////////////// Top-level template function //////////////////////////////// -#define CV_IMPL_BGRA2RGBA( flavor, arrtype ) \ -static CvStatus CV_STDCALL \ -icvBGRA2RGBA_##flavor##_C4R( const arrtype* src, int srcstep, \ - arrtype* dst, int dststep, CvSize size ) \ -{ \ - int i; \ - \ - srcstep /= sizeof(src[0]); \ - dststep /= sizeof(dst[0]); \ - size.width *= 4; \ - \ - for( ; size.height--; src += srcstep, dst += dststep ) \ - { \ - for( i = 0; i < size.width; i += 4 ) \ - { \ - arrtype t0 = src[2], t1 = src[1], t2 = src[0], t3 = src[3]; \ - dst[i] = t0; \ - dst[i+1] = t1; \ - dst[i+2] = t2; \ - dst[i+3] = t3; \ - } \ - } \ - \ - return CV_OK; \ +template<class Cvt> void CvtColorLoop(const Mat& srcmat, Mat& dstmat, const Cvt& cvt) +{ + typedef typename Cvt::channel_type _Tp; + Size sz = srcmat.size(); + const uchar* src = srcmat.data; + uchar* dst = dstmat.data; + size_t srcstep = srcmat.step, dststep = dstmat.step; + + if( srcmat.isContinuous() && dstmat.isContinuous() ) + { + sz.width *= sz.height; + sz.height = 1; + } + + for( ; sz.height--; src += srcstep, dst += dststep ) + cvt((const _Tp*)src, (_Tp*)dst, sz.width); } - - -CV_IMPL_BGRX2BGR( 8u, uchar ) -CV_IMPL_BGRX2BGR( 16u, ushort ) -CV_IMPL_BGRX2BGR( 32f, int ) -CV_IMPL_BGR2BGRX( 8u, uchar ) -CV_IMPL_BGR2BGRX( 16u, ushort ) -CV_IMPL_BGR2BGRX( 32f, int ) -CV_IMPL_BGRA2RGBA( 8u, uchar ) -CV_IMPL_BGRA2RGBA( 16u, ushort ) -CV_IMPL_BGRA2RGBA( 32f, int ) - - -/****************************************************************************************\ -* Transforming 16-bit (565 or 555) RGB to/from 24/32-bit (888[8]) RGB * -\****************************************************************************************/ - -static CvStatus CV_STDCALL -icvBGR5x52BGRx_8u_C2CnR( const uchar* src, int srcstep, - uchar* dst, int dststep, - CvSize size, int dst_cn, - int blue_idx, int green_bits ) + + +////////////////// Various 3/4-channel to 3/4-channel RGB transformations ///////////////// + +template<typename _Tp> struct RGB2RGB { - int i; - assert( green_bits == 5 || green_bits == 6 ); - dststep -= size.width*dst_cn; + typedef _Tp channel_type; + + RGB2RGB(int _srccn, int _dstcn, int _blueIdx) : srccn(_srccn), dstcn(_dstcn), blueIdx(_blueIdx) {} + void operator()(const _Tp* src, _Tp* dst, int n) const + { + int scn = srccn, dcn = dstcn, bidx = blueIdx; + if( dcn == 3 ) + { + n *= 3; + for( int i = 0; i < n; i += 3, src += scn ) + { + _Tp t0 = src[bidx], t1 = src[1], t2 = src[bidx ^ 2]; + dst[i] = t0; dst[i+1] = t1; dst[i+2] = t2; + } + } + else if( scn == 3 ) + { + n *= 3; + _Tp alpha = ColorChannel<_Tp>::max(); + for( int i = 0; i < n; i += 3, dst += 4 ) + { + _Tp t0 = src[i], t1 = src[i+1], t2 = src[i+2]; + dst[bidx] = t0; dst[1] = t1; dst[bidx^2] = t2; dst[3] = alpha; + } + } + else + { + n *= 4; + for( int i = 0; i < n; i += 4 ) + { + _Tp t0 = src[i], t1 = src[i+1], t2 = src[i+2], t3 = src[i+3]; + dst[i] = t2; dst[i+1] = t1; dst[i+2] = t0; dst[i+3] = t3; + } + } + } + + int srccn, dstcn, blueIdx; +}; + +/////////// Transforming 16-bit (565 or 555) RGB to/from 24/32-bit (888[8]) RGB ////////// - for( ; size.height--; src += srcstep, dst += dststep ) +struct RGB5x52RGB +{ + typedef uchar channel_type; + + RGB5x52RGB(int _dstcn, int _blueIdx, int _greenBits) + : dstcn(_dstcn), blueIdx(_blueIdx), greenBits(_greenBits) {} + + void operator()(const uchar* src, uchar* dst, int n) const { - if( green_bits == 6 ) - for( i = 0; i < size.width; i++, dst += dst_cn ) + int dcn = dstcn, bidx = blueIdx; + if( greenBits == 6 ) + for( int i = 0; i < n; i++, dst += dcn ) { unsigned t = ((const ushort*)src)[i]; - dst[blue_idx] = (uchar)(t << 3); + dst[bidx] = (uchar)(t << 3); dst[1] = (uchar)((t >> 3) & ~3); - dst[blue_idx ^ 2] = (uchar)((t >> 8) & ~7); - if( dst_cn == 4 ) - dst[3] = 0; + dst[bidx ^ 2] = (uchar)((t >> 8) & ~7); + if( dcn == 4 ) + dst[3] = 255; } else - for( i = 0; i < size.width; i++, dst += dst_cn ) + for( int i = 0; i < n; i++, dst += dcn ) { unsigned t = ((const ushort*)src)[i]; - dst[blue_idx] = (uchar)(t << 3); + dst[bidx] = (uchar)(t << 3); dst[1] = (uchar)((t >> 2) & ~7); - dst[blue_idx ^ 2] = (uchar)((t >> 7) & ~7); - if( dst_cn == 4 ) - dst[3] = 0; + dst[bidx ^ 2] = (uchar)((t >> 7) & ~7); + if( dcn == 4 ) + dst[3] = t & 0x8000 ? 255 : 0; } } + + int dstcn, blueIdx, greenBits; +}; - return CV_OK; -} - - -static CvStatus CV_STDCALL -icvBGRx2BGR5x5_8u_CnC2R( const uchar* src, int srcstep, - uchar* dst, int dststep, - CvSize size, int src_cn, - int blue_idx, int green_bits ) + +struct RGB2RGB5x5 { - int i; - srcstep -= size.width*src_cn; - - for( ; size.height--; src += srcstep, dst += dststep ) + typedef uchar channel_type; + + RGB2RGB5x5(int _srccn, int _blueIdx, int _greenBits) + : srccn(_srccn), blueIdx(_blueIdx), greenBits(_greenBits) {} + + void operator()(const uchar* src, uchar* dst, int n) const { - if( green_bits == 6 ) - for( i = 0; i < size.width; i++, src += src_cn ) + int scn = srccn, bidx = blueIdx; + if( greenBits == 6 ) + for( int i = 0; i < n; i++, src += scn ) { - int t = (src[blue_idx] >> 3)|((src[1]&~3) << 3)|((src[blue_idx^2]&~7) << 8); - ((ushort*)dst)[i] = (ushort)t; + ((ushort*)dst)[i] = (ushort)((src[bidx] >> 3)|((src[1]&~3) << 3)|((src[bidx^2]&~7) << 8)); + } + else if( scn == 3 ) + for( int i = 0; i < n; i++, src += 3 ) + { + ((ushort*)dst)[i] = (ushort)((src[bidx] >> 3)|((src[1]&~7) << 2)|((src[bidx^2]&~7) << 7)); } else - for( i = 0; i < size.width; i++, src += src_cn ) + for( int i = 0; i < n; i++, src += 4 ) { - int t = (src[blue_idx] >> 3)|((src[1]&~7) << 2)|((src[blue_idx^2]&~7) << 7); - ((ushort*)dst)[i] = (ushort)t; + ((ushort*)dst)[i] = (ushort)((src[bidx] >> 3)|((src[1]&~7) << 2)| + ((src[bidx^2]&~7) << 7)|(src[3] ? 0x8000 : 0)); } } + + int srccn, blueIdx, greenBits; +}; + +///////////////////////////////// Color to/from Grayscale //////////////////////////////// - return CV_OK; -} - - - -/////////////////////////// IPP Color Conversion Functions ////////////////////////////// - -#define CV_IMPL_BGRx2ABC_IPP( flavor, arrtype ) \ -static CvStatus CV_STDCALL \ -icvBGRx2ABC_IPP_##flavor##_CnC3R( const arrtype* src, int srcstep, \ - arrtype* dst, int dststep, CvSize size, int src_cn, \ - int blue_idx, CvColorCvtFunc0 ipp_func ) \ -{ \ - int block_size = MIN(1 << 14, size.width); \ - arrtype* buffer; \ - int i, di, k; \ - int do_copy = src_cn > 3 || blue_idx != 2 || src == dst; \ - CvStatus status = CV_OK; \ - \ - if( !do_copy ) \ - return ipp_func( src, srcstep, dst, dststep, size ); \ - \ - srcstep /= sizeof(src[0]); \ - dststep /= sizeof(dst[0]); \ - \ - buffer = (arrtype*)cvStackAlloc( block_size*3*sizeof(buffer[0]) ); \ - srcstep -= size.width*src_cn; \ - \ - for( ; size.height--; src += srcstep, dst += dststep ) \ - { \ - for( i = 0; i < size.width; i += block_size ) \ - { \ - arrtype* dst1 = dst + i*3; \ - di = MIN(block_size, size.width - i); \ - \ - for( k = 0; k < di*3; k += 3, src += src_cn ) \ - { \ - arrtype b = src[blue_idx]; \ - arrtype g = src[1]; \ - arrtype r = src[blue_idx^2]; \ - buffer[k] = r; \ - buffer[k+1] = g; \ - buffer[k+2] = b; \ - } \ - \ - status = ipp_func( buffer, CV_STUB_STEP, \ - dst1, CV_STUB_STEP, cvSize(di,1) ); \ - if( status < 0 ) \ - return status; \ - } \ - } \ - \ - return CV_OK; \ -} - -#ifdef HAVE_IPP -static CvStatus CV_STDCALL -icvBGRx2ABC_IPP_8u_CnC3R( const uchar* src, int srcstep, - uchar* dst, int dststep, CvSize size, int src_cn, - int blue_idx, CvColorCvtFunc0 ipp_func ) +template<typename _Tp> +struct Gray2RGB { - int block_size = MIN(1 << 14, size.width); - uchar* buffer; - int i, di, k; - int do_copy = src_cn > 3 || blue_idx != 2 || src == dst; - CvStatus status = CV_OK; - - if( !do_copy ) - return ipp_func( src, srcstep, dst, dststep, size ); - - srcstep /= sizeof(src[0]); - dststep /= sizeof(dst[0]); - - buffer = (uchar*)cvStackAlloc( block_size*3*sizeof(buffer[0]) ); - srcstep -= size.width*src_cn; - - for( ; size.height--; src += srcstep, dst += dststep ) + typedef _Tp channel_type; + + Gray2RGB(int _dstcn) : dstcn(_dstcn) {} + void operator()(const _Tp* src, _Tp* dst, int n) const { - for( i = 0; i < size.width; i += block_size ) + if( dstcn == 3 ) + for( int i = 0; i < n; i++, dst += 3 ) + { + dst[0] = dst[1] = dst[2] = src[i]; + } + else { - uchar* dst1 = dst + i*3; - di = MIN(block_size, size.width - i); - - for( k = 0; k < di*3; k += 3, src += src_cn ) + _Tp alpha = ColorChannel<_Tp>::max(); + for( int i = 0; i < n; i++, dst += 4 ) { - uchar b = src[blue_idx]; - uchar g = src[1]; - uchar r = src[blue_idx^2]; - buffer[k] = r; - buffer[k+1] = g; - buffer[k+2] = b; + dst[0] = dst[1] = dst[2] = src[i]; + dst[3] = alpha; } - - status = ipp_func( buffer, CV_STUB_STEP, - dst1, CV_STUB_STEP, cvSize(di,1) ); - if( status < 0 ) - return status; } } + + int dstcn; +}; + - return CV_OK; -} - -//CV_IMPL_BGRx2ABC_IPP( 8u, uchar ) -//CV_IMPL_BGRx2ABC_IPP( 16u, ushort ) -CV_IMPL_BGRx2ABC_IPP( 32f, float ) - -#define CV_IMPL_ABC2BGRx_IPP( flavor, arrtype ) \ -static CvStatus CV_STDCALL \ -icvABC2BGRx_IPP_##flavor##_C3CnR( const arrtype* src, int srcstep, \ - arrtype* dst, int dststep, CvSize size, int dst_cn, \ - int blue_idx, CvColorCvtFunc0 ipp_func ) \ -{ \ - int block_size = MIN(1 << 10, size.width); \ - arrtype* buffer; \ - int i, di, k; \ - int do_copy = dst_cn > 3 || blue_idx != 2 || src == dst; \ - CvStatus status = CV_OK; \ - \ - if( !do_copy ) \ - return ipp_func( src, srcstep, dst, dststep, size ); \ - \ - srcstep /= sizeof(src[0]); \ - dststep /= sizeof(dst[0]); \ - \ - buffer = (arrtype*)cvStackAlloc( block_size*3*sizeof(buffer[0]) ); \ - dststep -= size.width*dst_cn; \ - \ - for( ; size.height--; src += srcstep, dst += dststep ) \ - { \ - for( i = 0; i < size.width; i += block_size ) \ - { \ - const arrtype* src1 = src + i*3; \ - di = MIN(block_size, size.width - i); \ - \ - status = ipp_func( src1, CV_STUB_STEP, \ - buffer, CV_STUB_STEP, cvSize(di,1) ); \ - if( status < 0 ) \ - return status; \ - \ - for( k = 0; k < di*3; k += 3, dst += dst_cn ) \ - { \ - arrtype r = buffer[k]; \ - arrtype g = buffer[k+1]; \ - arrtype b = buffer[k+2]; \ - dst[blue_idx] = b; \ - dst[1] = g; \ - dst[blue_idx^2] = r; \ - if( dst_cn == 4 ) \ - dst[3] = 0; \ - } \ - } \ - } \ - \ - return CV_OK; \ -} - -CV_IMPL_ABC2BGRx_IPP( 8u, uchar ) -//CV_IMPL_ABC2BGRx_IPP( 16u, ushort ) -CV_IMPL_ABC2BGRx_IPP( 32f, float ) -#endif - -///////////////////////////////////////////////////////////////////////////////////////// - - -/****************************************************************************************\ -* Color to/from Grayscale * -\****************************************************************************************/ - -#define fix(x,n) (int)((x)*(1 << (n)) + 0.5) -#define descale CV_DESCALE - -#define cscGr_32f 0.299f -#define cscGg_32f 0.587f -#define cscGb_32f 0.114f - -/* BGR/RGB -> Gray */ -#define csc_shift 14 -#define cscGr fix(cscGr_32f,csc_shift) -#define cscGg fix(cscGg_32f,csc_shift) -#define cscGb /*fix(cscGb_32f,csc_shift)*/ ((1 << csc_shift) - cscGr - cscGg) - -#define CV_IMPL_GRAY2BGRX( flavor, arrtype ) \ -static CvStatus CV_STDCALL \ -icvGray2BGRx_##flavor##_C1CnR( const arrtype* src, int srcstep, \ - arrtype* dst, int dststep, CvSize size, \ - int dst_cn ) \ -{ \ - int i; \ - srcstep /= sizeof(src[0]); \ - dststep /= sizeof(src[0]); \ - dststep -= size.width*dst_cn; \ - \ - for( ; size.height--; src += srcstep, dst += dststep ) \ - { \ - if( dst_cn == 3 ) \ - for( i = 0; i < size.width; i++, dst += 3 ) \ - dst[0] = dst[1] = dst[2] = src[i]; \ - else \ - for( i = 0; i < size.width; i++, dst += 4 ) \ - { \ - dst[0] = dst[1] = dst[2] = src[i]; \ - dst[3] = 0; \ - } \ - } \ - \ - return CV_OK; \ -} - - -CV_IMPL_GRAY2BGRX( 8u, uchar ) -CV_IMPL_GRAY2BGRX( 16u, ushort ) -CV_IMPL_GRAY2BGRX( 32f, float ) - - -static CvStatus CV_STDCALL -icvBGR5x52Gray_8u_C2C1R( const uchar* src, int srcstep, - uchar* dst, int dststep, - CvSize size, int green_bits ) +struct Gray2RGB5x5 { - int i; - assert( green_bits == 5 || green_bits == 6 ); - - for( ; size.height--; src += srcstep, dst += dststep ) + typedef uchar channel_type; + + Gray2RGB5x5(int _greenBits) : greenBits(_greenBits) {} + void operator()(const uchar* src, uchar* dst, int n) const { - if( green_bits == 6 ) - for( i = 0; i < size.width; i++ ) + if( greenBits == 6 ) + for( int i = 0; i < n; i++ ) { - int t = ((ushort*)src)[i]; - t = ((t << 3) & 0xf8)*cscGb + ((t >> 3) & 0xfc)*cscGg + - ((t >> 8) & 0xf8)*cscGr; - dst[i] = (uchar)CV_DESCALE(t,csc_shift); + int t = src[i]; + ((ushort*)dst)[i] = (ushort)((t >> 3)|((t & ~3) << 3)|((t & ~7) << 8)); } else - for( i = 0; i < size.width; i++ ) + for( int i = 0; i < n; i++ ) { - int t = ((ushort*)src)[i]; - t = ((t << 3) & 0xf8)*cscGb + ((t >> 2) & 0xf8)*cscGg + - ((t >> 7) & 0xf8)*cscGr; - dst[i] = (uchar)CV_DESCALE(t,csc_shift); + int t = src[i] >> 3; + ((ushort*)dst)[i] = (ushort)(t|(t << 5)|(t << 10)); } } - - return CV_OK; -} + int greenBits; +}; -static CvStatus CV_STDCALL -icvGray2BGR5x5_8u_C1C2R( const uchar* src, int srcstep, - uchar* dst, int dststep, - CvSize size, int green_bits ) +#undef R2Y +#undef G2Y +#undef B2Y + +enum { - int i; - assert( green_bits == 5 || green_bits == 6 ); + yuv_shift = 14, + xyz_shift = 12, + R2Y = 4899, + G2Y = 9617, + B2Y = 1868, + BLOCK_SIZE = 256 +}; + - for( ; size.height--; src += srcstep, dst += dststep ) +struct RGB5x52Gray +{ + typedef uchar channel_type; + + RGB5x52Gray(int _greenBits) : greenBits(_greenBits) {} + void operator()(const uchar* src, uchar* dst, int n) const { - if( green_bits == 6 ) - for( i = 0; i < size.width; i++ ) + if( greenBits == 6 ) + for( int i = 0; i < n; i++ ) { - int t = src[i]; - ((ushort*)dst)[i] = (ushort)((t >> 3)|((t & ~3) << 3)|((t & ~7) << 8)); + int t = ((ushort*)src)[i]; + dst[i] = (uchar)CV_DESCALE(((t << 3) & 0xf8)*B2Y + + ((t >> 3) & 0xfc)*G2Y + + ((t >> 8) & 0xf8)*R2Y, yuv_shift); } else - for( i = 0; i < size.width; i++ ) + for( int i = 0; i < n; i++ ) { - int t = src[i] >> 3; - ((ushort*)dst)[i] = (ushort)(t|(t << 5)|(t << 10)); + int t = ((ushort*)src)[i]; + dst[i] = (uchar)CV_DESCALE(((t << 3) & 0xf8)*B2Y + + ((t >> 2) & 0xf8)*G2Y + + ((t >> 7) & 0xf8)*R2Y, yuv_shift); } } - - return CV_OK; -} + int greenBits; +}; -static CvStatus CV_STDCALL -icvBGRx2Gray_8u_CnC1R( const uchar* src, int srcstep, - uchar* dst, int dststep, CvSize size, - int src_cn, int blue_idx ) +template<typename _Tp> struct RGB2Gray { - int i; - srcstep -= size.width*src_cn; - - if( size.width*size.height >= 1024 ) + typedef _Tp channel_type; + + RGB2Gray(int _srccn, int blueIdx, const float* _coeffs) : srccn(_srccn) { - int* tab = (int*)cvStackAlloc( 256*3*sizeof(tab[0]) ); - int r = 0, g = 0, b = (1 << (csc_shift-1)); + 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<uchar> +{ + typedef uchar channel_type; - for( i = 0; i < 256; i++ ) + RGB2Gray<uchar>(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; - g += cscGg; - if( !blue_idx ) - b += cscGb, r += cscGr; - else - b += cscGr, r += cscGb; - } - - for( ; size.height--; src += srcstep, dst += dststep ) - { - for( i = 0; i < size.width; i++, src += src_cn ) - { - int t0 = tab[src[0]] + tab[src[1] + 256] + tab[src[2] + 512]; - dst[i] = (uchar)(t0 >> csc_shift); - } } } - else + void operator()(const uchar* src, uchar* dst, int n) const { - for( ; size.height--; src += srcstep, dst += dststep ) - { - for( i = 0; i < size.width; i++, src += src_cn ) - { - int t0 = src[blue_idx]*cscGb + src[1]*cscGg + src[blue_idx^2]*cscGr; - dst[i] = (uchar)CV_DESCALE(t0, csc_shift); - } - } + 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); } - return CV_OK; -} - + int srccn, blueIdx; + int tab[256*3]; +}; -static CvStatus CV_STDCALL -icvBGRx2Gray_16u_CnC1R( const ushort* src, int srcstep, - ushort* dst, int dststep, CvSize size, - int src_cn, int blue_idx ) + +template<> struct RGB2Gray<ushort> { - int i; - int cb = cscGb, cr = cscGr; - srcstep /= sizeof(src[0]); - dststep /= sizeof(dst[0]); - srcstep -= size.width*src_cn; - - if( blue_idx ) - cb = cscGr, cr = cscGb; - - for( ; size.height--; src += srcstep, dst += dststep ) - for( i = 0; i < size.width; i++, src += src_cn ) - dst[i] = (ushort)CV_DESCALE((unsigned)(src[0]*cb + - src[1]*cscGg + src[2]*cr), csc_shift); - - return CV_OK; -} + typedef ushort channel_type; + + RGB2Gray<ushort>(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)CV_DESCALE((unsigned)(src[0]*cb + src[1]*cg + src[2]*cr), yuv_shift); + } + int srccn; + int coeffs[3]; +}; + +///////////////////////////////////// RGB <-> YCrCb ////////////////////////////////////// -static CvStatus CV_STDCALL -icvBGRx2Gray_32f_CnC1R( const float* src, int srcstep, - float* dst, int dststep, CvSize size, - int src_cn, int blue_idx ) +template<typename _Tp> struct RGB2YCrCb_f { - int i; - float cb = cscGb_32f, cr = cscGr_32f; - if( blue_idx ) - cb = cscGr_32f, cr = cscGb_32f; - - srcstep /= sizeof(src[0]); - dststep /= sizeof(dst[0]); - srcstep -= size.width*src_cn; - for( ; size.height--; src += srcstep, dst += dststep ) - for( i = 0; i < size.width; i++, src += src_cn ) - dst[i] = src[0]*cb + src[1]*cscGg_32f + src[2]*cr; - - return CV_OK; -} - - -/****************************************************************************************\ -* RGB <-> YCrCb * -\****************************************************************************************/ - -/* BGR/RGB -> YCrCb */ -#define yuvYr_32f cscGr_32f -#define yuvYg_32f cscGg_32f -#define yuvYb_32f cscGb_32f -#define yuvCr_32f 0.713f -#define yuvCb_32f 0.564f - -#define yuv_shift 14 -#define yuvYr fix(yuvYr_32f,yuv_shift) -#define yuvYg fix(yuvYg_32f,yuv_shift) -#define yuvYb fix(yuvYb_32f,yuv_shift) -#define yuvCr fix(yuvCr_32f,yuv_shift) -#define yuvCb fix(yuvCb_32f,yuv_shift) - -#define yuv_descale(x) CV_DESCALE((x), yuv_shift) -#define yuv_prescale(x) ((x) << yuv_shift) - -#define yuvRCr_32f 1.403f -#define yuvGCr_32f (-0.714f) -#define yuvGCb_32f (-0.344f) -#define yuvBCb_32f 1.773f - -#define yuvRCr fix(yuvRCr_32f,yuv_shift) -#define yuvGCr (-fix(-yuvGCr_32f,yuv_shift)) -#define yuvGCb (-fix(-yuvGCb_32f,yuv_shift)) -#define yuvBCb fix(yuvBCb_32f,yuv_shift) - -#define CV_IMPL_BGRx2YCrCb( flavor, arrtype, worktype, scale_macro, cast_macro, \ - YUV_YB, YUV_YG, YUV_YR, YUV_CR, YUV_CB, YUV_Cx_BIAS ) \ -static CvStatus CV_STDCALL \ -icvBGRx2YCrCb_##flavor##_CnC3R( const arrtype* src, int srcstep, \ - arrtype* dst, int dststep, CvSize size, int src_cn, int blue_idx ) \ -{ \ - int i; \ - srcstep /= sizeof(src[0]); \ - dststep /= sizeof(src[0]); \ - srcstep -= size.width*src_cn; \ - size.width *= 3; \ - \ - for( ; size.height--; src += srcstep, dst += dststep ) \ - { \ - for( i = 0; i < size.width; i += 3, src += src_cn ) \ - { \ - worktype b = src[blue_idx], r = src[2^blue_idx], y; \ - y = scale_macro(b*YUV_YB + src[1]*YUV_YG + r*YUV_YR); \ - r = scale_macro((r - y)*YUV_CR) + YUV_Cx_BIAS; \ - b = scale_macro((b - y)*YUV_CB) + YUV_Cx_BIAS; \ - dst[i] = cast_macro(y); \ - dst[i+1] = cast_macro(r); \ - dst[i+2] = cast_macro(b); \ - } \ - } \ - \ - return CV_OK; \ -} - - -CV_IMPL_BGRx2YCrCb( 8u, uchar, int, yuv_descale, CV_CAST_8U, - yuvYb, yuvYg, yuvYr, yuvCr, yuvCb, 128 ) - -CV_IMPL_BGRx2YCrCb( 16u, ushort, int, yuv_descale, CV_CAST_16U, - yuvYb, yuvYg, yuvYr, yuvCr, yuvCb, 32768 ) - -CV_IMPL_BGRx2YCrCb( 32f, float, float, CV_NOP, CV_NOP, - yuvYb_32f, yuvYg_32f, yuvYr_32f, yuvCr_32f, yuvCb_32f, 0.5f ) - - -#define CV_IMPL_YCrCb2BGRx( flavor, arrtype, worktype, prescale_macro, \ - scale_macro, cast_macro, YUV_BCb, YUV_GCr, YUV_GCb, YUV_RCr, YUV_Cx_BIAS)\ -static CvStatus CV_STDCALL \ -icvYCrCb2BGRx_##flavor##_C3CnR( const arrtype* src, int srcstep, \ - arrtype* dst, int dststep, CvSize size, \ - int dst_cn, int blue_idx ) \ -{ \ - int i; \ - srcstep /= sizeof(src[0]); \ - dststep /= sizeof(src[0]); \ - dststep -= size.width*dst_cn; \ - size.width *= 3; \ - \ - for( ; size.height--; src += srcstep, dst += dststep ) \ - { \ - for( i = 0; i < size.width; i += 3, dst += dst_cn ) \ - { \ - worktype Y = prescale_macro(src[i]), \ - Cr = src[i+1] - YUV_Cx_BIAS, \ - Cb = src[i+2] - YUV_Cx_BIAS; \ - worktype b, g, r; \ - b = scale_macro( Y + YUV_BCb*Cb ); \ - g = scale_macro( Y + YUV_GCr*Cr + YUV_GCb*Cb ); \ - r = scale_macro( Y + YUV_RCr*Cr ); \ - \ - dst[blue_idx] = cast_macro(b); \ - dst[1] = cast_macro(g); \ - dst[blue_idx^2] = cast_macro(r); \ - if( dst_cn == 4 ) \ - dst[3] = 0; \ - } \ - } \ - \ - return CV_OK; \ -} - - -CV_IMPL_YCrCb2BGRx( 8u, uchar, int, yuv_prescale, yuv_descale, CV_CAST_8U, - yuvBCb, yuvGCr, yuvGCb, yuvRCr, 128 ) - -CV_IMPL_YCrCb2BGRx( 16u, ushort, int, yuv_prescale, yuv_descale, CV_CAST_16U, - yuvBCb, yuvGCr, yuvGCb, yuvRCr, 32768 ) - -CV_IMPL_YCrCb2BGRx( 32f, float, float, CV_NOP, CV_NOP, CV_NOP, - yuvBCb_32f, yuvGCr_32f, yuvGCb_32f, yuvRCr_32f, 0.5f ) - - -/****************************************************************************************\ -* RGB <-> XYZ * -\****************************************************************************************/ - -#define xyzXr_32f 0.412453f -#define xyzXg_32f 0.357580f -#define xyzXb_32f 0.180423f - -#define xyzYr_32f 0.212671f -#define xyzYg_32f 0.715160f -#define xyzYb_32f 0.072169f - -#define xyzZr_32f 0.019334f -#define xyzZg_32f 0.119193f -#define xyzZb_32f 0.950227f - -#define xyzRx_32f 3.240479f -#define xyzRy_32f (-1.53715f) -#define xyzRz_32f (-0.498535f) - -#define xyzGx_32f (-0.969256f) -#define xyzGy_32f 1.875991f -#define xyzGz_32f 0.041556f - -#define xyzBx_32f 0.055648f -#define xyzBy_32f (-0.204043f) -#define xyzBz_32f 1.057311f - -#define xyz_shift 10 -#define xyzXr_32s fix(xyzXr_32f, xyz_shift ) -#define xyzXg_32s fix(xyzXg_32f, xyz_shift ) -#define xyzXb_32s fix(xyzXb_32f, xyz_shift ) - -#define xyzYr_32s fix(xyzYr_32f, xyz_shift ) -#define xyzYg_32s fix(xyzYg_32f, xyz_shift ) -#define xyzYb_32s fix(xyzYb_32f, xyz_shift ) - -#define xyzZr_32s fix(xyzZr_32f, xyz_shift ) -#define xyzZg_32s fix(xyzZg_32f, xyz_shift ) -#define xyzZb_32s fix(xyzZb_32f, xyz_shift ) - -#define xyzRx_32s fix(3.240479f, xyz_shift ) -#define xyzRy_32s -fix(1.53715f, xyz_shift ) -#define xyzRz_32s -fix(0.498535f, xyz_shift ) - -#define xyzGx_32s -fix(0.969256f, xyz_shift ) -#define xyzGy_32s fix(1.875991f, xyz_shift ) -#define xyzGz_32s fix(0.041556f, xyz_shift ) - -#define xyzBx_32s fix(0.055648f, xyz_shift ) -#define xyzBy_32s -fix(0.204043f, xyz_shift ) -#define xyzBz_32s fix(1.057311f, xyz_shift ) - -#define xyz_descale(x) CV_DESCALE((x),xyz_shift) - -#define CV_IMPL_BGRx2XYZ( flavor, arrtype, worktype, \ - scale_macro, cast_macro, suffix ) \ -static CvStatus CV_STDCALL \ -icvBGRx2XYZ_##flavor##_CnC3R( const arrtype* src, int srcstep, \ - arrtype* dst, int dststep, CvSize size, \ - int src_cn, int blue_idx ) \ -{ \ - int i; \ - worktype t, matrix[] = \ - { \ - xyzXb##suffix, xyzXg##suffix, xyzXr##suffix, \ - xyzYb##suffix, xyzYg##suffix, xyzYr##suffix, \ - xyzZb##suffix, xyzZg##suffix, xyzZr##suffix \ - }; \ - \ - srcstep /= sizeof(src[0]); \ - dststep /= sizeof(dst[0]); \ - srcstep -= size.width*src_cn; \ - size.width *= 3; \ - \ - if( blue_idx ) \ - { \ - CV_SWAP( matrix[0], matrix[2], t ); \ - CV_SWAP( matrix[3], matrix[5], t ); \ - CV_SWAP( matrix[6], matrix[8], t ); \ - } \ - \ - for( ; size.height--; src += srcstep, dst += dststep ) \ - { \ - for( i = 0; i < size.width; i += 3, src += src_cn ) \ - { \ - worktype x = scale_macro(src[0]*matrix[0] + \ - src[1]*matrix[1] + src[2]*matrix[2]); \ - worktype y = scale_macro(src[0]*matrix[3] + \ - src[1]*matrix[4] + src[2]*matrix[5]); \ - worktype z = scale_macro(src[0]*matrix[6] + \ - src[1]*matrix[7] + src[2]*matrix[8]); \ - \ - dst[i] = (arrtype)(x); \ - dst[i+1] = (arrtype)(y); \ - dst[i+2] = cast_macro(z); /*sum of weights for z > 1*/ \ - } \ - } \ - \ - return CV_OK; \ -} - - -CV_IMPL_BGRx2XYZ( 8u, uchar, int, xyz_descale, CV_CAST_8U, _32s ) -CV_IMPL_BGRx2XYZ( 16u, ushort, int, xyz_descale, CV_CAST_16U, _32s ) -CV_IMPL_BGRx2XYZ( 32f, float, float, CV_NOP, CV_NOP, _32f ) - - -#define CV_IMPL_XYZ2BGRx( flavor, arrtype, worktype, scale_macro, \ - cast_macro, suffix ) \ -static CvStatus CV_STDCALL \ -icvXYZ2BGRx_##flavor##_C3CnR( const arrtype* src, int srcstep, \ - arrtype* dst, int dststep, CvSize size, \ - int dst_cn, int blue_idx ) \ -{ \ - int i; \ - worktype t, matrix[] = \ - { \ - xyzBx##suffix, xyzBy##suffix, xyzBz##suffix, \ - xyzGx##suffix, xyzGy##suffix, xyzGz##suffix, \ - xyzRx##suffix, xyzRy##suffix, xyzRz##suffix \ - }; \ - \ - srcstep /= sizeof(src[0]); \ - dststep /= sizeof(dst[0]); \ - dststep -= size.width*dst_cn; \ - size.width *= 3; \ - \ - if( blue_idx ) \ - { \ - CV_SWAP( matrix[0], matrix[6], t ); \ - CV_SWAP( matrix[1], matrix[7], t ); \ - CV_SWAP( matrix[2], matrix[8], t ); \ - } \ - \ - for( ; size.height--; src += srcstep, dst += dststep ) \ - { \ - for( i = 0; i < size.width; i += 3, dst += dst_cn ) \ - { \ - worktype b = scale_macro(src[i]*matrix[0] + \ - src[i+1]*matrix[1] + src[i+2]*matrix[2]); \ - worktype g = scale_macro(src[i]*matrix[3] + \ - src[i+1]*matrix[4] + src[i+2]*matrix[5]); \ - worktype r = scale_macro(src[i]*matrix[6] + \ - src[i+1]*matrix[7] + src[i+2]*matrix[8]); \ - \ - dst[0] = cast_macro(b); \ - dst[1] = cast_macro(g); \ - dst[2] = cast_macro(r); \ - \ - if( dst_cn == 4 ) \ - dst[3] = 0; \ - } \ - } \ - \ - return CV_OK; \ -} - -CV_IMPL_XYZ2BGRx( 8u, uchar, int, xyz_descale, CV_CAST_8U, _32s ) -CV_IMPL_XYZ2BGRx( 16u, ushort, int, xyz_descale, CV_CAST_16U, _32s ) -CV_IMPL_XYZ2BGRx( 32f, float, float, CV_NOP, CV_NOP, _32f ) - + 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]; +}; -/****************************************************************************************\ -* Non-linear Color Space Transformations * -\****************************************************************************************/ -#ifndef HAVE_IPP -// driver color space conversion function for 8u arrays that uses 32f function -// with appropriate pre- and post-scaling. -static CvStatus CV_STDCALL -icvABC2BGRx_8u_C3CnR( const uchar* src, int srcstep, uchar* dst, int dststep, - CvSize size, int dst_cn, int blue_idx, CvColorCvtFunc2 cvtfunc_32f, - const float* pre_coeffs, int postscale ) +template<typename _Tp> struct RGB2YCrCb_i { - int block_size = MIN(1 << 8, size.width); - float* buffer = (float*)cvStackAlloc( block_size*3*sizeof(buffer[0]) ); - int i, di, k; - CvStatus status = CV_OK; + 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 = CV_DESCALE(src[0]*C0 + src[1]*C1 + src[2]*C2, yuv_shift); + int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + delta, yuv_shift); + int Cb = CV_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]; +}; - dststep -= size.width*dst_cn; - for( ; size.height--; src += srcstep, dst += dststep ) +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 { - for( i = 0; i < size.width; i += block_size ) + 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) { - const uchar* src1 = src + i*3; - di = MIN(block_size, size.width - i); + _Tp Y = src[i]; + _Tp Cr = src[i+1]; + _Tp Cb = src[i+2]; - for( k = 0; k < di*3; k += 3 ) - { - float a = CV_8TO32F(src1[k])*pre_coeffs[0] + pre_coeffs[1]; - float b = CV_8TO32F(src1[k+1])*pre_coeffs[2] + pre_coeffs[3]; - float c = CV_8TO32F(src1[k+2])*pre_coeffs[4] + pre_coeffs[5]; - buffer[k] = a; - buffer[k+1] = b; - buffer[k+2] = c; - } - - status = cvtfunc_32f( buffer, 0, buffer, 0, cvSize(di,1), 3, blue_idx ); - if( status < 0 ) - return status; + _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); - if( postscale ) - { - for( k = 0; k < di*3; k += 3, dst += dst_cn ) - { - int b = cvRound(buffer[k]*255.); - int g = cvRound(buffer[k+1]*255.); - int r = cvRound(buffer[k+2]*255.); - - dst[0] = CV_CAST_8U(b); - dst[1] = CV_CAST_8U(g); - dst[2] = CV_CAST_8U(r); - if( dst_cn == 4 ) - dst[3] = 0; - } - } - else - { - for( k = 0; k < di*3; k += 3, dst += dst_cn ) - { - int b = cvRound(buffer[k]); - int g = cvRound(buffer[k+1]); - int r = cvRound(buffer[k+2]); - - dst[0] = CV_CAST_8U(b); - dst[1] = CV_CAST_8U(g); - dst[2] = CV_CAST_8U(r); - if( dst_cn == 4 ) - dst[3] = 0; - } - } + dst[bidx] = b; dst[1] = g; dst[bidx^2] = r; + if( dcn == 4 ) + dst[3] = alpha; } } - - return CV_OK; -} + int dstcn, blueIdx; + float coeffs[4]; +}; -// driver color space conversion function for 8u arrays that uses 32f function -// with appropriate pre- and post-scaling. -static CvStatus CV_STDCALL -icvBGRx2ABC_8u_CnC3R( const uchar* src, int srcstep, uchar* dst, int dststep, - CvSize size, int src_cn, int blue_idx, CvColorCvtFunc2 cvtfunc_32f, - int prescale, const float* post_coeffs ) +template<typename _Tp> struct YCrCb2RGB_i { - int block_size = MIN(1 << 8, size.width); - float* buffer = (float*)cvStackAlloc( block_size*3*sizeof(buffer[0]) ); - int i, di, k; - CvStatus status = CV_OK; - - srcstep -= size.width*src_cn; - - for( ; size.height--; src += srcstep, dst += dststep ) + typedef _Tp channel_type; + + YCrCb2RGB_i(int _dstcn, int _blueIdx, const int* _coeffs) + : dstcn(_dstcn), blueIdx(_blueIdx) { - for( i = 0; i < size.width; i += block_size ) + 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) { - uchar* dst1 = dst + i*3; - di = MIN(block_size, size.width - i); - - if( prescale ) - { - for( k = 0; k < di*3; k += 3, src += src_cn ) - { - float b = CV_8TO32F(src[0])*0.0039215686274509803f; - float g = CV_8TO32F(src[1])*0.0039215686274509803f; - float r = CV_8TO32F(src[2])*0.0039215686274509803f; - - buffer[k] = b; - buffer[k+1] = g; - buffer[k+2] = r; - } - } - else - { - for( k = 0; k < di*3; k += 3, src += src_cn ) - { - float b = CV_8TO32F(src[0]); - float g = CV_8TO32F(src[1]); - float r = CV_8TO32F(src[2]); - - buffer[k] = b; - buffer[k+1] = g; - buffer[k+2] = r; - } - } + _Tp Y = src[i]; + _Tp Cr = src[i+1]; + _Tp Cb = src[i+2]; - status = cvtfunc_32f( buffer, 0, buffer, 0, cvSize(di,1), 3, blue_idx ); - if( status < 0 ) - return status; - - for( k = 0; k < di*3; k += 3 ) - { - int a = cvRound( buffer[k]*post_coeffs[0] + post_coeffs[1] ); - int b = cvRound( buffer[k+1]*post_coeffs[2] + post_coeffs[3] ); - int c = cvRound( buffer[k+2]*post_coeffs[4] + post_coeffs[5] ); - dst1[k] = CV_CAST_8U(a); - dst1[k+1] = CV_CAST_8U(b); - dst1[k+2] = CV_CAST_8U(c); - } + int b = Y + CV_DESCALE((Cb - delta)*C3, yuv_shift); + int g = Y + CV_DESCALE((Cb - delta)*C2 + (Cr - delta)*C1, yuv_shift); + int r = Y + CV_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]; +}; - return CV_OK; -} -#endif - -/****************************************************************************************\ -* RGB <-> HSV * -\****************************************************************************************/ + +////////////////////////////////////// RGB <-> XYZ /////////////////////////////////////// -static const uchar icvHue255To180[] = +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[] = { - 0, 1, 1, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11, - 11, 12, 13, 13, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, - 23, 23, 24, 25, 25, 26, 27, 28, 28, 29, 30, 30, 31, 32, 32, 33, - 34, 35, 35, 36, 37, 37, 38, 39, 40, 40, 41, 42, 42, 43, 44, 44, - 45, 46, 47, 47, 48, 49, 49, 50, 51, 52, 52, 53, 54, 54, 55, 56, - 56, 57, 58, 59, 59, 60, 61, 61, 62, 63, 64, 64, 65, 66, 66, 67, - 68, 68, 69, 70, 71, 71, 72, 73, 73, 74, 75, 76, 76, 77, 78, 78, - 79, 80, 80, 81, 82, 83, 83, 84, 85, 85, 86, 87, 88, 88, 89, 90, - 90, 91, 92, 92, 93, 94, 95, 95, 96, 97, 97, 98, 99, 100, 100, 101, - 102, 102, 103, 104, 104, 105, 106, 107, 107, 108, 109, 109, 110, 111, 112, 112, - 113, 114, 114, 115, 116, 116, 117, 118, 119, 119, 120, 121, 121, 122, 123, 124, - 124, 125, 126, 126, 127, 128, 128, 129, 130, 131, 131, 132, 133, 133, 134, 135, - 136, 136, 137, 138, 138, 139, 140, 140, 141, 142, 143, 143, 144, 145, 145, 146, - 147, 148, 148, 149, 150, 150, 151, 152, 152, 153, 154, 155, 155, 156, 157, 157, - 158, 159, 160, 160, 161, 162, 162, 163, 164, 164, 165, 166, 167, 167, 168, 169, - 169, 170, 171, 172, 172, 173, 174, 174, 175, 176, 176, 177, 178, 179, 179, 180 + 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]; }; -static const uchar icvHue180To255[] = +template<typename _Tp> struct RGB2XYZ_i { - 0, 1, 3, 4, 6, 7, 9, 10, 11, 13, 14, 16, 17, 18, 20, 21, - 23, 24, 26, 27, 28, 30, 31, 33, 34, 35, 37, 38, 40, 41, 43, 44, - 45, 47, 48, 50, 51, 52, 54, 55, 57, 58, 60, 61, 62, 64, 65, 67, - 68, 69, 71, 72, 74, 75, 77, 78, 79, 81, 82, 84, 85, 86, 88, 89, - 91, 92, 94, 95, 96, 98, 99, 101, 102, 103, 105, 106, 108, 109, 111, 112, - 113, 115, 116, 118, 119, 120, 122, 123, 125, 126, 128, 129, 130, 132, 133, 135, - 136, 137, 139, 140, 142, 143, 145, 146, 147, 149, 150, 152, 153, 154, 156, 157, - 159, 160, 162, 163, 164, 166, 167, 169, 170, 171, 173, 174, 176, 177, 179, 180, - 181, 183, 184, 186, 187, 188, 190, 191, 193, 194, 196, 197, 198, 200, 201, 203, - 204, 205, 207, 208, 210, 211, 213, 214, 215, 217, 218, 220, 221, 222, 224, 225, - 227, 228, 230, 231, 232, 234, 235, 237, 238, 239, 241, 242, 244, 245, 247, 248, - 249, 251, 252, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 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 = CV_DESCALE(src[0]*C0 + src[1]*C1 + src[2]*C2, xyz_shift); + int Y = CV_DESCALE(src[0]*C3 + src[1]*C4 + src[2]*C5, xyz_shift); + int Z = CV_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]; }; -static CvStatus CV_STDCALL -icvBGRx2HSV_8u_CnC3R( const uchar* src, int srcstep, uchar* dst, int dststep, - CvSize size, int src_cn, int blue_idx ) +template<typename _Tp> struct XYZ2RGB_i { - int i; - -#ifdef HAVE_IPP - CvStatus status = icvBGRx2ABC_IPP_8u_CnC3R( src, srcstep, dst, dststep, size, - src_cn, blue_idx, (CvColorCvtFunc0)ippiRGBToHSV_8u_C3R ); - if( status >= 0 ) + typedef _Tp channel_type; + + XYZ2RGB_i(int _dstcn, int _blueIdx, const int* _coeffs) + : dstcn(_dstcn), blueIdx(_blueIdx) { - size.width *= 3; - for( ; size.height--; dst += dststep ) + static const int coeffs0[] = { - for( i = 0; i <= size.width - 12; i += 12 ) - { - uchar t0 = icvHue255To180[dst[i]], t1 = icvHue255To180[dst[i+3]]; - dst[i] = t0; dst[i+3] = t1; - t0 = icvHue255To180[dst[i+6]]; t1 = icvHue255To180[dst[i+9]]; - dst[i+6] = t0; dst[i+9] = t1; - } - for( ; i < size.width; i += 3 ) - dst[i] = icvHue255To180[dst[i]]; + 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]); } } - return status; -#else + 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 = CV_DESCALE(src[i]*C0 + src[i+1]*C1 + src[i+2]*C2, xyz_shift); + int G = CV_DESCALE(src[i]*C3 + src[i+1]*C4 + src[i+2]*C5, xyz_shift); + int R = CV_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]; +}; + + +////////////////////////////////////// RGB <-> HSV /////////////////////////////////////// + + +struct RGB2HSV_b +{ + typedef uchar channel_type; + + RGB2HSV_b(int _srccn, int _blueIdx, int _hrange) + : srccn(_srccn), blueIdx(_blueIdx), hrange(_hrange) {} - const int hsv_shift = 12; - - static const int div_table[] = { - 0, 1044480, 522240, 348160, 261120, 208896, 174080, 149211, - 130560, 116053, 104448, 94953, 87040, 80345, 74606, 69632, - 65280, 61440, 58027, 54973, 52224, 49737, 47476, 45412, - 43520, 41779, 40172, 38684, 37303, 36017, 34816, 33693, - 32640, 31651, 30720, 29842, 29013, 28229, 27486, 26782, - 26112, 25475, 24869, 24290, 23738, 23211, 22706, 22223, - 21760, 21316, 20890, 20480, 20086, 19707, 19342, 18991, - 18651, 18324, 18008, 17703, 17408, 17123, 16846, 16579, - 16320, 16069, 15825, 15589, 15360, 15137, 14921, 14711, - 14507, 14308, 14115, 13926, 13743, 13565, 13391, 13221, - 13056, 12895, 12738, 12584, 12434, 12288, 12145, 12006, - 11869, 11736, 11605, 11478, 11353, 11231, 11111, 10995, - 10880, 10768, 10658, 10550, 10445, 10341, 10240, 10141, - 10043, 9947, 9854, 9761, 9671, 9582, 9495, 9410, - 9326, 9243, 9162, 9082, 9004, 8927, 8852, 8777, - 8704, 8632, 8561, 8492, 8423, 8356, 8290, 8224, - 8160, 8097, 8034, 7973, 7913, 7853, 7795, 7737, - 7680, 7624, 7569, 7514, 7461, 7408, 7355, 7304, - 7253, 7203, 7154, 7105, 7057, 7010, 6963, 6917, - 6872, 6827, 6782, 6739, 6695, 6653, 6611, 6569, - 6528, 6487, 6447, 6408, 6369, 6330, 6292, 6254, - 6217, 6180, 6144, 6108, 6073, 6037, 6003, 5968, - 5935, 5901, 5868, 5835, 5803, 5771, 5739, 5708, - 5677, 5646, 5615, 5585, 5556, 5526, 5497, 5468, - 5440, 5412, 5384, 5356, 5329, 5302, 5275, 5249, - 5222, 5196, 5171, 5145, 5120, 5095, 5070, 5046, - 5022, 4998, 4974, 4950, 4927, 4904, 4881, 4858, - 4836, 4813, 4791, 4769, 4748, 4726, 4705, 4684, - 4663, 4642, 4622, 4601, 4581, 4561, 4541, 4522, - 4502, 4483, 4464, 4445, 4426, 4407, 4389, 4370, - 4352, 4334, 4316, 4298, 4281, 4263, 4246, 4229, - 4212, 4195, 4178, 4161, 4145, 4128, 4112, 4096 - }; - - srcstep -= size.width*src_cn; - size.width *= 3; - - for( ; size.height--; src += srcstep, dst += dststep ) + void operator()(const uchar* src, uchar* dst, int n) const { - for( i = 0; i < size.width; i += 3, src += src_cn ) + int i, bidx = blueIdx, scn = srccn; + const int hsv_shift = 12; + + static const int div_table[] = { + 0, 1044480, 522240, 348160, 261120, 208896, 174080, 149211, + 130560, 116053, 104448, 94953, 87040, 80345, 74606, 69632, + 65280, 61440, 58027, 54973, 52224, 49737, 47476, 45412, + 43520, 41779, 40172, 38684, 37303, 36017, 34816, 33693, + 32640, 31651, 30720, 29842, 29013, 28229, 27486, 26782, + 26112, 25475, 24869, 24290, 23738, 23211, 22706, 22223, + 21760, 21316, 20890, 20480, 20086, 19707, 19342, 18991, + 18651, 18324, 18008, 17703, 17408, 17123, 16846, 16579, + 16320, 16069, 15825, 15589, 15360, 15137, 14921, 14711, + 14507, 14308, 14115, 13926, 13743, 13565, 13391, 13221, + 13056, 12895, 12738, 12584, 12434, 12288, 12145, 12006, + 11869, 11736, 11605, 11478, 11353, 11231, 11111, 10995, + 10880, 10768, 10658, 10550, 10445, 10341, 10240, 10141, + 10043, 9947, 9854, 9761, 9671, 9582, 9495, 9410, + 9326, 9243, 9162, 9082, 9004, 8927, 8852, 8777, + 8704, 8632, 8561, 8492, 8423, 8356, 8290, 8224, + 8160, 8097, 8034, 7973, 7913, 7853, 7795, 7737, + 7680, 7624, 7569, 7514, 7461, 7408, 7355, 7304, + 7253, 7203, 7154, 7105, 7057, 7010, 6963, 6917, + 6872, 6827, 6782, 6739, 6695, 6653, 6611, 6569, + 6528, 6487, 6447, 6408, 6369, 6330, 6292, 6254, + 6217, 6180, 6144, 6108, 6073, 6037, 6003, 5968, + 5935, 5901, 5868, 5835, 5803, 5771, 5739, 5708, + 5677, 5646, 5615, 5585, 5556, 5526, 5497, 5468, + 5440, 5412, 5384, 5356, 5329, 5302, 5275, 5249, + 5222, 5196, 5171, 5145, 5120, 5095, 5070, 5046, + 5022, 4998, 4974, 4950, 4927, 4904, 4881, 4858, + 4836, 4813, 4791, 4769, 4748, 4726, 4705, 4684, + 4663, 4642, 4622, 4601, 4581, 4561, 4541, 4522, + 4502, 4483, 4464, 4445, 4426, 4407, 4389, 4370, + 4352, 4334, 4316, 4298, 4281, 4263, 4246, 4229, + 4212, 4195, 4178, 4161, 4145, 4128, 4112, 4096 + }; + int hr = hrange, hscale = hr == 180 ? 15 : 21; + n *= 3; + + for( i = 0; i < n; i += 3, src += scn ) { - int b = (src)[blue_idx], g = (src)[1], r = (src)[2^blue_idx]; + int b = src[bidx], g = src[1], r = src[bidx^2]; int h, s, v = b; int vmin = b, diff; int vr, vg; - + CV_CALC_MAX_8U( v, g ); CV_CALC_MAX_8U( v, r ); CV_CALC_MIN_8U( vmin, g ); CV_CALC_MIN_8U( vmin, r ); - + diff = v - vmin; vr = v == r ? -1 : 0; vg = v == g ? -1 : 0; - + s = diff * div_table[v] >> hsv_shift; h = (vr & (g - b)) + (~vr & ((vg & (b - r + 2 * diff)) + ((~vg) & (r - g + 4 * diff)))); - h = ((h * div_table[diff] * 15 + (1 << (hsv_shift + 6))) >> (7 + hsv_shift))\ - + (h < 0 ? 30*6 : 0); - + h = (h * div_table[diff] * hscale + (1 << (hsv_shift + 6))) >> (7 + hsv_shift); + h += h < 0 ? hr : 0; + dst[i] = (uchar)h; dst[i+1] = (uchar)s; dst[i+2] = (uchar)v; } } + + int srccn, blueIdx, hrange; +}; - return CV_OK; -#endif -} - - -static CvStatus CV_STDCALL -icvBGRx2HSV_32f_CnC3R( const float* src, int srcstep, - float* dst, int dststep, - CvSize size, int src_cn, int blue_idx ) + +struct RGB2HSV_f { - int i; - srcstep /= sizeof(src[0]); - dststep /= sizeof(dst[0]); - srcstep -= size.width*src_cn; - size.width *= 3; - - for( ; size.height--; src += srcstep, dst += dststep ) + 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 { - for( i = 0; i < size.width; i += 3, src += src_cn ) + 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[blue_idx], g = src[1], r = src[2^blue_idx]; + 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)); @@ -1248,32 +862,35 @@ icvBGRx2HSV_32f_CnC3R( const float* src, int srcstep, h = (b - r)*diff + 120.f; else h = (r - g)*diff + 240.f; - + if( h < 0 ) h += 360.f; - - dst[i] = h; + + dst[i] = h*hscale; dst[i+1] = s; dst[i+2] = v; } } - - return CV_OK; -} + + int srccn, blueIdx; + float hrange; +}; -static CvStatus CV_STDCALL -icvHSV2BGRx_32f_C3CnR( const float* src, int srcstep, float* dst, - int dststep, CvSize size, int dst_cn, int blue_idx ) +struct HSV2RGB_f { - int i; - srcstep /= sizeof(src[0]); - dststep /= sizeof(dst[0]); - dststep -= size.width*dst_cn; - size.width *= 3; - - for( ; size.height--; src += srcstep, dst += dststep ) + 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 { - for( i = 0; i < size.width; i += 3, dst += dst_cn ) + 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; @@ -1286,7 +903,7 @@ icvHSV2BGRx_32f_C3CnR( const float* src, int srcstep, float* dst, {{1,3,0}, {1,0,2}, {3,0,1}, {0,2,1}, {0,1,3}, {2,1,0}}; float tab[4]; int sector; - h *= 0.016666666666666666f; // h /= 60; + h *= _hscale; if( h < 0 ) do h += 6; while( h < 0 ); else if( h >= 6 ) @@ -1304,792 +921,789 @@ icvHSV2BGRx_32f_C3CnR( const float* src, int srcstep, float* dst, r = tab[sector_data[sector][2]]; } - dst[blue_idx] = b; + dst[bidx] = b; dst[1] = g; - dst[blue_idx^2] = r; - if( dst_cn == 4 ) - dst[3] = 0; + dst[bidx^2] = r; + if( dcn == 4 ) + dst[3] = alpha; } } - return CV_OK; -} - + int dstcn, blueIdx; + float hscale; +}; + -static CvStatus CV_STDCALL -icvHSV2BGRx_8u_C3CnR( const uchar* src, int srcstep, uchar* dst, int dststep, - CvSize size, int dst_cn, int blue_idx ) +struct HSV2RGB_b { - static const float pre_coeffs[] = { 2.f, 0.f, 0.0039215686274509803f, 0.f, 1.f, 0.f }; - -#ifdef HAVE_IPP - int block_size = MIN(1 << 14, size.width); - uchar* buffer; - int i, di, k; - CvStatus status = CV_OK; - - buffer = (uchar*)cvStackAlloc( block_size*3*sizeof(buffer[0]) ); - dststep -= size.width*dst_cn; - - for( ; size.height--; src += srcstep, dst += dststep ) + typedef uchar channel_type; + + HSV2RGB_b(int _dstcn, int _blueIdx, int _hrange) + : dstcn(_dstcn), cvt(3, _blueIdx, _hrange) + {} + + void operator()(const uchar* src, uchar* dst, int n) const { - for( i = 0; i < size.width; i += block_size ) + int i, j, dcn = dstcn; + uchar alpha = ColorChannel<uchar>::max(); + float buf[3*BLOCK_SIZE]; + + for( i = 0; i < n; i += BLOCK_SIZE, src += BLOCK_SIZE*3 ) { - const uchar* src1 = src + i*3; - di = MIN(block_size, size.width - i); - for( k = 0; k < di*3; k += 3 ) + int dn = std::min(n - i, (int)BLOCK_SIZE); + + for( j = 0; j < dn*3; j += 3 ) { - uchar h = icvHue180To255[src1[k]]; - uchar s = src1[k+1]; - uchar v = src1[k+2]; - buffer[k] = h; - buffer[k+1] = s; - buffer[k+2] = v; + buf[j] = src[j]; + buf[j+1] = src[j+1]*(1.f/255.f); + buf[j+2] = src[j+2]*(1.f/255.f); } - - status = (CvStatus)ippiHSVToRGB_8u_C3R( buffer, di*3, - buffer, di*3, ippiSize(di,1) ); - if( status < 0 ) - return status; - - for( k = 0; k < di*3; k += 3, dst += dst_cn ) + cvt(buf, buf, dn); + + for( j = 0; j < dn*3; j += 3, dst += dcn ) { - uchar r = buffer[k]; - uchar g = buffer[k+1]; - uchar b = buffer[k+2]; - dst[blue_idx] = b; - dst[1] = g; - dst[blue_idx^2] = r; - if( dst_cn == 4 ) - dst[3] = 0; + dst[0] = saturate_cast<uchar>(buf[j]*255.f); + dst[1] = saturate_cast<uchar>(buf[j+1]*255.f); + dst[2] = saturate_cast<uchar>(buf[j+2]*255.f); + if( dcn == 4 ) + dst[3] = alpha; } } } - return CV_OK; -#else - return icvABC2BGRx_8u_C3CnR( src, srcstep, dst, dststep, size, dst_cn, blue_idx, - (CvColorCvtFunc2)icvHSV2BGRx_32f_C3CnR, pre_coeffs, 0 ); -#endif -} - + + int dstcn; + HSV2RGB_f cvt; +}; -/****************************************************************************************\ -* RGB <-> HLS * -\****************************************************************************************/ + +///////////////////////////////////// RGB <-> HLS //////////////////////////////////////// -static CvStatus CV_STDCALL -icvBGRx2HLS_32f_CnC3R( const float* src, int srcstep, float* dst, int dststep, - CvSize size, int src_cn, int blue_idx ) +struct RGB2HLS_f { - int i; - -#ifdef HAVE_IPP - CvStatus status = icvBGRx2ABC_IPP_32f_CnC3R( src, srcstep, dst, dststep, size, - src_cn, blue_idx, (CvColorCvtFunc0)ippiRGBToHLS_32f_C3R ); - if( status >= 0 ) - { - size.width *= 3; - dststep /= sizeof(dst[0]); - - for( ; size.height--; dst += dststep ) - { - for( i = 0; i <= size.width - 12; i += 12 ) - { - float t0 = dst[i]*360.f, t1 = dst[i+3]*360.f; - dst[i] = t0; dst[i+3] = t1; - t0 = dst[i+6]*360.f; t1 = dst[i+9]*360.f; - dst[i+6] = t0; dst[i+9] = t1; - } - for( ; i < size.width; i += 3 ) - dst[i] = dst[i]*360.f; - } - } - return status; -#else - srcstep /= sizeof(src[0]); - dststep /= sizeof(dst[0]); - srcstep -= size.width*src_cn; - size.width *= 3; - - for( ; size.height--; src += srcstep, dst += dststep ) + 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 { - for( i = 0; i < size.width; i += 3, src += src_cn ) + 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[blue_idx], g = src[1], r = src[2^blue_idx]; + 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; + + dst[i] = h*hscale; dst[i+1] = l; dst[i+2] = s; } } - - return CV_OK; -#endif -} - - -static CvStatus CV_STDCALL -icvHLS2BGRx_32f_C3CnR( const float* src, int srcstep, float* dst, int dststep, - CvSize size, int dst_cn, int blue_idx ) + + int srccn, blueIdx; + float hrange; +}; + + +struct RGB2HLS_b { - int i; - srcstep /= sizeof(src[0]); - dststep /= sizeof(dst[0]); - -#ifdef HAVE_IPP - int block_size = MIN(1 << 10, size.width); - float* buffer; - int di, k; - CvStatus status = CV_OK; - - buffer = (float*)cvStackAlloc( block_size*3*sizeof(buffer[0]) ); - dststep -= size.width*dst_cn; - - for( ; size.height--; src += srcstep, dst += dststep ) + 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 { - for( i = 0; i < size.width; i += block_size ) + int i, j, scn = srccn; + float buf[3*BLOCK_SIZE]; + + for( i = 0; i < n; i += BLOCK_SIZE, dst += BLOCK_SIZE*3 ) { - const float* src1 = src + i*3; - di = MIN(block_size, size.width - i); - for( k = 0; k < di*3; k += 3 ) + int dn = std::min(n - i, (int)BLOCK_SIZE); + + for( j = 0; j < dn*3; j += 3, src += scn ) { - float h = src1[k]*0.0027777777777777779f; // /360. - float s = src1[k+1], v = src1[k+2]; - buffer[k] = h; buffer[k+1] = s; buffer[k+2] = v; + 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); } - - status = (CvStatus)ippiHLSToRGB_32f_C3R( buffer, di*3*sizeof(dst[0]), - buffer, di*3*sizeof(dst[0]), ippiSize(di,1) ); - if( status < 0 ) - return status; - - for( k = 0; k < di*3; k += 3, dst += dst_cn ) + cvt(buf, buf, dn); + + for( j = 0; j < dn*3; j += 3 ) { - float r = buffer[k], g = buffer[k+1], b = buffer[k+2]; - dst[blue_idx] = b; dst[1] = g; dst[blue_idx^2] = r; - if( dst_cn == 4 ) - dst[3] = 0; + dst[j] = saturate_cast<uchar>(buf[j]); + dst[j+1] = saturate_cast<uchar>(buf[j+1]*255.f); + dst[j+2] = saturate_cast<uchar>(buf[j+2]*255.f); } } } - - return CV_OK; -#else - dststep -= size.width*dst_cn; - size.width *= 3; + int srccn; + RGB2HLS_f cvt; +}; + - for( ; size.height--; src += srcstep, dst += dststep ) +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 { - for( i = 0; i < size.width; i += 3, dst += dst_cn ) + 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]; float b, g, r; - + if( s == 0 ) b = g = r = l; 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}}; + {{1,3,0}, {1,0,2}, {3,0,1}, {0,2,1}, {0,1,3}, {2,1,0}}; float tab[4]; int sector; float p2 = l <= 0.5f ? l*(1 + s) : l + s - l*s; float p1 = 2*l - p2; - - h *= 0.016666666666666666f; // h /= 60; + + h *= _hscale; if( h < 0 ) do h += 6; while( h < 0 ); else if( h >= 6 ) do h -= 6; while( h >= 6 ); - + assert( 0 <= h && h < 6 ); sector = cvFloor(h); h -= sector; - + tab[0] = p2; tab[1] = p1; tab[2] = p1 + (p2 - p1)*(1-h); tab[3] = p1 + (p2 - p1)*h; - + b = tab[sector_data[sector][0]]; g = tab[sector_data[sector][1]]; r = tab[sector_data[sector][2]]; } - - dst[blue_idx] = b; + + dst[bidx] = b; dst[1] = g; - dst[blue_idx^2] = r; - if( dst_cn == 4 ) - dst[3] = 0; + dst[bidx^2] = r; + if( dcn == 4 ) + dst[3] = alpha; } } + + int dstcn, blueIdx; + float hscale; +}; + - return CV_OK; -#endif -} - -static CvStatus CV_STDCALL -icvBGRx2HLS_8u_CnC3R( const uchar* src, int srcstep, uchar* dst, int dststep, - CvSize size, int src_cn, int blue_idx ) +struct HLS2RGB_b { - static const float post_coeffs[] = { 0.5f, 0.f, 255.f, 0.f, 255.f, 0.f }; - -#ifdef HAVE_IPP - CvStatus status = icvBGRx2ABC_IPP_8u_CnC3R( src, srcstep, dst, dststep, size, - src_cn, blue_idx, (CvColorCvtFunc0)ippiRGBToHLS_8u_C3R ); - if( status >= 0 ) + typedef uchar channel_type; + + HLS2RGB_b(int _dstcn, int _blueIdx, int _hrange) + : dstcn(_dstcn), cvt(3, _blueIdx, _hrange) + {} + + void operator()(const uchar* src, uchar* dst, int n) const { - size.width *= 3; - for( ; size.height--; dst += dststep ) + int i, j, dcn = dstcn; + uchar alpha = ColorChannel<uchar>::max(); + float buf[3*BLOCK_SIZE]; + + for( i = 0; i < n; i += BLOCK_SIZE, src += BLOCK_SIZE*3 ) { - int i; - for( i = 0; i <= size.width - 12; i += 12 ) + int dn = std::min(n - i, (int)BLOCK_SIZE); + + for( j = 0; 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); + + for( j = 0; j < dn*3; j += 3, dst += dcn ) { - uchar t0 = icvHue255To180[dst[i]], t1 = icvHue255To180[dst[i+3]]; - dst[i] = t0; dst[i+3] = t1; - t0 = icvHue255To180[dst[i+6]]; t1 = icvHue255To180[dst[i+9]]; - dst[i+6] = t0; dst[i+9] = t1; + dst[0] = saturate_cast<uchar>(buf[j]*255.f); + dst[1] = saturate_cast<uchar>(buf[j+1]*255.f); + dst[2] = saturate_cast<uchar>(buf[j+2]*255.f); + if( dcn == 4 ) + dst[3] = alpha; } - for( ; i < size.width; i += 3 ) - dst[i] = icvHue255To180[dst[i]]; } } - return status; -#else - return icvBGRx2ABC_8u_CnC3R( src, srcstep, dst, dststep, size, src_cn, blue_idx, - (CvColorCvtFunc2)icvBGRx2HLS_32f_CnC3R, 1, post_coeffs ); -#endif -} - + + int dstcn; + HLS2RGB_f cvt; +}; -static CvStatus CV_STDCALL -icvHLS2BGRx_8u_C3CnR( const uchar* src, int srcstep, uchar* dst, int dststep, - CvSize size, int dst_cn, int blue_idx ) -{ - static const float pre_coeffs[] = { 2.f, 0.f, 0.0039215686274509803f, 0.f, - 0.0039215686274509803f, 0.f }; + +///////////////////////////////////// RGB <-> L*a*b* ///////////////////////////////////// -#ifdef HAVE_IPP - int block_size = MIN(1 << 14, size.width); - uchar* buffer; - int i, di, k; - CvStatus status = CV_OK; +static const float D65[] = { 0.950456f, 1.f, 1.088754f }; - buffer = (uchar*)cvStackAlloc( block_size*3*sizeof(buffer[0]) ); - dststep -= size.width*dst_cn; +enum { LAB_CBRT_TAB_SIZE = 1024, GAMMA_TAB_SIZE = 1024 }; +static float LabCbrtTab[LAB_CBRT_TAB_SIZE*4]; +static const float LabCbrtTabScale = LAB_CBRT_TAB_SIZE/1.5f; - for( ; size.height--; src += srcstep, dst += dststep ) +static float sRGBGammaTab[GAMMA_TAB_SIZE*4], sRGBInvGammaTab[GAMMA_TAB_SIZE*4]; +static const float GammaTabScale = (float)GAMMA_TAB_SIZE; + +static ushort sRGBGammaTab_b[256], linearGammaTab_b[256]; +#undef lab_shift +#define lab_shift xyz_shift +#define gamma_shift 3 +#define lab_shift2 (lab_shift + gamma_shift) +#define LAB_CBRT_TAB_SIZE_B (256*3/2*(1<<gamma_shift)) +static ushort LabCbrtTab_b[LAB_CBRT_TAB_SIZE_B]; + +static void initLabTabs() +{ + static bool initialized = false; + if(!initialized) { - for( i = 0; i < size.width; i += block_size ) + float f[LAB_CBRT_TAB_SIZE+1], g[GAMMA_TAB_SIZE], ig[GAMMA_TAB_SIZE], scale = 1.f/LabCbrtTabScale; + int i; + for(i = 0; i <= LAB_CBRT_TAB_SIZE; i++) { - const uchar* src1 = src + i*3; - di = MIN(block_size, size.width - i); - for( k = 0; k < di*3; k += 3 ) - { - uchar h = icvHue180To255[src1[k]]; - uchar l = src1[k+1]; - uchar s = src1[k+2]; - buffer[k] = h; - buffer[k+1] = l; - buffer[k+2] = s; - } - - status = (CvStatus)ippiHLSToRGB_8u_C3R( buffer, di*3, - buffer, di*3, ippiSize(di,1) ); - if( status < 0 ) - return status; - - for( k = 0; k < di*3; k += 3, dst += dst_cn ) - { - uchar r = buffer[k]; - uchar g = buffer[k+1]; - uchar b = buffer[k+2]; - dst[blue_idx] = b; - dst[1] = g; - dst[blue_idx^2] = r; - if( dst_cn == 4 ) - dst[3] = 0; - } + float x = i*scale; + f[i] = x < 0.008856f ? x*7.787f + 0.13793103448275862f : cvCbrt(x); + } + splineBuild(f, LAB_CBRT_TAB_SIZE, LabCbrtTab); + + scale = 1.f/GammaTabScale; + for(i = 0; i <= GAMMA_TAB_SIZE; i++) + { + float x = i*scale; + g[i] = x <= 0.04045f ? x*(1.f/12.92f) : (float)pow((double)(x + 0.055)*(1./1.055), 2.4); + ig[i] = x <= 0.0031308 ? x*12.92f : (float)(1.055*pow((double)x, 1./2.4) - 0.055); + } + splineBuild(g, GAMMA_TAB_SIZE, sRGBGammaTab); + splineBuild(ig, GAMMA_TAB_SIZE, sRGBInvGammaTab); + + for(i = 0; i < 256; i++) + { + float x = i*(1.f/255.f); + sRGBGammaTab_b[i] = saturate_cast<ushort>(255.f*(1 << gamma_shift)*(x <= 0.04045f ? x*(1.f/12.92f) : (float)pow((double)(x + 0.055)*(1./1.055), 2.4))); + linearGammaTab_b[i] = (ushort)(i*(1 << gamma_shift)); } + + for(i = 0; i < LAB_CBRT_TAB_SIZE_B; i++) + { + float x = i*(1.f/(255.f*(1 << gamma_shift))); + LabCbrtTab_b[i] = saturate_cast<ushort>((1 << lab_shift2)*(x < 0.008856f ? x*7.787f + 0.13793103448275862f : cvCbrt(x))); + } + initialized = true; } - - return CV_OK; -#else - return icvABC2BGRx_8u_C3CnR( src, srcstep, dst, dststep, size, dst_cn, blue_idx, - (CvColorCvtFunc2)icvHLS2BGRx_32f_C3CnR, pre_coeffs, 1 ); -#endif } -/****************************************************************************************\ -* RGB <-> L*a*b* * -\****************************************************************************************/ - -#define labXr_32f 0.433953f /* = xyzXr_32f / 0.950456 */ -#define labXg_32f 0.376219f /* = xyzXg_32f / 0.950456 */ -#define labXb_32f 0.189828f /* = xyzXb_32f / 0.950456 */ - -#define labYr_32f 0.212671f /* = xyzYr_32f */ -#define labYg_32f 0.715160f /* = xyzYg_32f */ -#define labYb_32f 0.072169f /* = xyzYb_32f */ - -#define labZr_32f 0.017758f /* = xyzZr_32f / 1.088754 */ -#define labZg_32f 0.109477f /* = xyzZg_32f / 1.088754 */ -#define labZb_32f 0.872766f /* = xyzZb_32f / 1.088754 */ - -#define labRx_32f 3.0799327f /* = xyzRx_32f * 0.950456 */ -#define labRy_32f (-1.53715f) /* = xyzRy_32f */ -#define labRz_32f (-0.542782f)/* = xyzRz_32f * 1.088754 */ - -#define labGx_32f (-0.921235f)/* = xyzGx_32f * 0.950456 */ -#define labGy_32f 1.875991f /* = xyzGy_32f */ -#define labGz_32f 0.04524426f /* = xyzGz_32f * 1.088754 */ - -#define labBx_32f 0.0528909755f /* = xyzBx_32f * 0.950456 */ -#define labBy_32f (-0.204043f) /* = xyzBy_32f */ -#define labBz_32f 1.15115158f /* = xyzBz_32f * 1.088754 */ - -#define labT_32f 0.008856f - -#define labT fix(labT_32f*255,lab_shift) - -#undef lab_shift -#define lab_shift 10 -#define labXr fix(labXr_32f,lab_shift) -#define labXg fix(labXg_32f,lab_shift) -#define labXb fix(labXb_32f,lab_shift) - -#define labYr fix(labYr_32f,lab_shift) -#define labYg fix(labYg_32f,lab_shift) -#define labYb fix(labYb_32f,lab_shift) - -#define labZr fix(labZr_32f,lab_shift) -#define labZg fix(labZg_32f,lab_shift) -#define labZb fix(labZb_32f,lab_shift) - -#define labSmallScale_32f 7.787f -#define labSmallShift_32f 0.13793103448275862f /* 16/116 */ -#define labLScale_32f 116.f -#define labLShift_32f 16.f -#define labLScale2_32f 903.3f - -#define labSmallScale fix(31.27 /* labSmallScale_32f*(1<<lab_shift)/255 */,lab_shift) -#define labSmallShift fix(141.24138 /* labSmallScale_32f*(1<<lab) */,lab_shift) -#define labLScale fix(295.8 /* labLScale_32f*255/100 */,lab_shift) -#define labLShift fix(41779.2 /* labLShift_32f*1024*255/100 */,lab_shift) -#define labLScale2 fix(labLScale2_32f*0.01,lab_shift) - -/* 1024*(([0..511]./255)**(1./3)) */ -static ushort icvLabCubeRootTab[] = { - 0, 161, 203, 232, 256, 276, 293, 308, 322, 335, 347, 359, 369, 379, 389, 398, - 406, 415, 423, 430, 438, 445, 452, 459, 465, 472, 478, 484, 490, 496, 501, 507, - 512, 517, 523, 528, 533, 538, 542, 547, 552, 556, 561, 565, 570, 574, 578, 582, - 586, 590, 594, 598, 602, 606, 610, 614, 617, 621, 625, 628, 632, 635, 639, 642, - 645, 649, 652, 655, 659, 662, 665, 668, 671, 674, 677, 680, 684, 686, 689, 692, - 695, 698, 701, 704, 707, 710, 712, 715, 718, 720, 723, 726, 728, 731, 734, 736, - 739, 741, 744, 747, 749, 752, 754, 756, 759, 761, 764, 766, 769, 771, 773, 776, - 778, 780, 782, 785, 787, 789, 792, 794, 796, 798, 800, 803, 805, 807, 809, 811, - 813, 815, 818, 820, 822, 824, 826, 828, 830, 832, 834, 836, 838, 840, 842, 844, - 846, 848, 850, 852, 854, 856, 857, 859, 861, 863, 865, 867, 869, 871, 872, 874, - 876, 878, 880, 882, 883, 885, 887, 889, 891, 892, 894, 896, 898, 899, 901, 903, - 904, 906, 908, 910, 911, 913, 915, 916, 918, 920, 921, 923, 925, 926, 928, 929, - 931, 933, 934, 936, 938, 939, 941, 942, 944, 945, 947, 949, 950, 952, 953, 955, - 956, 958, 959, 961, 962, 964, 965, 967, 968, 970, 971, 973, 974, 976, 977, 979, - 980, 982, 983, 985, 986, 987, 989, 990, 992, 993, 995, 996, 997, 999, 1000, 1002, - 1003, 1004, 1006, 1007, 1009, 1010, 1011, 1013, 1014, 1015, 1017, 1018, 1019, 1021, 1022, 1024, - 1025, 1026, 1028, 1029, 1030, 1031, 1033, 1034, 1035, 1037, 1038, 1039, 1041, 1042, 1043, 1044, - 1046, 1047, 1048, 1050, 1051, 1052, 1053, 1055, 1056, 1057, 1058, 1060, 1061, 1062, 1063, 1065, - 1066, 1067, 1068, 1070, 1071, 1072, 1073, 1074, 1076, 1077, 1078, 1079, 1081, 1082, 1083, 1084, - 1085, 1086, 1088, 1089, 1090, 1091, 1092, 1094, 1095, 1096, 1097, 1098, 1099, 1101, 1102, 1103, - 1104, 1105, 1106, 1107, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1117, 1118, 1119, 1120, 1121, - 1122, 1123, 1124, 1125, 1127, 1128, 1129, 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1138, 1139, - 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1154, 1155, 1156, - 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, - 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, - 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, - 1205, 1206, 1207, 1208, 1209, 1210, 1211, 1212, 1213, 1214, 1215, 1215, 1216, 1217, 1218, 1219, - 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1230, 1231, 1232, 1233, 1234, - 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, - 1250, 1251, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259, 1259, 1260, 1261, 1262, 1263, - 1264, 1265, 1266, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1273, 1274, 1275, 1276, 1277, - 1278, 1279, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1285, 1286, 1287, 1288, 1289, 1290, 1291 +struct RGB2Lab_b +{ + typedef uchar channel_type; + + RGB2Lab_b(int _srccn, int blueIdx, const float* _coeffs, + const float* _whitept, bool _srgb) + : srccn(_srccn), srgb(_srgb) + { + initLabTabs(); + + if(!_coeffs) _coeffs = sRGB2XYZ_D65; + if(!_whitept) _whitept = D65; + float scale[] = + { + (1 << lab_shift)/_whitept[0], + (float)(1 << lab_shift), + (1 << lab_shift)/_whitept[2] + }; + + for( int i = 0; i < 3; i++ ) + { + coeffs[i*3+(blueIdx^2)] = cvRound(_coeffs[i*3]*scale[i]); + coeffs[i*3+1] = cvRound(_coeffs[i*3+1]*scale[i]); + coeffs[i*3+blueIdx] = cvRound(_coeffs[i*3+2]*scale[i]); + CV_Assert( coeffs[i] >= 0 && coeffs[i+3] >= 0 && coeffs[i+6] >= 0 && + coeffs[i] + coeffs[i+1] + coeffs[i+2] < 2*(1 << lab_shift) ); + } + } + + void operator()(const uchar* src, uchar* dst, int n) const + { + const int Lscale = (116*255+50)/100; + const int Lshift = -((16*255*(1 << lab_shift2) + 50)/100); + const ushort* tab = srgb ? sRGBGammaTab_b : linearGammaTab_b; + int i, 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( i = 0; i < n; i += 3, src += scn ) + { + int R = tab[src[0]], G = tab[src[1]], B = tab[src[2]]; + int fX = LabCbrtTab_b[CV_DESCALE(R*C0 + G*C1 + B*C2, lab_shift)]; + int fY = LabCbrtTab_b[CV_DESCALE(R*C3 + G*C4 + B*C5, lab_shift)]; + int fZ = LabCbrtTab_b[CV_DESCALE(R*C6 + G*C7 + B*C8, lab_shift)]; + + int L = CV_DESCALE( Lscale*fY + Lshift, lab_shift2 ); + int a = CV_DESCALE( 500*(fX - fY) + 128*(1 << lab_shift2), lab_shift2 ); + int b = CV_DESCALE( 200*(fY - fZ) + 128*(1 << lab_shift2), lab_shift2 ); + + dst[i] = saturate_cast<uchar>(L); + dst[i+1] = saturate_cast<uchar>(a); + dst[i+2] = saturate_cast<uchar>(b); + } + } + + int srccn; + int coeffs[9]; + bool srgb; }; - - -static CvStatus CV_STDCALL -icvBGRx2Lab_8u_CnC3R( const uchar* src, int srcstep, uchar* dst, int dststep, - CvSize size, int src_cn, int blue_idx ) + + +struct RGB2Lab_f { -#ifdef HAVE_IPP - return icvBGRx2ABC_IPP_8u_CnC3R( src, srcstep, dst, dststep, size, - src_cn, blue_idx^2, (CvColorCvtFunc0)ippiBGRToLab_8u_C3R ); -#else - srcstep -= size.width*src_cn; - size.width *= 3; - - for( ; size.height--; src += srcstep, dst += dststep ) + typedef float channel_type; + + RGB2Lab_f(int _srccn, int blueIdx, const float* _coeffs, + const float* _whitept, bool _srgb) + : srccn(_srccn), srgb(_srgb) { - for( int i = 0; i < size.width; i += 3, src += src_cn ) + initLabTabs(); + + if(!_coeffs) _coeffs = sRGB2XYZ_D65; + if(!_whitept) _whitept = D65; + float scale[] = { LabCbrtTabScale/_whitept[0], LabCbrtTabScale, LabCbrtTabScale/_whitept[2] }; + + for( int i = 0; i < 3; i++ ) { - int b = src[blue_idx], g = src[1], r = src[2^blue_idx]; - int x, y, z, f; - int L, a; - - x = b*labXb + g*labXg + r*labXr; - y = b*labYb + g*labYg + r*labYr; - z = b*labZb + g*labZg + r*labZr; - - f = x > labT; - x = CV_DESCALE( x, lab_shift ); - - if( f ) - assert( (unsigned)x < 512 ), x = icvLabCubeRootTab[x]; - else - x = CV_DESCALE(x*labSmallScale + labSmallShift,lab_shift); - - f = z > labT; - z = CV_DESCALE( z, lab_shift ); - - if( f ) - assert( (unsigned)z < 512 ), z = icvLabCubeRootTab[z]; - else - z = CV_DESCALE(z*labSmallScale + labSmallShift,lab_shift); - - f = y > labT; - y = CV_DESCALE( y, lab_shift ); - - if( f ) + coeffs[i*3+(blueIdx^2)] = _coeffs[i*3]*scale[i]; + coeffs[i*3+1] = _coeffs[i*3+1]*scale[i]; + coeffs[i*3+blueIdx] = _coeffs[i*3+2]*scale[i]; + CV_Assert( coeffs[i*3] >= 0 && coeffs[i*3+1] >= 0 && coeffs[i*3+2] >= 0 && + coeffs[i*3] + coeffs[i*3+1] + coeffs[i*3+2] < 1.5f*LabCbrtTabScale ); + } + } + + void operator()(const float* src, float* dst, int n) const + { + int i, scn = srccn; + float gscale = GammaTabScale; + const float* gammaTab = srgb ? sRGBGammaTab : 0; + 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( i = 0; i < n; i += 3, src += scn ) + { + float R = src[0], G = src[1], B = src[2]; + if( gammaTab ) { - assert( (unsigned)y < 512 ), y = icvLabCubeRootTab[y]; - L = CV_DESCALE(y*labLScale - labLShift, 2*lab_shift ); + R = splineInterpolate(R*gscale, gammaTab, GAMMA_TAB_SIZE); + G = splineInterpolate(G*gscale, gammaTab, GAMMA_TAB_SIZE); + B = splineInterpolate(B*gscale, gammaTab, GAMMA_TAB_SIZE); } - else + float fX = splineInterpolate(R*C0 + G*C1 + B*C2, LabCbrtTab, LAB_CBRT_TAB_SIZE); + float fY = splineInterpolate(R*C3 + G*C4 + B*C5, LabCbrtTab, LAB_CBRT_TAB_SIZE); + float fZ = splineInterpolate(R*C6 + G*C7 + B*C8, LabCbrtTab, LAB_CBRT_TAB_SIZE); + + float L = 116.f*fY - 16.f; + float a = 500.f*(fX - fY); + float b = 200.f*(fY - fZ); + + dst[i] = L; dst[i+1] = a; dst[i+2] = b; + } + } + + int srccn; + float coeffs[9]; + bool srgb; +}; + + +struct Lab2RGB_f +{ + typedef float channel_type; + + Lab2RGB_f( int _dstcn, int blueIdx, const float* _coeffs, + const float* _whitept, bool _srgb ) + : dstcn(_dstcn), srgb(_srgb) + { + initLabTabs(); + + if(!_coeffs) _coeffs = XYZ2sRGB_D65; + if(!_whitept) _whitept = D65; + + for( int i = 0; i < 3; i++ ) + { + coeffs[i+(blueIdx^2)*3] = _coeffs[i]*_whitept[i]; + coeffs[i+3] = _coeffs[i+3]*_whitept[i]; + coeffs[i+blueIdx*3] = _coeffs[i+6]*_whitept[i]; + } + } + + void operator()(const float* src, float* dst, int n) const + { + int i, dcn = dstcn; + const float* gammaTab = srgb ? sRGBInvGammaTab : 0; + float gscale = GammaTabScale; + 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]; + float alpha = ColorChannel<float>::max(); + n *= 3; + + for( i = 0; i < n; i += 3, dst += dcn ) + { + float L = src[i], a = src[i+1], b = src[i+2]; + float Y = (L + 16.f)*(1.f/116.f); + float X = (Y + a*0.002f); + float Z = (Y - b*0.005f); + Y = Y*Y*Y; + X = X*X*X; + Z = Z*Z*Z; + + float R = X*C0 + Y*C1 + Z*C2; + float G = X*C3 + Y*C4 + Z*C5; + float B = X*C6 + Y*C7 + Z*C8; + + if( gammaTab ) { - L = CV_DESCALE(y*labLScale2,lab_shift); - y = CV_DESCALE(y*labSmallScale + labSmallShift,lab_shift); + R = splineInterpolate(R*gscale, gammaTab, GAMMA_TAB_SIZE); + G = splineInterpolate(G*gscale, gammaTab, GAMMA_TAB_SIZE); + B = splineInterpolate(B*gscale, gammaTab, GAMMA_TAB_SIZE); } - - a = CV_DESCALE( 500*(x - y), lab_shift ) + 128; - b = CV_DESCALE( 200*(y - z), lab_shift ) + 128; - - dst[i] = CV_CAST_8U(L); - dst[i+1] = CV_CAST_8U(a); - dst[i+2] = CV_CAST_8U(b); + + dst[0] = R; dst[1] = G; dst[2] = B; + if( dcn == 4 ) + dst[3] = alpha; } } + + int dstcn; + float coeffs[9]; + bool srgb; +}; - return CV_OK; -#endif -} - - -static CvStatus CV_STDCALL -icvBGRx2Lab_32f_CnC3R( const float* src, int srcstep, float* dst, int dststep, - CvSize size, int src_cn, int blue_idx ) + +struct Lab2RGB_b { - int i; - srcstep /= sizeof(src[0]); - dststep /= sizeof(dst[0]); - srcstep -= size.width*src_cn; - size.width *= 3; - - for( ; size.height--; src += srcstep, dst += dststep ) + typedef uchar channel_type; + + Lab2RGB_b( int _dstcn, int blueIdx, const float* _coeffs, + const float* _whitept, bool _srgb ) + : dstcn(_dstcn), cvt(3, blueIdx, _coeffs, _whitept, _srgb ) {} + + void operator()(const uchar* src, uchar* dst, int n) const { - for( i = 0; i < size.width; i += 3, src += src_cn ) + int i, j, dcn = dstcn; + uchar alpha = ColorChannel<uchar>::max(); + float buf[3*BLOCK_SIZE]; + + for( i = 0; i < n; i += BLOCK_SIZE, src += BLOCK_SIZE*3 ) { - float b = src[blue_idx], g = src[1], r = src[2^blue_idx]; - float x, y, z; - float L, a; - - x = b*labXb_32f + g*labXg_32f + r*labXr_32f; - y = b*labYb_32f + g*labYg_32f + r*labYr_32f; - z = b*labZb_32f + g*labZg_32f + r*labZr_32f; - - if( x > labT_32f ) - x = cvCbrt(x); - else - x = x*labSmallScale_32f + labSmallShift_32f; - - if( z > labT_32f ) - z = cvCbrt(z); - else - z = z*labSmallScale_32f + labSmallShift_32f; - - if( y > labT_32f ) + int dn = std::min(n - i, (int)BLOCK_SIZE); + + for( j = 0; j < dn*3; j += 3 ) { - y = cvCbrt(y); - L = y*labLScale_32f - labLShift_32f; + buf[j] = src[j]*(100.f/255.f); + buf[j+1] = (float)(src[j+1] - 128); + buf[j+2] = (float)(src[j+2] - 128); } - else + cvt(buf, buf, dn); + + for( j = 0; j < dn*3; j += 3, dst += dcn ) { - L = y*labLScale2_32f; - y = y*labSmallScale_32f + labSmallShift_32f; + dst[0] = saturate_cast<uchar>(buf[j]*255.f); + dst[1] = saturate_cast<uchar>(buf[j+1]*255.f); + dst[2] = saturate_cast<uchar>(buf[j+2]*255.f); + if( dcn == 4 ) + dst[3] = alpha; } - - a = 500.f*(x - y); - b = 200.f*(y - z); - - dst[i] = L; - dst[i+1] = a; - dst[i+2] = b; } } + + int dstcn; + Lab2RGB_f cvt; +}; + + +///////////////////////////////////// RGB <-> L*u*v* ///////////////////////////////////// - return CV_OK; -} - - -static CvStatus CV_STDCALL -icvLab2BGRx_32f_C3CnR( const float* src, int srcstep, float* dst, int dststep, - CvSize size, int dst_cn, int blue_idx ) +struct RGB2Luv_f { - int i; - srcstep /= sizeof(src[0]); - dststep /= sizeof(dst[0]); - dststep -= size.width*dst_cn; - size.width *= 3; - - for( ; size.height--; src += srcstep, dst += dststep ) + typedef float channel_type; + + RGB2Luv_f( int _srccn, int blueIdx, const float* _coeffs, + const float* whitept, bool _srgb ) + : srccn(_srccn), srgb(_srgb) { - for( i = 0; i < size.width; i += 3, dst += dst_cn ) + initLabTabs(); + + if(!_coeffs) _coeffs = sRGB2XYZ_D65; + if(!whitept) whitept = D65; + + for( int i = 0; i < 3; i++ ) { - float L = src[i], a = src[i+1], b = src[i+2]; - float x, y, z; - float g, r; - - L = (L + labLShift_32f)*(1.f/labLScale_32f); - x = (L + a*0.002f); - z = (L - b*0.005f); - y = L*L*L; - x = x*x*x; - z = z*z*z; - - b = x*labBx_32f + y*labBy_32f + z*labBz_32f; - g = x*labGx_32f + y*labGy_32f + z*labGz_32f; - r = x*labRx_32f + y*labRy_32f + z*labRz_32f; - - dst[blue_idx] = b; - dst[1] = g; - dst[blue_idx^2] = r; - if( dst_cn == 4 ) - dst[3] = 0; + coeffs[i*3+(blueIdx^2)] = _coeffs[i*3]; + coeffs[i*3+1] = _coeffs[i*3+1]; + coeffs[i*3+blueIdx] = _coeffs[i*3+2]; + CV_Assert( coeffs[i*3] >= 0 && coeffs[i*3+1] >= 0 && coeffs[i*3+2] >= 0 && + coeffs[i*3] + coeffs[i*3+1] + coeffs[i*3+2] < 1.5f ); } + + float d = 1.f/(whitept[0] + whitept[1]*15 + whitept[2]*3); + un = 4*whitept[0]*d; + vn = 9*whitept[1]*d; + + CV_Assert(whitept[1] == 1.f); } + + void operator()(const float* src, float* dst, int n) const + { + int i, scn = srccn; + float gscale = GammaTabScale; + const float* gammaTab = srgb ? sRGBGammaTab : 0; + 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]; + float _un = 13*un, _vn = 13*vn; + n *= 3; + + for( i = 0; i < n; i += 3, src += scn ) + { + float R = src[0], G = src[1], B = src[2]; + if( gammaTab ) + { + R = splineInterpolate(R*gscale, gammaTab, GAMMA_TAB_SIZE); + G = splineInterpolate(G*gscale, gammaTab, GAMMA_TAB_SIZE); + B = splineInterpolate(B*gscale, gammaTab, GAMMA_TAB_SIZE); + } + + float X = R*C0 + G*C1 + B*C2; + float Y = R*C3 + G*C4 + B*C5; + float Z = R*C6 + G*C7 + B*C8; + + float L = splineInterpolate(Y*LabCbrtTabScale, LabCbrtTab, LAB_CBRT_TAB_SIZE); + L = 116.f*L - 16.f; + + float d = (4*13) / std::max(X + 15 * Y + 3 * Z, FLT_EPSILON); + float u = L*(X*d - _un); + float v = L*((9*0.25)*Y*d - _vn); + + dst[i] = L; dst[i+1] = u; dst[i+2] = v; + } + } + + int srccn; + float coeffs[9], un, vn; + bool srgb; +}; - return CV_OK; -} - - -static CvStatus CV_STDCALL -icvLab2BGRx_8u_C3CnR( const uchar* src, int srcstep, uchar* dst, int dststep, - CvSize size, int dst_cn, int blue_idx ) -{ -#ifdef HAVE_IPP - return icvABC2BGRx_IPP_8u_C3CnR( src, srcstep, dst, dststep, size, - dst_cn, blue_idx^2, (CvColorCvtFunc0)ippiLabToBGR_8u_C3R ); -#else - // L: [0..255] -> [0..100] - // a: [0..255] -> [-128..127] - // b: [0..255] -> [-128..127] - static const float pre_coeffs[] = { 0.39215686274509809f, 0.f, 1.f, -128.f, 1.f, -128.f }; - - return icvABC2BGRx_8u_C3CnR( src, srcstep, dst, dststep, size, dst_cn, blue_idx, - (CvColorCvtFunc2)icvLab2BGRx_32f_C3CnR, pre_coeffs, 1 ); -#endif -} - - -/****************************************************************************************\ -* RGB <-> L*u*v* * -\****************************************************************************************/ - -#define luvUn_32f 0.19793943f -#define luvVn_32f 0.46831096f -#define luvYmin_32f 0.05882353f /* 15/255 */ - -static CvStatus CV_STDCALL -icvBGRx2Luv_32f_CnC3R( const float* src, int srcstep, float* dst, int dststep, - CvSize size, int src_cn, int blue_idx ) + +struct Luv2RGB_f { -#ifdef HAVE_IPP - return icvBGRx2ABC_IPP_32f_CnC3R( src, srcstep, dst, dststep, size, - src_cn, blue_idx, (CvColorCvtFunc0)ippiRGBToLUV_32f_C3R ); -#else - srcstep /= sizeof(src[0]); - dststep /= sizeof(dst[0]); - srcstep -= size.width*src_cn; - size.width *= 3; - - for( ; size.height--; src += srcstep, dst += dststep ) + typedef float channel_type; + + Luv2RGB_f( int _dstcn, int blueIdx, const float* _coeffs, + const float* whitept, bool _srgb ) + : dstcn(_dstcn), srgb(_srgb) { - for( int i = 0; i < size.width; i += 3, src += src_cn ) + initLabTabs(); + + if(!_coeffs) _coeffs = XYZ2sRGB_D65; + if(!whitept) whitept = D65; + + for( int i = 0; i < 3; i++ ) { - float b = src[blue_idx], g = src[1], r = src[2^blue_idx]; - float x, y, z; - float L, u, v, t; - - x = b*xyzXb_32f + g*xyzXg_32f + r*xyzXr_32f; - y = b*xyzYb_32f + g*xyzYg_32f + r*xyzYr_32f; - z = b*xyzZb_32f + g*xyzZg_32f + r*xyzZr_32f; - - if( !x && !y && !z ) - L = u = v = 0.f; - else + coeffs[i+(blueIdx^2)*3] = _coeffs[i]; + coeffs[i+3] = _coeffs[i+3]; + coeffs[i+blueIdx*3] = _coeffs[i+6]; + } + + float d = 1.f/(whitept[0] + whitept[1]*15 + whitept[2]*3); + un = 4*whitept[0]*d; + vn = 9*whitept[1]*d; + + CV_Assert(whitept[1] == 1.f); + } + + void operator()(const float* src, float* dst, int n) const + { + int i, dcn = dstcn; + const float* gammaTab = srgb ? sRGBInvGammaTab : 0; + float gscale = GammaTabScale; + 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]; + float alpha = ColorChannel<float>::max(); + float _un = un, _vn = vn; + n *= 3; + + for( i = 0; i < n; i += 3, dst += dcn ) + { + float L = src[i], u = src[i+1], v = src[i+2], d, X, Y, Z; + Y = (L + 16.f) * (1.f/116.f); + Y = Y*Y*Y; + d = (1.f/13.f)/L; + u = u*d + _un; + v = v*d + _vn; + float iv = 1.f/v; + X = 2.25f * u * Y * iv ; + Z = (12 - 3 * u - 20 * v) * Y * 0.25 * iv; + + float R = X*C0 + Y*C1 + Z*C2; + float G = X*C3 + Y*C4 + Z*C5; + float B = X*C6 + Y*C7 + Z*C8; + + if( gammaTab ) { - if( y > labT_32f ) - L = labLScale_32f * cvCbrt(y) - labLShift_32f; - else - L = labLScale2_32f * y; - - t = 1.f / (x + 15 * y + 3 * z); - u = 4.0f * x * t; - v = 9.0f * y * t; - - u = 13*L*(u - luvUn_32f); - v = 13*L*(v - luvVn_32f); + R = splineInterpolate(R*gscale, gammaTab, GAMMA_TAB_SIZE); + G = splineInterpolate(G*gscale, gammaTab, GAMMA_TAB_SIZE); + B = splineInterpolate(B*gscale, gammaTab, GAMMA_TAB_SIZE); } - - dst[i] = L; - dst[i+1] = u; - dst[i+2] = v; + + dst[0] = R; dst[1] = G; dst[2] = B; + if( dcn == 4 ) + dst[3] = alpha; } } + + int dstcn; + float coeffs[9], un, vn; + bool srgb; +}; - return CV_OK; -#endif -} - - -static CvStatus CV_STDCALL -icvLuv2BGRx_32f_C3CnR( const float* src, int srcstep, float* dst, int dststep, - CvSize size, int dst_cn, int blue_idx ) + +struct RGB2Luv_b { -#ifdef HAVE_IPP - return icvABC2BGRx_IPP_32f_C3CnR( src, srcstep, dst, dststep, size, - dst_cn, blue_idx, (CvColorCvtFunc0)ippiLUVToRGB_32f_C3R ); -#else - srcstep /= sizeof(src[0]); - dststep /= sizeof(dst[0]); - dststep -= size.width*dst_cn; - size.width *= 3; - - for( ; size.height--; src += srcstep, dst += dststep ) + typedef uchar channel_type; + + RGB2Luv_b( int _srccn, int blueIdx, const float* _coeffs, + const float* _whitept, bool _srgb ) + : srccn(_srccn), cvt(3, blueIdx, _coeffs, _whitept, _srgb) {} + + void operator()(const uchar* src, uchar* dst, int n) const { - for( int i = 0; i < size.width; i += 3, dst += dst_cn ) + int i, j, scn = srccn; + float buf[3*BLOCK_SIZE]; + + for( i = 0; i < n; i += BLOCK_SIZE, dst += BLOCK_SIZE*3 ) { - float L = src[i], u = src[i+1], v = src[i+2]; - float x, y, z, t, u1, v1, b, g, r; - - if( L >= 8 ) + int dn = std::min(n - i, (int)BLOCK_SIZE); + + for( j = 0; j < dn*3; j += 3, src += scn ) { - t = (L + labLShift_32f) * (1.f/labLScale_32f); - y = t*t*t; + buf[j] = src[0]*(1.f/255.f); + buf[j+1] = (float)(src[1]*(1.f/255.f)); + buf[j+2] = (float)(src[2]*(1.f/255.f)); } - else + cvt(buf, buf, dn); + + for( j = 0; j < dn*3; j += 3 ) { - y = L * (1.f/labLScale2_32f); - L = MAX( L, 0.001f ); + dst[j] = saturate_cast<uchar>(buf[j]*2.55f); + dst[j+1] = saturate_cast<uchar>(buf[j+1]*0.72033898305084743f + 96.525423728813564f); + dst[j+2] = saturate_cast<uchar>(buf[j+2]*0.99609375f + 139.453125f); } - - t = 1.f/(13.f * L); - u1 = u*t + luvUn_32f; - v1 = v*t + luvVn_32f; - x = 2.25f * u1 * y / v1 ; - z = (12 - 3 * u1 - 20 * v1) * y / (4 * v1); - - b = xyzBx_32f*x + xyzBy_32f*y + xyzBz_32f*z; - g = xyzGx_32f*x + xyzGy_32f*y + xyzGz_32f*z; - r = xyzRx_32f*x + xyzRy_32f*y + xyzRz_32f*z; - - dst[blue_idx] = b; - dst[1] = g; - dst[blue_idx^2] = r; - if( dst_cn == 4 ) - dst[3] = 0.f; } } + + int srccn; + RGB2Luv_f cvt; +}; + - return CV_OK; -#endif -} - - -static CvStatus CV_STDCALL -icvBGRx2Luv_8u_CnC3R( const uchar* src, int srcstep, uchar* dst, int dststep, - CvSize size, int src_cn, int blue_idx ) -{ -#ifdef HAVE_IPP - return icvBGRx2ABC_IPP_8u_CnC3R( src, srcstep, dst, dststep, size, - src_cn, blue_idx, (CvColorCvtFunc0)ippiRGBToLUV_8u_C3R ); -#else - // L: [0..100] -> [0..255] - // u: [-134..220] -> [0..255] - // v: [-140..122] -> [0..255] - //static const float post_coeffs[] = { 2.55f, 0.f, 1.f, 83.f, 1.f, 140.f }; - static const float post_coeffs[] = { 2.55f, 0.f, 0.72033898305084743f, 96.525423728813564f, - 0.99609375f, 139.453125f }; - return icvBGRx2ABC_8u_CnC3R( src, srcstep, dst, dststep, size, src_cn, blue_idx, - (CvColorCvtFunc2)icvBGRx2Luv_32f_CnC3R, 1, post_coeffs ); -#endif -} - - -static CvStatus CV_STDCALL -icvLuv2BGRx_8u_C3CnR( const uchar* src, int srcstep, uchar* dst, int dststep, - CvSize size, int dst_cn, int blue_idx ) +struct Luv2RGB_b { -#ifdef HAVE_IPP - return icvABC2BGRx_IPP_8u_C3CnR( src, srcstep, dst, dststep, size, - dst_cn, blue_idx, (CvColorCvtFunc0)ippiLUVToRGB_8u_C3R ); -#else - // L: [0..255] -> [0..100] - // u: [0..255] -> [-134..220] - // v: [0..255] -> [-140..122] - static const float pre_coeffs[] = { 0.39215686274509809f, 0.f, 1.388235294117647f, -134.f, - 1.003921568627451f, -140.f }; - - return icvABC2BGRx_8u_C3CnR( src, srcstep, dst, dststep, size, dst_cn, blue_idx, - (CvColorCvtFunc2)icvLuv2BGRx_32f_C3CnR, pre_coeffs, 1 ); -#endif -} + typedef uchar channel_type; + + Luv2RGB_b( int _dstcn, int blueIdx, const float* _coeffs, + const float* _whitept, bool _srgb ) + : dstcn(_dstcn), cvt(3, blueIdx, _coeffs, _whitept, _srgb ) {} + + void operator()(const uchar* src, uchar* dst, int n) const + { + int i, j, dcn = dstcn; + uchar alpha = ColorChannel<uchar>::max(); + float 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); + + for( j = 0; j < dn*3; j += 3 ) + { + buf[j] = src[j]*(100.f/255.f); + buf[j+1] = (float)(src[j+1]*1.388235294117647f - 134.f); + buf[j+2] = (float)(src[j+2]*1.003921568627451f - 140.f); + } + cvt(buf, buf, dn); + + for( j = 0; j < dn*3; j += 3, dst += dcn ) + { + dst[0] = saturate_cast<uchar>(buf[j]*255.f); + dst[1] = saturate_cast<uchar>(buf[j+1]*255.f); + dst[2] = saturate_cast<uchar>(buf[j+2]*255.f); + if( dcn == 4 ) + dst[3] = alpha; + } + } + } + + int dstcn; + Luv2RGB_f cvt; +}; -/****************************************************************************************\ -* Bayer Pattern -> RGB conversion * -\****************************************************************************************/ + +//////////////////////////// Bayer Pattern -> RGB conversion ///////////////////////////// -static CvStatus CV_STDCALL -icvBayer2BGR_8u_C1C3R( const uchar* bayer0, int bayer_step, - uchar *dst0, int dst_step, - CvSize size, int code ) +static void Bayer2RGB_8u( const Mat& srcmat, Mat& dstmat, int code ) { + const uchar* bayer0 = srcmat.data; + int bayer_step = (int)srcmat.step; + uchar* dst0 = dstmat.data; + int dst_step = (int)dstmat.step; + Size size = srcmat.size(); int blue = code == CV_BayerBG2BGR || code == CV_BayerGB2BGR ? -1 : 1; int start_with_green = code == CV_BayerGB2BGR || code == CV_BayerGR2BGR; @@ -2178,23 +1792,28 @@ icvBayer2BGR_8u_C1C3R( const uchar* bayer0, int bayer_step, blue = -blue; start_with_green = !start_with_green; } - - return CV_OK; } - - -static CvStatus CV_STDCALL -icvBayer2BGR_VNG_8u_C1C3R( const uchar* bayer, int bstep, - uchar *dst, int dststep, - CvSize size, int code ) + +/////////////////// Demosaicing using Variable Number of Gradients /////////////////////// + +static void Bayer2RGB_VNG_8u( const Mat& srcmat, Mat& dstmat, int code ) { + const uchar* bayer = srcmat.data; + int bstep = (int)srcmat.step; + uchar* dst = dstmat.data; + int dststep = (int)dstmat.step; + Size size = srcmat.size(); + int blueIdx = code == CV_BayerBG2BGR_VNG || code == CV_BayerGB2BGR_VNG ? 0 : 2; bool greenCell0 = code != CV_BayerBG2BGR_VNG && code != CV_BayerRG2BGR_VNG; // for too small images use the simple interpolation algorithm if( MIN(size.width, size.height) < 8 ) - return icvBayer2BGR_8u_C1C3R( bayer, bstep, dst, dststep, size, code ); + { + Bayer2RGB_8u( srcmat, dstmat, code ); + return; + } const int brows = 3, bcn = 7; int N = size.width, N2 = N*2, N3 = N*3, N4 = N*4, N5 = N*5, N6 = N*6, N7 = N*7; @@ -2223,8 +1842,8 @@ icvBayer2BGR_VNG_8u_C1C3R( const uchar* bayer, int bstep, brow[N*i-1] = brow[(N-2) + N*i] = 0; i = 1; - - #if CV_SSE2 + +#if CV_SSE2 if( haveSSE ) { __m128i z = _mm_setzero_si128(); @@ -2271,22 +1890,22 @@ icvBayer2BGR_VNG_8u_C1C3R( const uchar* bayer, int bstep, _mm_storeu_si128((__m128i*)(brow + N6), b6); } } - #endif - +#endif + for( ; i < N-1; i++, srow++, brow++ ) { - brow[0] = (ushort)(abs(srow[-1-bstep] - srow[-1+bstep]) + - abs(srow[-bstep] - srow[+bstep])*2 + - abs(srow[1-bstep] - srow[1+bstep])); - brow[N] = (ushort)(abs(srow[-1-bstep] - srow[1-bstep]) + - abs(srow[-1] - srow[1])*2 + - abs(srow[-1+bstep] - srow[1+bstep])); - brow[N2] = (ushort)(abs(srow[+1-bstep] - srow[-1+bstep])*2); - brow[N3] = (ushort)(abs(srow[-1-bstep] - srow[1+bstep])*2); - brow[N4] = (ushort)(brow[N2] + abs(srow[-bstep] - srow[-1]) + - abs(srow[+bstep] - srow[1])); - brow[N5] = (ushort)(brow[N3] + abs(srow[-bstep] - srow[1]) + - abs(srow[+bstep] - srow[-1])); + brow[0] = (ushort)(std::abs(srow[-1-bstep] - srow[-1+bstep]) + + std::abs(srow[-bstep] - srow[+bstep])*2 + + std::abs(srow[1-bstep] - srow[1+bstep])); + brow[N] = (ushort)(std::abs(srow[-1-bstep] - srow[1-bstep]) + + std::abs(srow[-1] - srow[1])*2 + + std::abs(srow[-1+bstep] - srow[1+bstep])); + brow[N2] = (ushort)(std::abs(srow[+1-bstep] - srow[-1+bstep])*2); + brow[N3] = (ushort)(std::abs(srow[-1-bstep] - srow[1+bstep])*2); + brow[N4] = (ushort)(brow[N2] + std::abs(srow[-bstep] - srow[-1]) + + std::abs(srow[+bstep] - srow[1])); + brow[N5] = (ushort)(brow[N3] + std::abs(srow[-bstep] - srow[1]) + + std::abs(srow[+bstep] - srow[-1])); brow[N6] = (ushort)((srow[-bstep] + srow[-1] + srow[1] + srow[+bstep])>>1); } } @@ -2299,11 +1918,11 @@ icvBayer2BGR_VNG_8u_C1C3R( const uchar* bayer, int bstep, bool greenCell = greenCell0; i = 2; - #if CV_SSE2 +#if CV_SSE2 int limit = !haveSSE ? N-2 : greenCell ? std::min(3, N-2) : 2; - #else +#else int limit = N - 2; - #endif +#endif do { @@ -2467,20 +2086,20 @@ icvBayer2BGR_VNG_8u_C1C3R( const uchar* bayer, int bstep, greenCell = !greenCell; } - #if CV_SSE2 +#if CV_SSE2 if( !haveSSE ) break; __m128i emask = _mm_set1_epi32(0x0000ffff), - omask = _mm_set1_epi32(0xffff0000), - z = _mm_setzero_si128(); + omask = _mm_set1_epi32(0xffff0000), + z = _mm_setzero_si128(); __m128 _0_5 = _mm_set1_ps(0.5f); #define _mm_merge_epi16(a, b) \ _mm_or_si128(_mm_and_si128(a, emask), _mm_and_si128(b, omask)) #define _mm_cvtloepi16_ps(a) _mm_cvtepi32_ps(_mm_srai_epi32(_mm_unpacklo_epi16(a,a), 16)) #define _mm_cvthiepi16_ps(a) _mm_cvtepi32_ps(_mm_srai_epi32(_mm_unpackhi_epi16(a,a), 16)) - + // process 8 pixels at once for( ; i <= N - 10; i += 8, srow += 8, brow0 += 8, brow1 += 8, brow2 += 8 ) { @@ -2542,7 +2161,7 @@ icvBayer2BGR_VNG_8u_C1C3R( const uchar* bayer, int bstep, __m128i RGs = z, GRs = z, Bs = z, ng = z, mask; __m128i t0, t1, x0, x1, x2, x3, x4, x5, x6, x7, x8, - x9, x10, x11, x12, x13, x14, x15, x16; + x9, x10, x11, x12, x13, x14, x15, x16; x0 = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)srow), z); @@ -2597,7 +2216,7 @@ icvBayer2BGR_VNG_8u_C1C3R( const uchar* bayer, int bstep, GRs = _mm_adds_epu16(GRs, _mm_and_si128(t0, mask)); Bs = _mm_adds_epu16(Bs, _mm_and_si128(_mm_merge_epi16(_mm_adds_epu16(x5,x9), _mm_adds_epu16(x6,x8)), mask)); - + // gradSE mask = _mm_cmpgt_epi16(T, gradSE); ng = _mm_sub_epi16(ng, mask); @@ -2666,12 +2285,12 @@ icvBayer2BGR_VNG_8u_C1C3R( const uchar* bayer, int bstep, t1 = _mm_sub_epi16(Bs, RGs); t0 = _mm_add_epi16(x0, _mm_packs_epi32( - _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtloepi16_ps(t0), ngf0)), - _mm_cvtps_epi32(_mm_mul_ps(_mm_cvthiepi16_ps(t0), ngf1)))); + _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtloepi16_ps(t0), ngf0)), + _mm_cvtps_epi32(_mm_mul_ps(_mm_cvthiepi16_ps(t0), ngf1)))); t1 = _mm_add_epi16(x0, _mm_packs_epi32( - _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtloepi16_ps(t1), ngf0)), - _mm_cvtps_epi32(_mm_mul_ps(_mm_cvthiepi16_ps(t1), ngf1)))); + _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtloepi16_ps(t1), ngf0)), + _mm_cvtps_epi32(_mm_mul_ps(_mm_cvthiepi16_ps(t1), ngf1)))); x1 = _mm_merge_epi16(x0, t0); x2 = _mm_merge_epi16(t0, x0); @@ -2687,7 +2306,7 @@ icvBayer2BGR_VNG_8u_C1C3R( const uchar* bayer, int bstep, dstrow[0] = B[j]; dstrow[1] = G[j]; dstrow[2] = R[j]; } } - #endif +#endif limit = N - 2; } @@ -2711,438 +2330,322 @@ icvBayer2BGR_VNG_8u_C1C3R( const uchar* bayer, int bstep, dst[i + dststep*(size.height-2)] = dst[i + dststep*(size.height-1)] = dst[i + dststep*(size.height-5)]; } - - return CV_OK; } -/****************************************************************************************\ -* The main function * -\****************************************************************************************/ -CV_IMPL void -cvCvtColor( const CvArr* srcarr, CvArr* dstarr, int code ) -{ - CvMat srcstub, *src = (CvMat*)srcarr; - CvMat dststub, *dst = (CvMat*)dstarr; - CvSize size; - int src_step, dst_step; - int src_cn, dst_cn, depth; - CvColorCvtFunc0 func0 = 0; - CvColorCvtFunc1 func1 = 0; - CvColorCvtFunc2 func2 = 0; - CvColorCvtFunc3 func3 = 0; - int param[] = { 0, 0, 0, 0 }; - - src = cvGetMat( srcarr, &srcstub ); - dst = cvGetMat( dstarr, &dststub ); - - if( !CV_ARE_SIZES_EQ( src, dst )) - CV_Error( CV_StsUnmatchedSizes, "" ); - - if( !CV_ARE_DEPTHS_EQ( src, dst )) - CV_Error( CV_StsUnmatchedFormats, "" ); - - depth = CV_MAT_DEPTH(src->type); - if( depth != CV_8U && depth != CV_16U && depth != CV_32F ) - CV_Error( CV_StsUnsupportedFormat, "" ); - - src_cn = CV_MAT_CN( src->type ); - dst_cn = CV_MAT_CN( dst->type ); - size = cvGetMatSize( src ); - src_step = src->step; - dst_step = dst->step; - - if( CV_IS_MAT_CONT(src->type & dst->type) && - code != CV_BayerBG2BGR && code != CV_BayerGB2BGR && - code != CV_BayerRG2BGR && code != CV_BayerGR2BGR && - code != CV_BayerBG2BGR_VNG && code != CV_BayerGB2BGR_VNG && - code != CV_BayerRG2BGR_VNG && code != CV_BayerGR2BGR_VNG ) - { - size.width *= size.height; - size.height = 1; - src_step = dst_step = CV_STUB_STEP; - } +////////////////////////////////////////////////////////////////////////////////////////// +// The main function // +////////////////////////////////////////////////////////////////////////////////////////// +void cvtColor( const Mat& src, Mat& dst, int code, int dcn ) +{ + Size sz = src.size(); + int scn = src.channels(), depth = src.depth(), bidx; + + CV_Assert( depth == CV_8U || depth == CV_16U || depth == CV_32F ); + switch( code ) { - case CV_BGR2BGRA: - case CV_RGB2BGRA: - if( src_cn != 3 || dst_cn != 4 ) - CV_Error( CV_BadNumChannels, - "Incorrect number of channels for this conversion code" ); - - func1 = depth == CV_8U ? (CvColorCvtFunc1)icvBGR2BGRx_8u_C3C4R : - depth == CV_16U ? (CvColorCvtFunc1)icvBGR2BGRx_16u_C3C4R : - depth == CV_32F ? (CvColorCvtFunc1)icvBGR2BGRx_32f_C3C4R : 0; - param[0] = code == CV_BGR2BGRA ? 0 : 2; // blue_idx - break; - - case CV_BGRA2BGR: - case CV_RGBA2BGR: - case CV_RGB2BGR: - if( (src_cn != 3 && src_cn != 4) || dst_cn != 3 ) - CV_Error( CV_BadNumChannels, - "Incorrect number of channels for this conversion code" ); - - func2 = depth == CV_8U ? (CvColorCvtFunc2)icvBGRx2BGR_8u_CnC3R : - depth == CV_16U ? (CvColorCvtFunc2)icvBGRx2BGR_16u_CnC3R : - depth == CV_32F ? (CvColorCvtFunc2)icvBGRx2BGR_32f_CnC3R : 0; - param[0] = src_cn; - param[1] = code == CV_BGRA2BGR ? 0 : 2; // blue_idx - break; - - case CV_BGRA2RGBA: - if( src_cn != 4 || dst_cn != 4 ) - CV_Error( CV_BadNumChannels, - "Incorrect number of channels for this conversion code" ); - - func0 = depth == CV_8U ? (CvColorCvtFunc0)icvBGRA2RGBA_8u_C4R : - depth == CV_16U ? (CvColorCvtFunc0)icvBGRA2RGBA_16u_C4R : - depth == CV_32F ? (CvColorCvtFunc0)icvBGRA2RGBA_32f_C4R : 0; - break; - - case CV_BGR2BGR565: - case CV_BGR2BGR555: - case CV_RGB2BGR565: - case CV_RGB2BGR555: - case CV_BGRA2BGR565: - case CV_BGRA2BGR555: - case CV_RGBA2BGR565: - case CV_RGBA2BGR555: - if( (src_cn != 3 && src_cn != 4) || dst_cn != 2 ) - CV_Error( CV_BadNumChannels, - "Incorrect number of channels for this conversion code" ); - - if( depth != CV_8U ) - CV_Error( CV_BadDepth, - "Conversion to/from 16-bit packed RGB format " - "is only possible for 8-bit images (8-bit grayscale, 888 BGR/RGB or 8888 BGRA/RGBA)" ); - - func3 = (CvColorCvtFunc3)icvBGRx2BGR5x5_8u_CnC2R; - param[0] = src_cn; - param[1] = code == CV_BGR2BGR565 || code == CV_BGR2BGR555 || - code == CV_BGRA2BGR565 || code == CV_BGRA2BGR555 ? 0 : 2; // blue_idx - param[2] = code == CV_BGR2BGR565 || code == CV_RGB2BGR565 || - code == CV_BGRA2BGR565 || code == CV_RGBA2BGR565 ? 6 : 5; // green_bits - break; - - case CV_BGR5652BGR: - case CV_BGR5552BGR: - case CV_BGR5652RGB: - case CV_BGR5552RGB: - case CV_BGR5652BGRA: - case CV_BGR5552BGRA: - case CV_BGR5652RGBA: - case CV_BGR5552RGBA: - if( src_cn != 2 || (dst_cn != 3 && dst_cn != 4)) - CV_Error( CV_BadNumChannels, - "Incorrect number of channels for this conversion code" ); - - if( depth != CV_8U ) - CV_Error( CV_BadDepth, - "Conversion to/from 16-bit packed BGR format " - "is only possible for 8-bit images (8-bit grayscale, 888 BGR/BGR or 8888 BGRA/BGRA)" ); - - func3 = (CvColorCvtFunc3)icvBGR5x52BGRx_8u_C2CnR; - param[0] = dst_cn; - param[1] = code == CV_BGR5652BGR || code == CV_BGR5552BGR || - code == CV_BGR5652BGRA || code == CV_BGR5552BGRA ? 0 : 2; // blue_idx - param[2] = code == CV_BGR5652BGR || code == CV_BGR5652RGB || - code == CV_BGR5652BGRA || code == CV_BGR5652RGBA ? 6 : 5; // green_bits - break; - - case CV_BGR2GRAY: - case CV_BGRA2GRAY: - case CV_RGB2GRAY: - case CV_RGBA2GRAY: - if( (src_cn != 3 && src_cn != 4) || dst_cn != 1 ) - CV_Error( CV_BadNumChannels, - "Incorrect number of channels for this conversion code" ); - - func2 = depth == CV_8U ? (CvColorCvtFunc2)icvBGRx2Gray_8u_CnC1R : - depth == CV_16U ? (CvColorCvtFunc2)icvBGRx2Gray_16u_CnC1R : - depth == CV_32F ? (CvColorCvtFunc2)icvBGRx2Gray_32f_CnC1R : 0; + case CV_BGR2BGRA: case CV_RGB2BGRA: case CV_BGRA2BGR: + case CV_RGBA2BGR: case CV_RGB2BGR: case CV_BGRA2RGBA: + CV_Assert( scn == 3 || scn == 4 ); + dcn = code == CV_BGR2BGRA || code == CV_RGB2BGRA || code == CV_BGRA2RGBA ? 4 : 3; + bidx = code == CV_BGR2BGRA || code == CV_BGRA2BGR ? 0 : 2; + + dst.create( sz, CV_MAKETYPE(depth, dcn)); + if( depth == CV_8U ) + CvtColorLoop(src, dst, RGB2RGB<uchar>(scn, dcn, bidx)); + else if( depth == CV_16U ) + CvtColorLoop(src, dst, RGB2RGB<ushort>(scn, dcn, bidx)); + else + CvtColorLoop(src, dst, RGB2RGB<float>(scn, dcn, bidx)); + break; + + case CV_BGR2BGR565: case CV_BGR2BGR555: case CV_RGB2BGR565: case CV_RGB2BGR555: + case CV_BGRA2BGR565: case CV_BGRA2BGR555: case CV_RGBA2BGR565: case CV_RGBA2BGR555: + CV_Assert( (scn == 3 || scn == 4) && depth == CV_8U ); + dst.create(sz, CV_8UC2); - param[0] = src_cn; - param[1] = code == CV_BGR2GRAY || code == CV_BGRA2GRAY ? 0 : 2; - break; - - case CV_BGR5652GRAY: - case CV_BGR5552GRAY: - if( src_cn != 2 || dst_cn != 1 ) - CV_Error( CV_BadNumChannels, - "Incorrect number of channels for this conversion code" ); - - if( depth != CV_8U ) - CV_Error( CV_BadDepth, - "Conversion to/from 16-bit packed BGR format " - "is only possible for 8-bit images (888 BGR/BGR or 8888 BGRA/BGRA)" ); - - func2 = (CvColorCvtFunc2)icvBGR5x52Gray_8u_C2C1R; + CvtColorLoop(src, dst, RGB2RGB5x5(scn, + code == CV_BGR2BGR565 || code == CV_BGR2BGR555 || + code == CV_BGRA2BGR565 || code == CV_BGRA2BGR555 ? 0 : 2, + code == CV_BGR2BGR565 || code == CV_RGB2BGR565 || + code == CV_BGRA2BGR565 || code == CV_RGBA2BGR565 ? 6 : 5 // green bits + )); + break; - param[0] = code == CV_BGR5652GRAY ? 6 : 5; // green_bits - break; - - case CV_GRAY2BGR: - case CV_GRAY2BGRA: - if( src_cn != 1 || (dst_cn != 3 && dst_cn != 4)) - CV_Error( CV_BadNumChannels, - "Incorrect number of channels for this conversion code" ); - - func1 = depth == CV_8U ? (CvColorCvtFunc1)icvGray2BGRx_8u_C1CnR : - depth == CV_16U ? (CvColorCvtFunc1)icvGray2BGRx_16u_C1CnR : - depth == CV_32F ? (CvColorCvtFunc1)icvGray2BGRx_32f_C1CnR : 0; + case CV_BGR5652BGR: case CV_BGR5552BGR: case CV_BGR5652RGB: case CV_BGR5552RGB: + case CV_BGR5652BGRA: case CV_BGR5552BGRA: case CV_BGR5652RGBA: case CV_BGR5552RGBA: + if(dcn <= 0) dcn = 3; + CV_Assert( (dcn == 3 || dcn == 4) && scn == 2 && depth == CV_8U ); + dst.create(sz, CV_MAKETYPE(depth, dcn)); + + CvtColorLoop(src, dst, RGB5x52RGB(dcn, + code == CV_BGR5652BGR || code == CV_BGR5552BGR || + code == CV_BGR5652BGRA || code == CV_BGR5552BGRA ? 0 : 2, // blue idx + code == CV_BGR5652BGR || code == CV_BGR5652RGB || + code == CV_BGR5652BGRA || code == CV_BGR5652RGBA ? 6 : 5 // green bits + )); + break; + + case CV_BGR2GRAY: case CV_BGRA2GRAY: case CV_RGB2GRAY: case CV_RGBA2GRAY: + CV_Assert( scn == 3 || scn == 4 ); + dst.create(sz, CV_MAKETYPE(depth, 1)); + bidx = code == CV_BGR2GRAY || code == CV_BGRA2GRAY ? 0 : 2; + + if( depth == CV_8U ) + CvtColorLoop(src, dst, RGB2Gray<uchar>(scn, bidx, 0)); + else if( depth == CV_16U ) + CvtColorLoop(src, dst, RGB2Gray<ushort>(scn, bidx, 0)); + else + CvtColorLoop(src, dst, RGB2Gray<float>(scn, bidx, 0)); + break; - param[0] = dst_cn; - break; - - case CV_GRAY2BGR565: - case CV_GRAY2BGR555: - if( src_cn != 1 || dst_cn != 2 ) - CV_Error( CV_BadNumChannels, - "Incorrect number of channels for this conversion code" ); - - if( depth != CV_8U ) - CV_Error( CV_BadDepth, - "Conversion to/from 16-bit packed BGR format " - "is only possible for 8-bit images (888 BGR/BGR or 8888 BGRA/BGRA)" ); - - func2 = (CvColorCvtFunc2)icvGray2BGR5x5_8u_C1C2R; - param[0] = code == CV_GRAY2BGR565 ? 6 : 5; // green_bits - break; - - case CV_BGR2YCrCb: - case CV_RGB2YCrCb: - case CV_BGR2XYZ: - case CV_RGB2XYZ: - case CV_BGR2HSV: - case CV_RGB2HSV: - case CV_BGR2Lab: - case CV_RGB2Lab: - case CV_BGR2Luv: - case CV_RGB2Luv: - case CV_BGR2HLS: - case CV_RGB2HLS: - if( (src_cn != 3 && src_cn != 4) || dst_cn != 3 ) - CV_Error( CV_BadNumChannels, - "Incorrect number of channels for this conversion code" ); - - if( depth == CV_8U ) - func2 = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? (CvColorCvtFunc2)icvBGRx2YCrCb_8u_CnC3R : - code == CV_BGR2XYZ || code == CV_RGB2XYZ ? (CvColorCvtFunc2)icvBGRx2XYZ_8u_CnC3R : - code == CV_BGR2HSV || code == CV_RGB2HSV ? (CvColorCvtFunc2)icvBGRx2HSV_8u_CnC3R : - code == CV_BGR2Lab || code == CV_RGB2Lab ? (CvColorCvtFunc2)icvBGRx2Lab_8u_CnC3R : - code == CV_BGR2Luv || code == CV_RGB2Luv ? (CvColorCvtFunc2)icvBGRx2Luv_8u_CnC3R : - code == CV_BGR2HLS || code == CV_RGB2HLS ? (CvColorCvtFunc2)icvBGRx2HLS_8u_CnC3R : 0; - else if( depth == CV_16U ) - func2 = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? (CvColorCvtFunc2)icvBGRx2YCrCb_16u_CnC3R : - code == CV_BGR2XYZ || code == CV_RGB2XYZ ? (CvColorCvtFunc2)icvBGRx2XYZ_16u_CnC3R : 0; - else if( depth == CV_32F ) - func2 = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? (CvColorCvtFunc2)icvBGRx2YCrCb_32f_CnC3R : - code == CV_BGR2XYZ || code == CV_RGB2XYZ ? (CvColorCvtFunc2)icvBGRx2XYZ_32f_CnC3R : - code == CV_BGR2HSV || code == CV_RGB2HSV ? (CvColorCvtFunc2)icvBGRx2HSV_32f_CnC3R : - code == CV_BGR2Lab || code == CV_RGB2Lab ? (CvColorCvtFunc2)icvBGRx2Lab_32f_CnC3R : - code == CV_BGR2Luv || code == CV_RGB2Luv ? (CvColorCvtFunc2)icvBGRx2Luv_32f_CnC3R : - code == CV_BGR2HLS || code == CV_RGB2HLS ? (CvColorCvtFunc2)icvBGRx2HLS_32f_CnC3R : 0; + case CV_BGR5652GRAY: case CV_BGR5552GRAY: + CV_Assert( scn == 2 && depth == CV_8U ); + dst.create(sz, CV_8UC1); + CvtColorLoop(src, dst, RGB5x52Gray(code == CV_BGR5652GRAY ? 6 : 5)); + break; - param[0] = src_cn; - param[1] = code == CV_BGR2XYZ || code == CV_BGR2YCrCb || code == CV_BGR2HSV || - code == CV_BGR2Lab || code == CV_BGR2Luv || code == CV_BGR2HLS ? 0 : 2; - break; - - case CV_YCrCb2BGR: - case CV_YCrCb2RGB: - case CV_XYZ2BGR: - case CV_XYZ2RGB: - case CV_HSV2BGR: - case CV_HSV2RGB: - case CV_Lab2BGR: - case CV_Lab2RGB: - case CV_Luv2BGR: - case CV_Luv2RGB: - case CV_HLS2BGR: - case CV_HLS2RGB: - if( src_cn != 3 || (dst_cn != 3 && dst_cn != 4) ) - CV_Error( CV_BadNumChannels, - "Incorrect number of channels for this conversion code" ); - - if( depth == CV_8U ) - func2 = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? (CvColorCvtFunc2)icvYCrCb2BGRx_8u_C3CnR : - code == CV_XYZ2BGR || code == CV_XYZ2RGB ? (CvColorCvtFunc2)icvXYZ2BGRx_8u_C3CnR : - code == CV_HSV2BGR || code == CV_HSV2RGB ? (CvColorCvtFunc2)icvHSV2BGRx_8u_C3CnR : - code == CV_HLS2BGR || code == CV_HLS2RGB ? (CvColorCvtFunc2)icvHLS2BGRx_8u_C3CnR : - code == CV_Lab2BGR || code == CV_Lab2RGB ? (CvColorCvtFunc2)icvLab2BGRx_8u_C3CnR : - code == CV_Luv2BGR || code == CV_Luv2RGB ? (CvColorCvtFunc2)icvLuv2BGRx_8u_C3CnR : 0; - else if( depth == CV_16U ) - func2 = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? (CvColorCvtFunc2)icvYCrCb2BGRx_16u_C3CnR : - code == CV_XYZ2BGR || code == CV_XYZ2RGB ? (CvColorCvtFunc2)icvXYZ2BGRx_16u_C3CnR : 0; - else if( depth == CV_32F ) - func2 = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? (CvColorCvtFunc2)icvYCrCb2BGRx_32f_C3CnR : - code == CV_XYZ2BGR || code == CV_XYZ2RGB ? (CvColorCvtFunc2)icvXYZ2BGRx_32f_C3CnR : - code == CV_HSV2BGR || code == CV_HSV2RGB ? (CvColorCvtFunc2)icvHSV2BGRx_32f_C3CnR : - code == CV_HLS2BGR || code == CV_HLS2RGB ? (CvColorCvtFunc2)icvHLS2BGRx_32f_C3CnR : - code == CV_Lab2BGR || code == CV_Lab2RGB ? (CvColorCvtFunc2)icvLab2BGRx_32f_C3CnR : - code == CV_Luv2BGR || code == CV_Luv2RGB ? (CvColorCvtFunc2)icvLuv2BGRx_32f_C3CnR : 0; + case CV_GRAY2BGR: case CV_GRAY2BGRA: + if( dcn <= 0 ) dcn = 3; + CV_Assert( scn == 1 && (dcn == 3 || dcn == 4)); + dst.create(sz, CV_MAKETYPE(depth, dcn)); + + if( depth == CV_8U ) + CvtColorLoop(src, dst, Gray2RGB<uchar>(dcn)); + else if( depth == CV_16U ) + CvtColorLoop(src, dst, Gray2RGB<ushort>(dcn)); + else + CvtColorLoop(src, dst, Gray2RGB<float>(dcn)); + break; + + case CV_GRAY2BGR565: case CV_GRAY2BGR555: + CV_Assert( scn == 1 && depth == CV_8U ); + dst.create(sz, CV_8UC2); + + CvtColorLoop(src, dst, Gray2RGB5x5(code == CV_GRAY2BGR565 ? 6 : 5)); + break; + + case CV_BGR2YCrCb: case CV_RGB2YCrCb: + case CV_BGR2YUV: case CV_RGB2YUV: + { + CV_Assert( scn == 3 || scn == 4 ); + bidx = code == CV_BGR2YCrCb || code == CV_RGB2YUV ? 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; + + dst.create(sz, CV_MAKETYPE(depth, 3)); + + if( depth == CV_8U ) + CvtColorLoop(src, dst, RGB2YCrCb_i<uchar>(scn, bidx, coeffs_i)); + else if( depth == CV_16U ) + CvtColorLoop(src, dst, RGB2YCrCb_i<ushort>(scn, bidx, coeffs_i)); + else + CvtColorLoop(src, dst, RGB2YCrCb_f<float>(scn, bidx, coeffs_f)); + } + break; + + case CV_YCrCb2BGR: case CV_YCrCb2RGB: + case CV_YUV2BGR: case CV_YUV2RGB: + { + if( dcn <= 0 ) dcn = 3; + CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) ); + bidx = code == CV_YCrCb2BGR || code == CV_YUV2RGB ? 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; + + dst.create(sz, CV_MAKETYPE(depth, dcn)); + + if( depth == CV_8U ) + CvtColorLoop(src, dst, YCrCb2RGB_i<uchar>(dcn, bidx, coeffs_i)); + else if( depth == CV_16U ) + CvtColorLoop(src, dst, YCrCb2RGB_i<ushort>(dcn, bidx, coeffs_i)); + else + CvtColorLoop(src, dst, YCrCb2RGB_f<float>(dcn, bidx, coeffs_f)); + } + break; - param[0] = dst_cn; - param[1] = code == CV_XYZ2BGR || code == CV_YCrCb2BGR || code == CV_HSV2BGR || - code == CV_Lab2BGR || code == CV_Luv2BGR || code == CV_HLS2BGR ? 0 : 2; - break; - - case CV_BayerBG2BGR: - case CV_BayerGB2BGR: - case CV_BayerRG2BGR: - case CV_BayerGR2BGR: - if( src_cn != 1 || dst_cn != 3 ) - CV_Error( CV_BadNumChannels, - "Incorrect number of channels for this conversion code" ); + case CV_BGR2XYZ: case CV_RGB2XYZ: + CV_Assert( scn == 3 || scn == 4 ); + bidx = code == CV_BGR2XYZ ? 0 : 2; + + dst.create(sz, CV_MAKETYPE(depth, 3)); + + if( depth == CV_8U ) + CvtColorLoop(src, dst, RGB2XYZ_i<uchar>(scn, bidx, 0)); + else if( depth == CV_16U ) + CvtColorLoop(src, dst, RGB2XYZ_i<ushort>(scn, bidx, 0)); + else + CvtColorLoop(src, dst, RGB2XYZ_f<float>(scn, bidx, 0)); + break; - if( depth != CV_8U ) - CV_Error( CV_BadDepth, - "Bayer pattern can be converted only to 8-bit 3-channel BGR/RGB image" ); - - func1 = (CvColorCvtFunc1)icvBayer2BGR_8u_C1C3R; - param[0] = code; // conversion code - break; - - case CV_BayerBG2BGR_VNG: - case CV_BayerGB2BGR_VNG: - case CV_BayerRG2BGR_VNG: - case CV_BayerGR2BGR_VNG: - if( src_cn != 1 || dst_cn != 3 ) - CV_Error( CV_BadNumChannels, - "Incorrect number of channels for this conversion code" ); + case CV_XYZ2BGR: case CV_XYZ2RGB: + if( dcn <= 0 ) dcn = 3; + CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) ); + bidx = code == CV_XYZ2BGR ? 0 : 2; + + dst.create(sz, CV_MAKETYPE(depth, dcn)); + + if( depth == CV_8U ) + CvtColorLoop(src, dst, XYZ2RGB_i<uchar>(dcn, bidx, 0)); + else if( depth == CV_16U ) + CvtColorLoop(src, dst, XYZ2RGB_i<ushort>(dcn, bidx, 0)); + else + CvtColorLoop(src, dst, XYZ2RGB_f<float>(dcn, bidx, 0)); + 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: + { + CV_Assert( (scn == 3 || scn == 4) && (depth == CV_8U || depth == CV_32F) ); + bidx = code == CV_BGR2HSV || code == CV_BGR2HLS || + code == CV_BGR2HSV_FULL || code == CV_BGR2HLS_FULL ? 0 : 2; + int hrange = depth == CV_32F ? 360 : code == CV_BGR2HSV || code == CV_RGB2HSV || + code == CV_BGR2HLS || code == CV_RGB2HLS ? 180 : 255; + + dst.create(sz, CV_MAKETYPE(depth, 3)); + + if( code == CV_BGR2HSV || code == CV_RGB2HSV || + code == CV_BGR2HSV_FULL || code == CV_RGB2HSV_FULL ) + { + if( depth == CV_8U ) + CvtColorLoop(src, dst, RGB2HSV_b(scn, bidx, hrange)); + else + CvtColorLoop(src, dst, RGB2HSV_f(scn, bidx, (float)hrange)); + } + else + { + if( depth == CV_8U ) + CvtColorLoop(src, dst, RGB2HLS_b(scn, bidx, hrange)); + else + CvtColorLoop(src, dst, RGB2HLS_f(scn, bidx, (float)hrange)); + } + } + break; - if( depth != CV_8U ) - CV_Error( CV_BadDepth, - "Bayer pattern can be converted only to 8-bit 3-channel BGR/RGB image" ); + 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: + { + if( dcn <= 0 ) dcn = 3; + CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) && (depth == CV_8U || depth == CV_32F) ); + bidx = code == CV_HSV2BGR || code == CV_HLS2BGR || + code == CV_HSV2BGR_FULL || code == CV_HLS2BGR_FULL ? 0 : 2; + int hrange = depth == CV_32F ? 360 : code == CV_HSV2BGR || code == CV_HSV2RGB || + code == CV_HLS2BGR || code == CV_HLS2RGB ? 180 : 255; + + dst.create(sz, CV_MAKETYPE(depth, dcn)); + + if( code == CV_HSV2BGR || code == CV_HSV2RGB || + code == CV_HSV2BGR_FULL || code == CV_HSV2RGB_FULL ) + { + if( depth == CV_8U ) + CvtColorLoop(src, dst, HSV2RGB_b(dcn, bidx, hrange)); + else + CvtColorLoop(src, dst, HSV2RGB_f(dcn, bidx, (float)hrange)); + } + else + { + if( depth == CV_8U ) + CvtColorLoop(src, dst, HLS2RGB_b(dcn, bidx, hrange)); + else + CvtColorLoop(src, dst, HLS2RGB_f(dcn, bidx, (float)hrange)); + } + } + break; + + case CV_BGR2Lab: case CV_RGB2Lab: case CV_LBGR2Lab: case CV_LRGB2Lab: + case CV_BGR2Luv: case CV_RGB2Luv: case CV_LBGR2Luv: case CV_LRGB2Luv: + { + CV_Assert( (scn == 3 || scn == 4) && (depth == CV_8U || depth == CV_32F) ); + bidx = code == CV_BGR2Lab || code == CV_BGR2Luv || + code == CV_LBGR2Lab || code == CV_LBGR2Luv ? 0 : 2; + bool srgb = code == CV_BGR2Lab || code == CV_RGB2Lab || + code == CV_BGR2Luv || code == CV_RGB2Luv; + + dst.create(sz, CV_MAKETYPE(depth, 3)); + + if( code == CV_BGR2Lab || code == CV_RGB2Lab || + code == CV_LBGR2Lab || code == CV_LRGB2Lab ) + { + if( depth == CV_8U ) + CvtColorLoop(src, dst, RGB2Lab_b(scn, bidx, 0, 0, srgb)); + else + CvtColorLoop(src, dst, RGB2Lab_f(scn, bidx, 0, 0, srgb)); + } + else + { + if( depth == CV_8U ) + CvtColorLoop(src, dst, RGB2Luv_b(scn, bidx, 0, 0, srgb)); + else + CvtColorLoop(src, dst, RGB2Luv_f(scn, bidx, 0, 0, srgb)); + } + } + break; - func1 = (CvColorCvtFunc1)icvBayer2BGR_VNG_8u_C1C3R; - param[0] = code; // conversion code - break; - default: - CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); - } - - if( func0 ) - { - IPPI_CALL( func0( src->data.ptr, src_step, dst->data.ptr, dst_step, size )); - } - else if( func1 ) - { - IPPI_CALL( func1( src->data.ptr, src_step, - dst->data.ptr, dst_step, size, param[0] )); - } - else if( func2 ) - { - IPPI_CALL( func2( src->data.ptr, src_step, - dst->data.ptr, dst_step, size, param[0], param[1] )); - } - else if( func3 ) - { - IPPI_CALL( func3( src->data.ptr, src_step, - dst->data.ptr, dst_step, size, param[0], param[1], param[2] )); + case CV_Lab2BGR: case CV_Lab2RGB: case CV_Lab2LBGR: case CV_Lab2LRGB: + case CV_Luv2BGR: case CV_Luv2RGB: case CV_Luv2LBGR: case CV_Luv2LRGB: + { + if( dcn <= 0 ) dcn = 3; + CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) && (depth == CV_8U || depth == CV_32F) ); + bidx = code == CV_Lab2BGR || code == CV_Luv2BGR || + code == CV_Lab2LBGR || code == CV_Luv2LBGR ? 0 : 2; + bool srgb = code == CV_Lab2BGR || code == CV_Lab2RGB || + code == CV_Luv2BGR || code == CV_Luv2RGB; + + dst.create(sz, CV_MAKETYPE(depth, dcn)); + + if( code == CV_Lab2BGR || code == CV_Lab2RGB || + code == CV_Lab2LBGR || code == CV_Lab2LRGB ) + { + if( depth == CV_8U ) + CvtColorLoop(src, dst, Lab2RGB_b(dcn, bidx, 0, 0, srgb)); + else + CvtColorLoop(src, dst, Lab2RGB_f(dcn, bidx, 0, 0, srgb)); + } + else + { + if( depth == CV_8U ) + CvtColorLoop(src, dst, Luv2RGB_b(dcn, bidx, 0, 0, srgb)); + else + CvtColorLoop(src, dst, Luv2RGB_f(dcn, bidx, 0, 0, srgb)); + } + } + break; + + case CV_BayerBG2BGR: case CV_BayerGB2BGR: case CV_BayerRG2BGR: case CV_BayerGR2BGR: + case CV_BayerBG2BGR_VNG: case CV_BayerGB2BGR_VNG: case CV_BayerRG2BGR_VNG: case CV_BayerGR2BGR_VNG: + CV_Assert( scn == 1 && dcn == 3 && depth == CV_8U ); + dst.create(sz, CV_8UC3); + + if( code == CV_BayerBG2BGR || code == CV_BayerGB2BGR || + code == CV_BayerRG2BGR || code == CV_BayerGR2BGR ) + Bayer2RGB_8u(src, dst, code); + else + Bayer2RGB_VNG_8u(src, dst, code); + break; + default: + CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); } - else - CV_Error( CV_StsUnsupportedFormat, "The image format is not supported" ); } - -void cv::cvtColor( const Mat& src, Mat& dst, int code, int dst_cn ) +} + +CV_IMPL void +cvCvtColor( const CvArr* srcarr, CvArr* dstarr, int code ) { - switch( code ) - { - case CV_BGR2BGRA: - case CV_RGB2BGRA: - case CV_BGRA2RGBA: - case CV_BGR5652BGRA: - case CV_BGR5552BGRA: - case CV_BGR5652RGBA: - case CV_BGR5552RGBA: - case CV_GRAY2BGRA: - dst_cn = 4; - break; - - case CV_BGR2YCrCb: - case CV_RGB2YCrCb: - case CV_BGR2XYZ: - case CV_RGB2XYZ: - case CV_BGR2HSV: - case CV_RGB2HSV: - case CV_BGR2Lab: - case CV_RGB2Lab: - case CV_BGR2Luv: - case CV_RGB2Luv: - case CV_BGR2HLS: - case CV_RGB2HLS: - dst_cn = 3; - break; - - case CV_BayerBG2BGR: - case CV_BayerGB2BGR: - case CV_BayerRG2BGR: - case CV_BayerGR2BGR: - - case CV_BayerBG2BGR_VNG: - case CV_BayerGB2BGR_VNG: - case CV_BayerRG2BGR_VNG: - case CV_BayerGR2BGR_VNG: - - case CV_BGRA2BGR: - case CV_RGBA2BGR: - case CV_RGB2BGR: - case CV_BGR5652BGR: - case CV_BGR5552BGR: - case CV_BGR5652RGB: - case CV_BGR5552RGB: - case CV_GRAY2BGR: - - case CV_YCrCb2BGR: - case CV_YCrCb2RGB: - case CV_XYZ2BGR: - case CV_XYZ2RGB: - case CV_HSV2BGR: - case CV_HSV2RGB: - case CV_Lab2BGR: - case CV_Lab2RGB: - case CV_Luv2BGR: - case CV_Luv2RGB: - case CV_HLS2BGR: - case CV_HLS2RGB: - if( dst_cn != 4 ) - dst_cn = 3; - break; - - case CV_BGR2BGR565: - case CV_BGR2BGR555: - case CV_RGB2BGR565: - case CV_RGB2BGR555: - case CV_BGRA2BGR565: - case CV_BGRA2BGR555: - case CV_RGBA2BGR565: - case CV_RGBA2BGR555: - case CV_GRAY2BGR565: - case CV_GRAY2BGR555: - dst_cn = 2; - break; - - case CV_BGR2GRAY: - case CV_BGRA2GRAY: - case CV_RGB2GRAY: - case CV_RGBA2GRAY: - case CV_BGR5652GRAY: - case CV_BGR5552GRAY: - dst_cn = 1; - break; - default: - CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); - } + cv::Mat src = cv::cvarrToMat(srcarr), dst0 = cv::cvarrToMat(dstarr), dst = dst0; + CV_Assert( src.depth() == dst.depth() ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dst_cn)); - CvMat _src = src, _dst = dst; - cvCvtColor( &_src, &_dst, code ); + cv::cvtColor(src, dst, code, dst.channels()); + CV_Assert( dst.data == dst0.data ); } + /* End of file. */ diff --git a/tests/cv/src/acolor.cpp b/tests/cv/src/acolor.cpp index e6956a4ae7..b47c1841d8 100644 --- a/tests/cv/src/acolor.cpp +++ b/tests/cv/src/acolor.cpp @@ -90,6 +90,7 @@ protected: int fwd_code, inv_code; int timing_code; bool test_cpp; + bool hue_channel; }; @@ -116,6 +117,7 @@ CV_ColorCvtBaseTestImpl::CV_ColorCvtBaseTestImpl( const char* test_name, const c default_timing_param_names = 0; test_cpp = false; + hue_channel = false; } @@ -258,6 +260,18 @@ void CV_ColorCvtBaseTestImpl::prepare_to_validation( int /*test_case_idx*/ ) convert_forward( &test_mat[INPUT][0], &test_mat[REF_OUTPUT][0] ); convert_backward( &test_mat[INPUT][0], &test_mat[REF_OUTPUT][0], &test_mat[REF_OUTPUT][1] ); + int depth = CV_MAT_DEPTH(test_mat[REF_OUTPUT][0].type); + if( depth == CV_8U && hue_channel ) + { + for( int y = 0; y < test_mat[REF_OUTPUT][0].rows; y++ ) + for( int x = 0; x < test_mat[REF_OUTPUT][0].cols; x++ ) + { + uchar* h0 = test_mat[REF_OUTPUT][0].data.ptr + test_mat[REF_OUTPUT][0].step*y + x*3; + uchar* h = test_mat[OUTPUT][0].data.ptr + test_mat[OUTPUT][0].step*y + x*3; + if( abs(*h - *h0) == 180 ) + if( *h == 0 ) *h = 180; + } + } } @@ -393,7 +407,7 @@ void CV_ColorCvtBaseTestImpl::convert_backward( const CvMat* src, const CvMat* d dst_row[j*cn + 1] = CV_CAST_8U(g); dst_row[j*cn + (blue_idx^2)] = CV_CAST_8U(r); if( cn == 4 ) - dst_row[j*cn + 3] = 0; + dst_row[j*cn + 3] = 255; } } break; @@ -416,7 +430,7 @@ void CV_ColorCvtBaseTestImpl::convert_backward( const CvMat* src, const CvMat* d dst_row[j*cn + 1] = CV_CAST_16U(g); dst_row[j*cn + (blue_idx^2)] = CV_CAST_16U(r); if( cn == 4 ) - dst_row[j*cn + 3] = 0; + dst_row[j*cn + 3] = 65535; } } break; @@ -436,7 +450,7 @@ void CV_ColorCvtBaseTestImpl::convert_backward( const CvMat* src, const CvMat* d dst_row[j*cn + 1] = g; dst_row[j*cn + (blue_idx^2)] = r; if( cn == 4 ) - dst_row[j*cn + 3] = 0; + dst_row[j*cn + 3] = 1.f; } } break; @@ -701,6 +715,7 @@ CV_ColorHSVTest::CV_ColorHSVTest() { INIT_FWD_INV_CODES( BGR2HSV, HSV2BGR ); depth_list = cvtcolor_depths_8_32; + hue_channel = true; } @@ -809,7 +824,7 @@ void CV_ColorHSVTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* d } -//CV_ColorHSVTest color_hsv_test; +CV_ColorHSVTest color_hsv_test; @@ -831,6 +846,7 @@ CV_ColorHLSTest::CV_ColorHLSTest() { INIT_FWD_INV_CODES( BGR2HLS, HLS2BGR ); depth_list = cvtcolor_depths_8_32; + hue_channel = true; } @@ -1100,16 +1116,16 @@ void CV_ColorLabTest::get_test_array_types_and_sizes( int test_case_idx, CvSize* CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); if( blue_idx == 0 ) - fwd_code = CV_BGR2Lab, inv_code = CV_Lab2BGR; + fwd_code = CV_LBGR2Lab, inv_code = CV_Lab2LBGR; else - fwd_code = CV_RGB2Lab, inv_code = CV_Lab2RGB; + fwd_code = CV_LRGB2Lab, inv_code = CV_Lab2LRGB; } double CV_ColorLabTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) { int depth = CV_MAT_DEPTH(test_mat[i][j].type); - return depth == CV_8U ? 16 : depth == CV_16U ? 32 : 1e-4; + return depth == CV_8U ? 16 : depth == CV_16U ? 32 : 1e-3; } @@ -1234,16 +1250,16 @@ void CV_ColorLuvTest::get_test_array_types_and_sizes( int test_case_idx, CvSize* CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); if( blue_idx == 0 ) - fwd_code = CV_BGR2Luv, inv_code = CV_Luv2BGR; + fwd_code = CV_LBGR2Luv, inv_code = CV_Luv2LBGR; else - fwd_code = CV_RGB2Luv, inv_code = CV_Luv2RGB; + fwd_code = CV_LRGB2Luv, inv_code = CV_Luv2LRGB; } double CV_ColorLuvTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) { int depth = CV_MAT_DEPTH(test_mat[i][j].type); - return depth == CV_8U ? 48 : depth == CV_16U ? 32 : 5e-3; + return depth == CV_8U ? 48 : depth == CV_16U ? 32 : 1e-2; } @@ -1480,6 +1496,8 @@ void CV_ColorRGBTest::convert_forward( const CvMat* src, CvMat* dst ) int g = src_row[j*cn + 1] >> g_rshift; int r = src_row[j*cn + (blue_idx^2)] >> 3; ((ushort*)dst_row)[j] = (ushort)(b | (g << 5) | (r << r_lshift)); + if( cn == 4 && src_row[j*4+3] ) + ((ushort*)dst_row)[j] |= 1 << (r_lshift+5); } } } @@ -1558,7 +1576,7 @@ void CV_ColorRGBTest::convert_backward( const CvMat* /*src*/, const CvMat* src, dst_row[j*cn + (blue_idx^2)] = r; if( cn == 4 ) - dst_row[j*cn + 3] = 0; + dst_row[j*cn + 3] = 255; } } else @@ -1575,7 +1593,10 @@ void CV_ColorRGBTest::convert_backward( const CvMat* /*src*/, const CvMat* src, dst_row[j*cn + (blue_idx^2)] = r; if( cn == 4 ) - dst_row[j*cn + 3] = 0; + { + uchar alpha = r_rshift == 11 || (val & 0x8000) != 0 ? 255 : 0; + dst_row[j*cn + 3] = alpha; + } } } } @@ -1596,7 +1617,7 @@ void CV_ColorRGBTest::convert_backward( const CvMat* /*src*/, const CvMat* src, dst_row[j*cn + (blue_idx^2)] = r; if( cn == 4 ) - dst_row[j*cn + 3] = 0; + dst_row[j*cn + 3] = 65535; } } break; @@ -1616,7 +1637,7 @@ void CV_ColorRGBTest::convert_backward( const CvMat* /*src*/, const CvMat* src, dst_row[j*cn + (blue_idx^2)] = r; if( cn == 4 ) - dst_row[j*cn + 3] = 0; + dst_row[j*cn + 3] = 1.f; } } break;