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_Check(scn, VScn::contains(scn), "Invalid number of channels in input image" ); |
93 | CV_Check(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 | |