| 1 | // This file is part of OpenCV project. |
| 2 | // It is subject to the license terms in the LICENSE file found in the top-level directory |
| 3 | // of this distribution and at http://opencv.org/license.html |
| 4 | |
| 5 | #define CV_DESCALE(x,n) (((x) + (1 << ((n)-1))) >> (n)) |
| 6 | |
| 7 | namespace { |
| 8 | |
| 9 | //constants for conversion from/to RGB and Gray, YUV, YCrCb according to BT.601 |
| 10 | static const float B2YF = 0.114f; |
| 11 | static const float G2YF = 0.587f; |
| 12 | static const float R2YF = 0.299f; |
| 13 | |
| 14 | enum |
| 15 | { |
| 16 | gray_shift = 15, |
| 17 | yuv_shift = 14, |
| 18 | xyz_shift = 12, |
| 19 | R2Y = 4899, // == R2YF*16384 |
| 20 | G2Y = 9617, // == G2YF*16384 |
| 21 | B2Y = 1868, // == B2YF*16384 |
| 22 | RY15 = 9798, // == R2YF*32768 + 0.5 |
| 23 | GY15 = 19235, // == G2YF*32768 + 0.5 |
| 24 | BY15 = 3735, // == B2YF*32768 + 0.5 |
| 25 | BLOCK_SIZE = 256 |
| 26 | }; |
| 27 | |
| 28 | template<typename _Tp> struct ColorChannel |
| 29 | { |
| 30 | typedef float worktype_f; |
| 31 | static inline _Tp max() { return std::numeric_limits<_Tp>::max(); } |
| 32 | static inline _Tp half() { return (_Tp)(max()/2 + 1); } |
| 33 | }; |
| 34 | |
| 35 | template<> struct ColorChannel<float> |
| 36 | { |
| 37 | typedef float worktype_f; |
| 38 | static inline float max() { return 1.f; } |
| 39 | static inline float half() { return 0.5f; } |
| 40 | }; |
| 41 | |
| 42 | /*template<> struct ColorChannel<double> |
| 43 | { |
| 44 | typedef double worktype_f; |
| 45 | static double max() { return 1.; } |
| 46 | static double half() { return 0.5; } |
| 47 | };*/ |
| 48 | |
| 49 | |
| 50 | template<int i0, int i1 = -1, int i2 = -1> |
| 51 | struct Set |
| 52 | { |
| 53 | static inline bool contains(int i) |
| 54 | { |
| 55 | return (i == i0 || i == i1 || i == i2); |
| 56 | } |
| 57 | }; |
| 58 | |
| 59 | template<int i0, int i1> |
| 60 | struct Set<i0, i1, -1> |
| 61 | { |
| 62 | static inline bool contains(int i) |
| 63 | { |
| 64 | return (i == i0 || i == i1); |
| 65 | } |
| 66 | }; |
| 67 | |
| 68 | template<int i0> |
| 69 | struct Set<i0, -1, -1> |
| 70 | { |
| 71 | static inline bool contains(int i) |
| 72 | { |
| 73 | return (i == i0); |
| 74 | } |
| 75 | }; |
| 76 | |
| 77 | enum SizePolicy |
| 78 | { |
| 79 | TO_YUV, FROM_YUV, FROM_UYVY, TO_UYVY, NONE |
| 80 | }; |
| 81 | |
| 82 | template< typename VScn, typename VDcn, typename VDepth, SizePolicy sizePolicy = NONE > |
| 83 | struct CvtHelper |
| 84 | { |
| 85 | CvtHelper(InputArray _src, OutputArray _dst, int dcn) |
| 86 | { |
| 87 | CV_Assert(!_src.empty()); |
| 88 | |
| 89 | int stype = _src.type(); |
| 90 | scn = CV_MAT_CN(stype), depth = CV_MAT_DEPTH(stype); |
| 91 | |
| 92 | CV_CheckChannels(scn, VScn::contains(scn), "Invalid number of channels in input image" ); |
| 93 | CV_CheckChannels(dcn, VDcn::contains(dcn), "Invalid number of channels in output image" ); |
| 94 | CV_CheckDepth(depth, VDepth::contains(depth), "Unsupported depth of input image" ); |
| 95 | |
| 96 | if (_src.getObj() == _dst.getObj()) // inplace processing (#6653) |
| 97 | _src.copyTo(arr: src); |
| 98 | else |
| 99 | src = _src.getMat(); |
| 100 | Size sz = src.size(); |
| 101 | switch (sizePolicy) |
| 102 | { |
| 103 | case TO_YUV: |
| 104 | CV_Assert( sz.width % 2 == 0 && sz.height % 2 == 0); |
| 105 | dstSz = Size(sz.width, sz.height / 2 * 3); |
| 106 | break; |
| 107 | case FROM_YUV: |
| 108 | CV_Assert( sz.width % 2 == 0 && sz.height % 3 == 0); |
| 109 | dstSz = Size(sz.width, sz.height * 2 / 3); |
| 110 | break; |
| 111 | case FROM_UYVY: |
| 112 | case TO_UYVY: |
| 113 | CV_Assert( sz.width % 2 == 0); |
| 114 | dstSz = sz; |
| 115 | break; |
| 116 | case NONE: |
| 117 | default: |
| 118 | dstSz = sz; |
| 119 | break; |
| 120 | } |
| 121 | _dst.create(sz: dstSz, CV_MAKETYPE(depth, dcn)); |
| 122 | dst = _dst.getMat(); |
| 123 | } |
| 124 | Mat src, dst; |
| 125 | int depth, scn; |
| 126 | Size dstSz; |
| 127 | }; |
| 128 | |
| 129 | |
| 130 | ///////////////////////////// Top-level template function //////////////////////////////// |
| 131 | |
| 132 | template <typename Cvt> |
| 133 | class CvtColorLoop_Invoker : public ParallelLoopBody |
| 134 | { |
| 135 | typedef typename Cvt::channel_type _Tp; |
| 136 | public: |
| 137 | |
| 138 | CvtColorLoop_Invoker(const uchar * src_data_, size_t src_step_, uchar * dst_data_, size_t dst_step_, int width_, const Cvt& _cvt) : |
| 139 | ParallelLoopBody(), src_data(src_data_), src_step(src_step_), dst_data(dst_data_), dst_step(dst_step_), |
| 140 | width(width_), cvt(_cvt) |
| 141 | { |
| 142 | } |
| 143 | |
| 144 | virtual void operator()(const Range& range) const CV_OVERRIDE |
| 145 | { |
| 146 | CV_TRACE_FUNCTION(); |
| 147 | |
| 148 | const uchar* yS = src_data + static_cast<size_t>(range.start) * src_step; |
| 149 | uchar* yD = dst_data + static_cast<size_t>(range.start) * dst_step; |
| 150 | |
| 151 | for( int i = range.start; i < range.end; ++i, yS += src_step, yD += dst_step ) |
| 152 | cvt(reinterpret_cast<const _Tp*>(yS), reinterpret_cast<_Tp*>(yD), width); |
| 153 | } |
| 154 | |
| 155 | private: |
| 156 | const uchar * src_data; |
| 157 | const size_t src_step; |
| 158 | uchar * dst_data; |
| 159 | const size_t dst_step; |
| 160 | const int width; |
| 161 | const Cvt& cvt; |
| 162 | |
| 163 | CvtColorLoop_Invoker(const CvtColorLoop_Invoker&); // = delete; |
| 164 | const CvtColorLoop_Invoker& operator= (const CvtColorLoop_Invoker&); // = delete; |
| 165 | }; |
| 166 | |
| 167 | template <typename Cvt> static inline |
| 168 | void CvtColorLoop(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, const Cvt& cvt) |
| 169 | { |
| 170 | CV_AVX_GUARD |
| 171 | parallel_for_(Range(0, height), |
| 172 | CvtColorLoop_Invoker<Cvt>(src_data, src_step, dst_data, dst_step, width, cvt), |
| 173 | (width * height) / static_cast<double>(1<<16)); |
| 174 | } |
| 175 | |
| 176 | } //namespace |
| 177 | |