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 
6 #include "precomp.hpp"
7 #include "opencl_kernels_core.hpp"
8 #include "convert.hpp"
9 #include "opencv2/core/openvx/ovx_defs.hpp"
10 
11 /****************************************************************************************\
12 *                                    LUT Transform                                       *
13 \****************************************************************************************/
14 
15 namespace cv
16 {
17 
18 template<typename T> static void
LUT8u_(const uchar * src,const T * lut,T * dst,int len,int cn,int lutcn)19 LUT8u_( const uchar* src, const T* lut, T* dst, int len, int cn, int lutcn )
20 {
21     if( lutcn == 1 )
22     {
23         for( int i = 0; i < len*cn; i++ )
24             dst[i] = lut[src[i]];
25     }
26     else
27     {
28         for( int i = 0; i < len*cn; i += cn )
29             for( int k = 0; k < cn; k++ )
30                 dst[i+k] = lut[src[i+k]*cn+k];
31     }
32 }
33 
LUT8u_8u(const uchar * src,const uchar * lut,uchar * dst,int len,int cn,int lutcn)34 static void LUT8u_8u( const uchar* src, const uchar* lut, uchar* dst, int len, int cn, int lutcn )
35 {
36     LUT8u_( src, lut, dst, len, cn, lutcn );
37 }
38 
LUT8u_8s(const uchar * src,const schar * lut,schar * dst,int len,int cn,int lutcn)39 static void LUT8u_8s( const uchar* src, const schar* lut, schar* dst, int len, int cn, int lutcn )
40 {
41     LUT8u_( src, lut, dst, len, cn, lutcn );
42 }
43 
LUT8u_16u(const uchar * src,const ushort * lut,ushort * dst,int len,int cn,int lutcn)44 static void LUT8u_16u( const uchar* src, const ushort* lut, ushort* dst, int len, int cn, int lutcn )
45 {
46     LUT8u_( src, lut, dst, len, cn, lutcn );
47 }
48 
LUT8u_16s(const uchar * src,const short * lut,short * dst,int len,int cn,int lutcn)49 static void LUT8u_16s( const uchar* src, const short* lut, short* dst, int len, int cn, int lutcn )
50 {
51     LUT8u_( src, lut, dst, len, cn, lutcn );
52 }
53 
LUT8u_32s(const uchar * src,const int * lut,int * dst,int len,int cn,int lutcn)54 static void LUT8u_32s( const uchar* src, const int* lut, int* dst, int len, int cn, int lutcn )
55 {
56     LUT8u_( src, lut, dst, len, cn, lutcn );
57 }
58 
LUT8u_32f(const uchar * src,const float * lut,float * dst,int len,int cn,int lutcn)59 static void LUT8u_32f( const uchar* src, const float* lut, float* dst, int len, int cn, int lutcn )
60 {
61     LUT8u_( src, lut, dst, len, cn, lutcn );
62 }
63 
LUT8u_64f(const uchar * src,const double * lut,double * dst,int len,int cn,int lutcn)64 static void LUT8u_64f( const uchar* src, const double* lut, double* dst, int len, int cn, int lutcn )
65 {
66     LUT8u_( src, lut, dst, len, cn, lutcn );
67 }
68 
69 typedef void (*LUTFunc)( const uchar* src, const uchar* lut, uchar* dst, int len, int cn, int lutcn );
70 
71 static LUTFunc lutTab[] =
72 {
73     (LUTFunc)LUT8u_8u, (LUTFunc)LUT8u_8s, (LUTFunc)LUT8u_16u, (LUTFunc)LUT8u_16s,
74     (LUTFunc)LUT8u_32s, (LUTFunc)LUT8u_32f, (LUTFunc)LUT8u_64f, 0
75 };
76 
77 #ifdef HAVE_OPENCL
78 
ocl_LUT(InputArray _src,InputArray _lut,OutputArray _dst)79 static bool ocl_LUT(InputArray _src, InputArray _lut, OutputArray _dst)
80 {
81     int lcn = _lut.channels(), dcn = _src.channels(), ddepth = _lut.depth();
82 
83     UMat src = _src.getUMat(), lut = _lut.getUMat();
84     _dst.create(src.size(), CV_MAKETYPE(ddepth, dcn));
85     UMat dst = _dst.getUMat();
86     int kercn = lcn == 1 ? std::min(4, ocl::predictOptimalVectorWidth(_src, _dst)) : dcn;
87 
88     ocl::Kernel k("LUT", ocl::core::lut_oclsrc,
89                   format("-D dcn=%d -D lcn=%d -D srcT=%s -D dstT=%s", kercn, lcn,
90                          ocl::typeToStr(src.depth()), ocl::memopTypeToStr(ddepth)));
91     if (k.empty())
92         return false;
93 
94     k.args(ocl::KernelArg::ReadOnlyNoSize(src), ocl::KernelArg::ReadOnlyNoSize(lut),
95         ocl::KernelArg::WriteOnly(dst, dcn, kercn));
96 
97     size_t globalSize[2] = { (size_t)dst.cols * dcn / kercn, ((size_t)dst.rows + 3) / 4 };
98     return k.run(2, globalSize, NULL, false);
99 }
100 
101 #endif
102 
103 #ifdef HAVE_OPENVX
openvx_LUT(Mat src,Mat dst,Mat _lut)104 static bool openvx_LUT(Mat src, Mat dst, Mat _lut)
105 {
106     if (src.type() != CV_8UC1 || dst.type() != src.type() || _lut.type() != src.type() || !_lut.isContinuous())
107         return false;
108 
109     try
110     {
111         ivx::Context ctx = ovx::getOpenVXContext();
112 
113         ivx::Image
114             ia = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
115                 ivx::Image::createAddressing(src.cols, src.rows, 1, (vx_int32)(src.step)), src.data),
116             ib = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
117                 ivx::Image::createAddressing(dst.cols, dst.rows, 1, (vx_int32)(dst.step)), dst.data);
118 
119         ivx::LUT lut = ivx::LUT::create(ctx);
120         lut.copyFrom(_lut);
121         ivx::IVX_CHECK_STATUS(vxuTableLookup(ctx, ia, lut, ib));
122     }
123     catch (const ivx::RuntimeError& e)
124     {
125         VX_DbgThrow(e.what());
126     }
127     catch (const ivx::WrapperError& e)
128     {
129         VX_DbgThrow(e.what());
130     }
131 
132     return true;
133 }
134 #endif
135 
136 #if defined(HAVE_IPP)
137 #if !IPP_DISABLE_PERF_LUT // there are no performance benefits (PR #2653)
138 namespace ipp {
139 
140 class IppLUTParallelBody_LUTC1 : public ParallelLoopBody
141 {
142 public:
143     bool* ok;
144     const Mat& src_;
145     const Mat& lut_;
146     Mat& dst_;
147 
148     int width;
149     size_t elemSize1;
150 
IppLUTParallelBody_LUTC1(const Mat & src,const Mat & lut,Mat & dst,bool * _ok)151     IppLUTParallelBody_LUTC1(const Mat& src, const Mat& lut, Mat& dst, bool* _ok)
152         : ok(_ok), src_(src), lut_(lut), dst_(dst)
153     {
154         width = dst.cols * dst.channels();
155         elemSize1 = CV_ELEM_SIZE1(dst.depth());
156 
157         CV_DbgAssert(elemSize1 == 1 || elemSize1 == 4);
158         *ok = true;
159     }
160 
operator ()(const cv::Range & range) const161     void operator()( const cv::Range& range ) const
162     {
163         if (!*ok)
164             return;
165 
166         const int row0 = range.start;
167         const int row1 = range.end;
168 
169         Mat src = src_.rowRange(row0, row1);
170         Mat dst = dst_.rowRange(row0, row1);
171 
172         IppiSize sz = { width, dst.rows };
173 
174         if (elemSize1 == 1)
175         {
176             if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u_C1R, (const Ipp8u*)src.data, (int)src.step[0], dst.data, (int)dst.step[0], sz, lut_.data, 8) >= 0)
177                 return;
178         }
179         else if (elemSize1 == 4)
180         {
181             if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u32u_C1R, (const Ipp8u*)src.data, (int)src.step[0], (Ipp32u*)dst.data, (int)dst.step[0], sz, (Ipp32u*)lut_.data, 8) >= 0)
182                 return;
183         }
184         *ok = false;
185     }
186 private:
187     IppLUTParallelBody_LUTC1(const IppLUTParallelBody_LUTC1&);
188     IppLUTParallelBody_LUTC1& operator=(const IppLUTParallelBody_LUTC1&);
189 };
190 
191 class IppLUTParallelBody_LUTCN : public ParallelLoopBody
192 {
193 public:
194     bool *ok;
195     const Mat& src_;
196     const Mat& lut_;
197     Mat& dst_;
198 
199     int lutcn;
200 
201     uchar* lutBuffer;
202     uchar* lutTable[4];
203 
IppLUTParallelBody_LUTCN(const Mat & src,const Mat & lut,Mat & dst,bool * _ok)204     IppLUTParallelBody_LUTCN(const Mat& src, const Mat& lut, Mat& dst, bool* _ok)
205         : ok(_ok), src_(src), lut_(lut), dst_(dst), lutBuffer(NULL)
206     {
207         lutcn = lut.channels();
208         IppiSize sz256 = {256, 1};
209 
210         size_t elemSize1 = dst.elemSize1();
211         CV_DbgAssert(elemSize1 == 1);
212         lutBuffer = (uchar*)CV_IPP_MALLOC(256 * (int)elemSize1 * 4);
213         lutTable[0] = lutBuffer + 0;
214         lutTable[1] = lutBuffer + 1 * 256 * elemSize1;
215         lutTable[2] = lutBuffer + 2 * 256 * elemSize1;
216         lutTable[3] = lutBuffer + 3 * 256 * elemSize1;
217 
218         CV_DbgAssert(lutcn == 3 || lutcn == 4);
219         if (lutcn == 3)
220         {
221             IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C3P3R, lut.ptr(), (int)lut.step[0], lutTable, (int)lut.step[0], sz256);
222             if (status < 0)
223                 return;
224         }
225         else if (lutcn == 4)
226         {
227             IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C4P4R, lut.ptr(), (int)lut.step[0], lutTable, (int)lut.step[0], sz256);
228             if (status < 0)
229                 return;
230         }
231 
232         *ok = true;
233     }
234 
~IppLUTParallelBody_LUTCN()235     ~IppLUTParallelBody_LUTCN()
236     {
237         if (lutBuffer != NULL)
238             ippFree(lutBuffer);
239         lutBuffer = NULL;
240         lutTable[0] = NULL;
241     }
242 
operator ()(const cv::Range & range) const243     void operator()( const cv::Range& range ) const
244     {
245         if (!*ok)
246             return;
247 
248         const int row0 = range.start;
249         const int row1 = range.end;
250 
251         Mat src = src_.rowRange(row0, row1);
252         Mat dst = dst_.rowRange(row0, row1);
253 
254         if (lutcn == 3)
255         {
256             if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u_C3R, src.ptr(), (int)src.step[0], dst.ptr(), (int)dst.step[0], ippiSize(dst.size()), lutTable, 8) >= 0)
257                 return;
258         }
259         else if (lutcn == 4)
260         {
261             if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u_C4R, src.ptr(), (int)src.step[0], dst.ptr(), (int)dst.step[0], ippiSize(dst.size()), lutTable, 8) >= 0)
262                 return;
263         }
264         *ok = false;
265     }
266 private:
267     IppLUTParallelBody_LUTCN(const IppLUTParallelBody_LUTCN&);
268     IppLUTParallelBody_LUTCN& operator=(const IppLUTParallelBody_LUTCN&);
269 };
270 } // namespace ipp
271 
ipp_lut(Mat & src,Mat & lut,Mat & dst)272 static bool ipp_lut(Mat &src, Mat &lut, Mat &dst)
273 {
274     CV_INSTRUMENT_REGION_IPP();
275 
276     int lutcn = lut.channels();
277 
278     if(src.dims > 2)
279         return false;
280 
281     bool ok = false;
282     Ptr<ParallelLoopBody> body;
283 
284     size_t elemSize1 = CV_ELEM_SIZE1(dst.depth());
285 
286     if (lutcn == 1)
287     {
288         ParallelLoopBody* p = new ipp::IppLUTParallelBody_LUTC1(src, lut, dst, &ok);
289         body.reset(p);
290     }
291     else if ((lutcn == 3 || lutcn == 4) && elemSize1 == 1)
292     {
293         ParallelLoopBody* p = new ipp::IppLUTParallelBody_LUTCN(src, lut, dst, &ok);
294         body.reset(p);
295     }
296 
297     if (body != NULL && ok)
298     {
299         Range all(0, dst.rows);
300         if (dst.total()>>18)
301             parallel_for_(all, *body, (double)std::max((size_t)1, dst.total()>>16));
302         else
303             (*body)(all);
304         if (ok)
305             return true;
306     }
307 
308     return false;
309 }
310 
311 #endif
312 #endif // IPP
313 
314 class LUTParallelBody : public ParallelLoopBody
315 {
316 public:
317     bool* ok;
318     const Mat& src_;
319     const Mat& lut_;
320     Mat& dst_;
321 
322     LUTFunc func;
323 
LUTParallelBody(const Mat & src,const Mat & lut,Mat & dst,bool * _ok)324     LUTParallelBody(const Mat& src, const Mat& lut, Mat& dst, bool* _ok)
325         : ok(_ok), src_(src), lut_(lut), dst_(dst)
326     {
327         func = lutTab[lut.depth()];
328         *ok = (func != NULL);
329     }
330 
operator ()(const cv::Range & range) const331     void operator()( const cv::Range& range ) const CV_OVERRIDE
332     {
333         CV_DbgAssert(*ok);
334 
335         const int row0 = range.start;
336         const int row1 = range.end;
337 
338         Mat src = src_.rowRange(row0, row1);
339         Mat dst = dst_.rowRange(row0, row1);
340 
341         int cn = src.channels();
342         int lutcn = lut_.channels();
343 
344         const Mat* arrays[] = {&src, &dst, 0};
345         uchar* ptrs[2] = {};
346         NAryMatIterator it(arrays, ptrs);
347         int len = (int)it.size;
348 
349         for( size_t i = 0; i < it.nplanes; i++, ++it )
350             func(ptrs[0], lut_.ptr(), ptrs[1], len, cn, lutcn);
351     }
352 private:
353     LUTParallelBody(const LUTParallelBody&);
354     LUTParallelBody& operator=(const LUTParallelBody&);
355 };
356 
357 } // cv::
358 
LUT(InputArray _src,InputArray _lut,OutputArray _dst)359 void cv::LUT( InputArray _src, InputArray _lut, OutputArray _dst )
360 {
361     CV_INSTRUMENT_REGION();
362 
363     int cn = _src.channels(), depth = _src.depth();
364     int lutcn = _lut.channels();
365 
366     CV_Assert( (lutcn == cn || lutcn == 1) &&
367         _lut.total() == 256 && _lut.isContinuous() &&
368         (depth == CV_8U || depth == CV_8S) );
369 
370     CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2,
371                ocl_LUT(_src, _lut, _dst))
372 
373     Mat src = _src.getMat(), lut = _lut.getMat();
374     _dst.create(src.dims, src.size, CV_MAKETYPE(_lut.depth(), cn));
375     Mat dst = _dst.getMat();
376 
377     CV_OVX_RUN(!ovx::skipSmallImages<VX_KERNEL_TABLE_LOOKUP>(src.cols, src.rows),
378                openvx_LUT(src, dst, lut))
379 
380 #if !IPP_DISABLE_PERF_LUT
381     CV_IPP_RUN(_src.dims() <= 2, ipp_lut(src, lut, dst));
382 #endif
383 
384     if (_src.dims() <= 2)
385     {
386         bool ok = false;
387         LUTParallelBody body(src, lut, dst, &ok);
388         if (ok)
389         {
390             Range all(0, dst.rows);
391             if (dst.total() >= (size_t)(1<<18))
392                 parallel_for_(all, body, (double)std::max((size_t)1, dst.total()>>16));
393             else
394                 body(all);
395             if (ok)
396                 return;
397         }
398     }
399 
400     LUTFunc func = lutTab[lut.depth()];
401     CV_Assert( func != 0 );
402 
403     const Mat* arrays[] = {&src, &dst, 0};
404     uchar* ptrs[2] = {};
405     NAryMatIterator it(arrays, ptrs);
406     int len = (int)it.size;
407 
408     for( size_t i = 0; i < it.nplanes; i++, ++it )
409         func(ptrs[0], lut.ptr(), ptrs[1], len, cn, lutcn);
410 }
411