1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
8 //
9 //
10 // License Agreement
11 // For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
15 // Copyright (C) 2014-2015, Itseez Inc., all rights reserved.
16 // Third party copyrights are property of their respective owners.
17 //
18 // Redistribution and use in source and binary forms, with or without modification,
19 // are permitted provided that the following conditions are met:
20 //
21 // * Redistribution's of source code must retain the above copyright notice,
22 // this list of conditions and the following disclaimer.
23 //
24 // * Redistribution's in binary form must reproduce the above copyright notice,
25 // this list of conditions and the following disclaimer in the documentation
26 // and/or other materials provided with the distribution.
27 //
28 // * The name of the copyright holders may not be used to endorse or promote products
29 // derived from this software without specific prior written permission.
30 //
31 // This software is provided by the copyright holders and contributors "as is" and
32 // any express or implied warranties, including, but not limited to, the implied
33 // warranties of merchantability and fitness for a particular purpose are disclaimed.
34 // In no event shall the Intel Corporation or contributors be liable for any direct,
35 // indirect, incidental, special, exemplary, or consequential damages
36 // (including, but not limited to, procurement of substitute goods or services;
37 // loss of use, data, or profits; or business interruption) however caused
38 // and on any theory of liability, whether in contract, strict liability,
39 // or tort (including negligence or otherwise) arising in any way out of
40 // the use of this software, even if advised of the possibility of such damage.
41 //
42 //M*/
43
44 /* ////////////////////////////////////////////////////////////////////
45 //
46 // Arithmetic and logical operations: +, -, *, /, &, |, ^, ~, abs ...
47 //
48 // */
49
50 #include "precomp.hpp"
51 #include "opencl_kernels_core.hpp"
52
53 namespace cv
54 {
55
56 /****************************************************************************************\
57 * logical operations *
58 \****************************************************************************************/
59
60 enum { OCL_OP_ADD=0, OCL_OP_SUB=1, OCL_OP_RSUB=2, OCL_OP_ABSDIFF=3, OCL_OP_MUL=4,
61 OCL_OP_MUL_SCALE=5, OCL_OP_DIV_SCALE=6, OCL_OP_RECIP_SCALE=7, OCL_OP_ADDW=8,
62 OCL_OP_AND=9, OCL_OP_OR=10, OCL_OP_XOR=11, OCL_OP_NOT=12, OCL_OP_MIN=13, OCL_OP_MAX=14,
63 OCL_OP_RDIV_SCALE=15 };
64
65 #ifdef HAVE_OPENCL
66
67 static const char* oclop2str[] = { "OP_ADD", "OP_SUB", "OP_RSUB", "OP_ABSDIFF",
68 "OP_MUL", "OP_MUL_SCALE", "OP_DIV_SCALE", "OP_RECIP_SCALE",
69 "OP_ADDW", "OP_AND", "OP_OR", "OP_XOR", "OP_NOT", "OP_MIN", "OP_MAX", "OP_RDIV_SCALE", 0 };
70
ocl_binary_op(InputArray _src1,InputArray _src2,OutputArray _dst,InputArray _mask,bool bitwise,int oclop,bool haveScalar)71 static bool ocl_binary_op(InputArray _src1, InputArray _src2, OutputArray _dst,
72 InputArray _mask, bool bitwise, int oclop, bool haveScalar )
73 {
74 bool haveMask = !_mask.empty();
75 int srctype = _src1.type();
76 int srcdepth = CV_MAT_DEPTH(srctype);
77 int cn = CV_MAT_CN(srctype);
78
79 const ocl::Device d = ocl::Device::getDefault();
80 bool doubleSupport = d.doubleFPConfig() > 0;
81 if( oclop < 0 || ((haveMask || haveScalar) && cn > 4) ||
82 (!doubleSupport && srcdepth == CV_64F && !bitwise))
83 return false;
84
85 char opts[1024];
86 int kercn = haveMask || haveScalar ? cn : ocl::predictOptimalVectorWidth(_src1, _src2, _dst);
87 int scalarcn = kercn == 3 ? 4 : kercn;
88 int rowsPerWI = d.isIntel() ? 4 : 1;
89
90 const int dstDepth = srcdepth;
91 const int dstType = CV_MAKETYPE(dstDepth, kercn);
92 const int dstType1 = CV_MAKETYPE(dstDepth, 1);
93 const int scalarType = CV_MAKETYPE(srcdepth, scalarcn);
94
95 sprintf(opts, "-D %s%s -D %s%s -D dstT=%s -D DEPTH_dst=%d -D dstT_C1=%s -D workST=%s -D cn=%d -D rowsPerWI=%d",
96 haveMask ? "MASK_" : "", haveScalar ? "UNARY_OP" : "BINARY_OP", oclop2str[oclop],
97 doubleSupport ? " -D DOUBLE_SUPPORT" : "",
98 bitwise ? ocl::memopTypeToStr(dstType) : ocl::typeToStr(dstType),
99 dstDepth,
100 bitwise ? ocl::memopTypeToStr(dstType1) : ocl::typeToStr(dstType1),
101 bitwise ? ocl::memopTypeToStr(scalarType) : ocl::typeToStr(scalarType),
102 kercn, rowsPerWI);
103
104 ocl::Kernel k("KF", ocl::core::arithm_oclsrc, opts);
105 if (k.empty())
106 return false;
107
108 UMat src1 = _src1.getUMat(), src2;
109 UMat dst = _dst.getUMat(), mask = _mask.getUMat();
110
111 ocl::KernelArg src1arg = ocl::KernelArg::ReadOnlyNoSize(src1, cn, kercn);
112 ocl::KernelArg dstarg = haveMask ? ocl::KernelArg::ReadWrite(dst, cn, kercn) :
113 ocl::KernelArg::WriteOnly(dst, cn, kercn);
114 ocl::KernelArg maskarg = ocl::KernelArg::ReadOnlyNoSize(mask, 1);
115
116 if( haveScalar )
117 {
118 size_t esz = CV_ELEM_SIZE1(srctype)*scalarcn;
119 double buf[4] = {0,0,0,0};
120
121 if( oclop != OCL_OP_NOT )
122 {
123 Mat src2sc = _src2.getMat();
124 convertAndUnrollScalar(src2sc, srctype, (uchar*)buf, 1);
125 }
126
127 ocl::KernelArg scalararg = ocl::KernelArg(ocl::KernelArg::CONSTANT, 0, 0, 0, buf, esz);
128
129 if( !haveMask )
130 k.args(src1arg, dstarg, scalararg);
131 else
132 k.args(src1arg, maskarg, dstarg, scalararg);
133 }
134 else
135 {
136 src2 = _src2.getUMat();
137 ocl::KernelArg src2arg = ocl::KernelArg::ReadOnlyNoSize(src2, cn, kercn);
138
139 if( !haveMask )
140 k.args(src1arg, src2arg, dstarg);
141 else
142 k.args(src1arg, src2arg, maskarg, dstarg);
143 }
144
145 size_t globalsize[] = { (size_t)src1.cols * cn / kercn, ((size_t)src1.rows + rowsPerWI - 1) / rowsPerWI };
146 return k.run(2, globalsize, 0, false);
147 }
148
149 #endif
150
binary_op(InputArray _src1,InputArray _src2,OutputArray _dst,InputArray _mask,const BinaryFuncC * tab,bool bitwise,int oclop)151 static void binary_op( InputArray _src1, InputArray _src2, OutputArray _dst,
152 InputArray _mask, const BinaryFuncC* tab,
153 bool bitwise, int oclop )
154 {
155 const _InputArray *psrc1 = &_src1, *psrc2 = &_src2;
156 _InputArray::KindFlag kind1 = psrc1->kind(), kind2 = psrc2->kind();
157 int type1 = psrc1->type(), depth1 = CV_MAT_DEPTH(type1), cn = CV_MAT_CN(type1);
158 int type2 = psrc2->type(), depth2 = CV_MAT_DEPTH(type2), cn2 = CV_MAT_CN(type2);
159 int dims1 = psrc1->dims(), dims2 = psrc2->dims();
160 Size sz1 = dims1 <= 2 ? psrc1->size() : Size();
161 Size sz2 = dims2 <= 2 ? psrc2->size() : Size();
162 #ifdef HAVE_OPENCL
163 bool use_opencl = (kind1 == _InputArray::UMAT || kind2 == _InputArray::UMAT) &&
164 dims1 <= 2 && dims2 <= 2;
165 #endif
166 bool haveMask = !_mask.empty(), haveScalar = false;
167 BinaryFuncC func;
168
169 if( dims1 <= 2 && dims2 <= 2 && kind1 == kind2 && sz1 == sz2 && type1 == type2 && !haveMask )
170 {
171 _dst.create(sz1, type1);
172 CV_OCL_RUN(use_opencl,
173 ocl_binary_op(*psrc1, *psrc2, _dst, _mask, bitwise, oclop, false))
174
175 if( bitwise )
176 {
177 func = *tab;
178 cn = (int)CV_ELEM_SIZE(type1);
179 }
180 else
181 {
182 func = tab[depth1];
183 }
184 CV_Assert(func);
185
186 Mat src1 = psrc1->getMat(), src2 = psrc2->getMat(), dst = _dst.getMat();
187 Size sz = getContinuousSize2D(src1, src2, dst);
188 size_t len = sz.width*(size_t)cn;
189 if (len < INT_MAX) // FIXIT similar code below doesn't have that check
190 {
191 sz.width = (int)len;
192 func(src1.ptr(), src1.step, src2.ptr(), src2.step, dst.ptr(), dst.step, sz.width, sz.height, 0);
193 return;
194 }
195 }
196
197 if( oclop == OCL_OP_NOT )
198 haveScalar = true;
199 else if( (kind1 == _InputArray::MATX) + (kind2 == _InputArray::MATX) == 1 ||
200 !psrc1->sameSize(*psrc2) || type1 != type2 )
201 {
202 if( checkScalar(*psrc1, type2, kind1, kind2) )
203 {
204 // src1 is a scalar; swap it with src2
205 swap(psrc1, psrc2);
206 swap(type1, type2);
207 swap(depth1, depth2);
208 swap(cn, cn2);
209 swap(sz1, sz2);
210 }
211 else if( !checkScalar(*psrc2, type1, kind2, kind1) )
212 CV_Error( CV_StsUnmatchedSizes,
213 "The operation is neither 'array op array' (where arrays have the same size and type), "
214 "nor 'array op scalar', nor 'scalar op array'" );
215 haveScalar = true;
216 }
217 else
218 {
219 CV_Assert( psrc1->sameSize(*psrc2) && type1 == type2 );
220 }
221
222 size_t esz = CV_ELEM_SIZE(type1);
223 size_t blocksize0 = (BLOCK_SIZE + esz-1)/esz;
224 BinaryFunc copymask = 0;
225 bool reallocate = false;
226
227 if( haveMask )
228 {
229 int mtype = _mask.type();
230 CV_Assert( (mtype == CV_8U || mtype == CV_8S) && _mask.sameSize(*psrc1));
231 copymask = getCopyMaskFunc(esz);
232 reallocate = !_dst.sameSize(*psrc1) || _dst.type() != type1;
233 }
234
235 AutoBuffer<uchar> _buf;
236 uchar *scbuf = 0, *maskbuf = 0;
237
238 _dst.createSameSize(*psrc1, type1);
239 // if this is mask operation and dst has been reallocated,
240 // we have to clear the destination
241 if( haveMask && reallocate )
242 _dst.setTo(0.);
243
244 CV_OCL_RUN(use_opencl,
245 ocl_binary_op(*psrc1, *psrc2, _dst, _mask, bitwise, oclop, haveScalar))
246
247
248 Mat src1 = psrc1->getMat(), src2 = psrc2->getMat();
249 Mat dst = _dst.getMat(), mask = _mask.getMat();
250
251 if( bitwise )
252 {
253 func = *tab;
254 cn = (int)esz;
255 }
256 else
257 func = tab[depth1];
258 CV_Assert(func);
259
260 if( !haveScalar )
261 {
262 const Mat* arrays[] = { &src1, &src2, &dst, &mask, 0 };
263 uchar* ptrs[4] = {};
264
265 NAryMatIterator it(arrays, ptrs);
266 size_t total = it.size, blocksize = total;
267
268 if( blocksize*cn > INT_MAX )
269 blocksize = INT_MAX/cn;
270
271 if( haveMask )
272 {
273 blocksize = std::min(blocksize, blocksize0);
274 _buf.allocate(blocksize*esz);
275 maskbuf = _buf.data();
276 }
277
278 for( size_t i = 0; i < it.nplanes; i++, ++it )
279 {
280 for( size_t j = 0; j < total; j += blocksize )
281 {
282 int bsz = (int)MIN(total - j, blocksize);
283
284 func( ptrs[0], 0, ptrs[1], 0, haveMask ? maskbuf : ptrs[2], 0, bsz*cn, 1, 0 );
285 if( haveMask )
286 {
287 copymask( maskbuf, 0, ptrs[3], 0, ptrs[2], 0, Size(bsz, 1), &esz );
288 ptrs[3] += bsz;
289 }
290
291 bsz *= (int)esz;
292 ptrs[0] += bsz; ptrs[1] += bsz; ptrs[2] += bsz;
293 }
294 }
295 }
296 else
297 {
298 const Mat* arrays[] = { &src1, &dst, &mask, 0 };
299 uchar* ptrs[3] = {};
300
301 NAryMatIterator it(arrays, ptrs);
302 size_t total = it.size, blocksize = std::min(total, blocksize0);
303
304 _buf.allocate(blocksize*(haveMask ? 2 : 1)*esz + 32);
305 scbuf = _buf.data();
306 maskbuf = alignPtr(scbuf + blocksize*esz, 16);
307
308 convertAndUnrollScalar( src2, src1.type(), scbuf, blocksize);
309
310 for( size_t i = 0; i < it.nplanes; i++, ++it )
311 {
312 for( size_t j = 0; j < total; j += blocksize )
313 {
314 int bsz = (int)MIN(total - j, blocksize);
315
316 func( ptrs[0], 0, scbuf, 0, haveMask ? maskbuf : ptrs[1], 0, bsz*cn, 1, 0 );
317 if( haveMask )
318 {
319 copymask( maskbuf, 0, ptrs[2], 0, ptrs[1], 0, Size(bsz, 1), &esz );
320 ptrs[2] += bsz;
321 }
322
323 bsz *= (int)esz;
324 ptrs[0] += bsz; ptrs[1] += bsz;
325 }
326 }
327 }
328 }
329
getMaxTab()330 static BinaryFuncC* getMaxTab()
331 {
332 static BinaryFuncC maxTab[] =
333 {
334 (BinaryFuncC)GET_OPTIMIZED(cv::hal::max8u), (BinaryFuncC)GET_OPTIMIZED(cv::hal::max8s),
335 (BinaryFuncC)GET_OPTIMIZED(cv::hal::max16u), (BinaryFuncC)GET_OPTIMIZED(cv::hal::max16s),
336 (BinaryFuncC)GET_OPTIMIZED(cv::hal::max32s),
337 (BinaryFuncC)GET_OPTIMIZED(cv::hal::max32f), (BinaryFuncC)cv::hal::max64f,
338 0
339 };
340
341 return maxTab;
342 }
343
getMinTab()344 static BinaryFuncC* getMinTab()
345 {
346 static BinaryFuncC minTab[] =
347 {
348 (BinaryFuncC)GET_OPTIMIZED(cv::hal::min8u), (BinaryFuncC)GET_OPTIMIZED(cv::hal::min8s),
349 (BinaryFuncC)GET_OPTIMIZED(cv::hal::min16u), (BinaryFuncC)GET_OPTIMIZED(cv::hal::min16s),
350 (BinaryFuncC)GET_OPTIMIZED(cv::hal::min32s),
351 (BinaryFuncC)GET_OPTIMIZED(cv::hal::min32f), (BinaryFuncC)cv::hal::min64f,
352 0
353 };
354
355 return minTab;
356 }
357
358 }
359
bitwise_and(InputArray a,InputArray b,OutputArray c,InputArray mask)360 void cv::bitwise_and(InputArray a, InputArray b, OutputArray c, InputArray mask)
361 {
362 CV_INSTRUMENT_REGION();
363
364 BinaryFuncC f = (BinaryFuncC)GET_OPTIMIZED(cv::hal::and8u);
365 binary_op(a, b, c, mask, &f, true, OCL_OP_AND);
366 }
367
bitwise_or(InputArray a,InputArray b,OutputArray c,InputArray mask)368 void cv::bitwise_or(InputArray a, InputArray b, OutputArray c, InputArray mask)
369 {
370 CV_INSTRUMENT_REGION();
371
372 BinaryFuncC f = (BinaryFuncC)GET_OPTIMIZED(cv::hal::or8u);
373 binary_op(a, b, c, mask, &f, true, OCL_OP_OR);
374 }
375
bitwise_xor(InputArray a,InputArray b,OutputArray c,InputArray mask)376 void cv::bitwise_xor(InputArray a, InputArray b, OutputArray c, InputArray mask)
377 {
378 CV_INSTRUMENT_REGION();
379
380 BinaryFuncC f = (BinaryFuncC)GET_OPTIMIZED(cv::hal::xor8u);
381 binary_op(a, b, c, mask, &f, true, OCL_OP_XOR);
382 }
383
bitwise_not(InputArray a,OutputArray c,InputArray mask)384 void cv::bitwise_not(InputArray a, OutputArray c, InputArray mask)
385 {
386 CV_INSTRUMENT_REGION();
387
388 BinaryFuncC f = (BinaryFuncC)GET_OPTIMIZED(cv::hal::not8u);
389 binary_op(a, a, c, mask, &f, true, OCL_OP_NOT);
390 }
391
max(InputArray src1,InputArray src2,OutputArray dst)392 void cv::max( InputArray src1, InputArray src2, OutputArray dst )
393 {
394 CV_INSTRUMENT_REGION();
395
396 binary_op(src1, src2, dst, noArray(), getMaxTab(), false, OCL_OP_MAX );
397 }
398
min(InputArray src1,InputArray src2,OutputArray dst)399 void cv::min( InputArray src1, InputArray src2, OutputArray dst )
400 {
401 CV_INSTRUMENT_REGION();
402
403 binary_op(src1, src2, dst, noArray(), getMinTab(), false, OCL_OP_MIN );
404 }
405
max(const Mat & src1,const Mat & src2,Mat & dst)406 void cv::max(const Mat& src1, const Mat& src2, Mat& dst)
407 {
408 CV_INSTRUMENT_REGION();
409
410 OutputArray _dst(dst);
411 binary_op(src1, src2, _dst, noArray(), getMaxTab(), false, OCL_OP_MAX );
412 }
413
min(const Mat & src1,const Mat & src2,Mat & dst)414 void cv::min(const Mat& src1, const Mat& src2, Mat& dst)
415 {
416 CV_INSTRUMENT_REGION();
417
418 OutputArray _dst(dst);
419 binary_op(src1, src2, _dst, noArray(), getMinTab(), false, OCL_OP_MIN );
420 }
421
max(const UMat & src1,const UMat & src2,UMat & dst)422 void cv::max(const UMat& src1, const UMat& src2, UMat& dst)
423 {
424 CV_INSTRUMENT_REGION();
425
426 OutputArray _dst(dst);
427 binary_op(src1, src2, _dst, noArray(), getMaxTab(), false, OCL_OP_MAX );
428 }
429
min(const UMat & src1,const UMat & src2,UMat & dst)430 void cv::min(const UMat& src1, const UMat& src2, UMat& dst)
431 {
432 CV_INSTRUMENT_REGION();
433
434 OutputArray _dst(dst);
435 binary_op(src1, src2, _dst, noArray(), getMinTab(), false, OCL_OP_MIN );
436 }
437
438
439 /****************************************************************************************\
440 * add/subtract *
441 \****************************************************************************************/
442
443 namespace cv
444 {
445
actualScalarDepth(const double * data,int len)446 static int actualScalarDepth(const double* data, int len)
447 {
448 int i = 0, minval = INT_MAX, maxval = INT_MIN;
449 for(; i < len; ++i)
450 {
451 int ival = cvRound(data[i]);
452 if( ival != data[i] )
453 break;
454 minval = MIN(minval, ival);
455 maxval = MAX(maxval, ival);
456 }
457 return i < len ? CV_64F :
458 minval >= 0 && maxval <= (int)UCHAR_MAX ? CV_8U :
459 minval >= (int)SCHAR_MIN && maxval <= (int)SCHAR_MAX ? CV_8S :
460 minval >= 0 && maxval <= (int)USHRT_MAX ? CV_16U :
461 minval >= (int)SHRT_MIN && maxval <= (int)SHRT_MAX ? CV_16S :
462 CV_32S;
463 }
464
465 #ifdef HAVE_OPENCL
466
ocl_arithm_op(InputArray _src1,InputArray _src2,OutputArray _dst,InputArray _mask,int wtype,void * usrdata,int oclop,bool haveScalar)467 static bool ocl_arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst,
468 InputArray _mask, int wtype,
469 void* usrdata, int oclop,
470 bool haveScalar )
471 {
472 const ocl::Device d = ocl::Device::getDefault();
473 bool doubleSupport = d.doubleFPConfig() > 0;
474 int type1 = _src1.type(), depth1 = CV_MAT_DEPTH(type1), cn = CV_MAT_CN(type1);
475 bool haveMask = !_mask.empty();
476
477 if ( (haveMask || haveScalar) && cn > 4 )
478 return false;
479
480 int dtype = _dst.type(), ddepth = CV_MAT_DEPTH(dtype), wdepth = std::max(CV_32S, CV_MAT_DEPTH(wtype));
481 if (!doubleSupport)
482 wdepth = std::min(wdepth, CV_32F);
483
484 wtype = CV_MAKETYPE(wdepth, cn);
485 int type2 = haveScalar ? wtype : _src2.type(), depth2 = CV_MAT_DEPTH(type2);
486 if (!doubleSupport && (depth2 == CV_64F || depth1 == CV_64F))
487 return false;
488
489 int kercn = haveMask || haveScalar ? cn : ocl::predictOptimalVectorWidth(_src1, _src2, _dst);
490 int scalarcn = kercn == 3 ? 4 : kercn, rowsPerWI = d.isIntel() ? 4 : 1;
491
492 char cvtstr[4][32], opts[1024];
493 sprintf(opts, "-D %s%s -D %s -D srcT1=%s -D srcT1_C1=%s -D srcT2=%s -D srcT2_C1=%s "
494 "-D dstT=%s -D DEPTH_dst=%d -D dstT_C1=%s -D workT=%s -D workST=%s -D scaleT=%s -D wdepth=%d -D convertToWT1=%s "
495 "-D convertToWT2=%s -D convertToDT=%s%s -D cn=%d -D rowsPerWI=%d -D convertFromU=%s",
496 (haveMask ? "MASK_" : ""), (haveScalar ? "UNARY_OP" : "BINARY_OP"),
497 oclop2str[oclop], ocl::typeToStr(CV_MAKETYPE(depth1, kercn)),
498 ocl::typeToStr(depth1), ocl::typeToStr(CV_MAKETYPE(depth2, kercn)),
499 ocl::typeToStr(depth2), ocl::typeToStr(CV_MAKETYPE(ddepth, kercn)), ddepth,
500 ocl::typeToStr(ddepth), ocl::typeToStr(CV_MAKETYPE(wdepth, kercn)),
501 ocl::typeToStr(CV_MAKETYPE(wdepth, scalarcn)),
502 ocl::typeToStr(wdepth), wdepth,
503 ocl::convertTypeStr(depth1, wdepth, kercn, cvtstr[0]),
504 ocl::convertTypeStr(depth2, wdepth, kercn, cvtstr[1]),
505 ocl::convertTypeStr(wdepth, ddepth, kercn, cvtstr[2]),
506 doubleSupport ? " -D DOUBLE_SUPPORT" : "", kercn, rowsPerWI,
507 oclop == OCL_OP_ABSDIFF && wdepth == CV_32S && ddepth == wdepth ?
508 ocl::convertTypeStr(CV_8U, ddepth, kercn, cvtstr[3]) : "noconvert");
509
510 size_t usrdata_esz = CV_ELEM_SIZE(wdepth);
511 const uchar* usrdata_p = (const uchar*)usrdata;
512 const double* usrdata_d = (const double*)usrdata;
513 float usrdata_f[3];
514 int i, n = oclop == OCL_OP_MUL_SCALE || oclop == OCL_OP_DIV_SCALE ||
515 oclop == OCL_OP_RDIV_SCALE || oclop == OCL_OP_RECIP_SCALE ? 1 : oclop == OCL_OP_ADDW ? 3 : 0;
516 if( usrdata && n > 0 && wdepth == CV_32F )
517 {
518 for( i = 0; i < n; i++ )
519 usrdata_f[i] = (float)usrdata_d[i];
520 usrdata_p = (const uchar*)usrdata_f;
521 }
522
523 ocl::Kernel k("KF", ocl::core::arithm_oclsrc, opts);
524 if (k.empty())
525 return false;
526
527 UMat src1 = _src1.getUMat(), src2;
528 UMat dst = _dst.getUMat(), mask = _mask.getUMat();
529
530 ocl::KernelArg src1arg = ocl::KernelArg::ReadOnlyNoSize(src1, cn, kercn);
531 ocl::KernelArg dstarg = haveMask ? ocl::KernelArg::ReadWrite(dst, cn, kercn) :
532 ocl::KernelArg::WriteOnly(dst, cn, kercn);
533 ocl::KernelArg maskarg = ocl::KernelArg::ReadOnlyNoSize(mask, 1);
534
535 if( haveScalar )
536 {
537 size_t esz = CV_ELEM_SIZE1(wtype)*scalarcn;
538 double buf[4]={0,0,0,0};
539 Mat src2sc = _src2.getMat();
540
541 if( !src2sc.empty() )
542 convertAndUnrollScalar(src2sc, wtype, (uchar*)buf, 1);
543 ocl::KernelArg scalararg = ocl::KernelArg(ocl::KernelArg::CONSTANT, 0, 0, 0, buf, esz);
544
545 if( !haveMask )
546 {
547 if(n == 0)
548 k.args(src1arg, dstarg, scalararg);
549 else if(n == 1)
550 k.args(src1arg, dstarg, scalararg,
551 ocl::KernelArg(ocl::KernelArg::CONSTANT, 0, 0, 0, usrdata_p, usrdata_esz));
552 else
553 CV_Error(Error::StsNotImplemented, "unsupported number of extra parameters");
554 }
555 else
556 k.args(src1arg, maskarg, dstarg, scalararg);
557 }
558 else
559 {
560 src2 = _src2.getUMat();
561 ocl::KernelArg src2arg = ocl::KernelArg::ReadOnlyNoSize(src2, cn, kercn);
562
563 if( !haveMask )
564 {
565 if (n == 0)
566 k.args(src1arg, src2arg, dstarg);
567 else if (n == 1)
568 k.args(src1arg, src2arg, dstarg,
569 ocl::KernelArg(ocl::KernelArg::CONSTANT, 0, 0, 0, usrdata_p, usrdata_esz));
570 else if (n == 3)
571 k.args(src1arg, src2arg, dstarg,
572 ocl::KernelArg(ocl::KernelArg::CONSTANT, 0, 0, 0, usrdata_p, usrdata_esz),
573 ocl::KernelArg(ocl::KernelArg::CONSTANT, 0, 0, 0, usrdata_p + usrdata_esz, usrdata_esz),
574 ocl::KernelArg(ocl::KernelArg::CONSTANT, 0, 0, 0, usrdata_p + usrdata_esz*2, usrdata_esz));
575 else
576 CV_Error(Error::StsNotImplemented, "unsupported number of extra parameters");
577 }
578 else
579 k.args(src1arg, src2arg, maskarg, dstarg);
580 }
581
582 size_t globalsize[] = { (size_t)src1.cols * cn / kercn, ((size_t)src1.rows + rowsPerWI - 1) / rowsPerWI };
583 return k.run(2, globalsize, NULL, false);
584 }
585
586 #endif
587
arithm_op(InputArray _src1,InputArray _src2,OutputArray _dst,InputArray _mask,int dtype,BinaryFuncC * tab,bool muldiv=false,void * usrdata=0,int oclop=-1)588 static void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst,
589 InputArray _mask, int dtype, BinaryFuncC* tab, bool muldiv=false,
590 void* usrdata=0, int oclop=-1 )
591 {
592 const _InputArray *psrc1 = &_src1, *psrc2 = &_src2;
593 _InputArray::KindFlag kind1 = psrc1->kind(), kind2 = psrc2->kind();
594 bool haveMask = !_mask.empty();
595 bool reallocate = false;
596 int type1 = psrc1->type(), depth1 = CV_MAT_DEPTH(type1), cn = CV_MAT_CN(type1);
597 int type2 = psrc2->type(), depth2 = CV_MAT_DEPTH(type2), cn2 = CV_MAT_CN(type2);
598 int wtype, dims1 = psrc1->dims(), dims2 = psrc2->dims();
599 Size sz1 = dims1 <= 2 ? psrc1->size() : Size();
600 Size sz2 = dims2 <= 2 ? psrc2->size() : Size();
601 #ifdef HAVE_OPENCL
602 bool use_opencl = OCL_PERFORMANCE_CHECK(_dst.isUMat()) && dims1 <= 2 && dims2 <= 2;
603 #endif
604 bool src1Scalar = checkScalar(*psrc1, type2, kind1, kind2);
605 bool src2Scalar = checkScalar(*psrc2, type1, kind2, kind1);
606
607 if( (kind1 == kind2 || cn == 1) && sz1 == sz2 && dims1 <= 2 && dims2 <= 2 && type1 == type2 &&
608 !haveMask && ((!_dst.fixedType() && (dtype < 0 || CV_MAT_DEPTH(dtype) == depth1)) ||
609 (_dst.fixedType() && _dst.type() == type1)) &&
610 (src1Scalar == src2Scalar) )
611 {
612 _dst.createSameSize(*psrc1, type1);
613 CV_OCL_RUN(use_opencl,
614 ocl_arithm_op(*psrc1, *psrc2, _dst, _mask,
615 (!usrdata ? type1 : std::max(depth1, CV_32F)),
616 usrdata, oclop, false))
617
618 Mat src1 = psrc1->getMat(), src2 = psrc2->getMat(), dst = _dst.getMat();
619 Size sz = getContinuousSize2D(src1, src2, dst, src1.channels());
620 tab[depth1](src1.ptr(), src1.step, src2.ptr(), src2.step, dst.ptr(), dst.step, sz.width, sz.height, usrdata);
621 return;
622 }
623
624 bool haveScalar = false, swapped12 = false;
625
626 if( dims1 != dims2 || sz1 != sz2 || cn != cn2 ||
627 (kind1 == _InputArray::MATX && (sz1 == Size(1,4) || sz1 == Size(1,1))) ||
628 (kind2 == _InputArray::MATX && (sz2 == Size(1,4) || sz2 == Size(1,1))) )
629 {
630 if ((type1 == CV_64F && (sz1.height == 1 || sz1.height == 4)) &&
631 checkScalar(*psrc1, type2, kind1, kind2))
632 {
633 // src1 is a scalar; swap it with src2
634 swap(psrc1, psrc2);
635 swap(sz1, sz2);
636 swap(type1, type2);
637 swap(depth1, depth2);
638 swap(cn, cn2);
639 swap(dims1, dims2);
640 swapped12 = true;
641 if( oclop == OCL_OP_SUB )
642 oclop = OCL_OP_RSUB;
643 if ( oclop == OCL_OP_DIV_SCALE )
644 oclop = OCL_OP_RDIV_SCALE;
645 }
646 else if( !checkScalar(*psrc2, type1, kind2, kind1) )
647 CV_Error( CV_StsUnmatchedSizes,
648 "The operation is neither 'array op array' "
649 "(where arrays have the same size and the same number of channels), "
650 "nor 'array op scalar', nor 'scalar op array'" );
651 haveScalar = true;
652 CV_Assert(type2 == CV_64F && (sz2.height == 1 || sz2.height == 4));
653
654 if (!muldiv)
655 {
656 Mat sc = psrc2->getMat();
657 depth2 = actualScalarDepth(sc.ptr<double>(), sz2 == Size(1, 1) ? cn2 : cn);
658 if( depth2 == CV_64F && (depth1 < CV_32S || depth1 == CV_32F) )
659 depth2 = CV_32F;
660 }
661 else
662 depth2 = CV_64F;
663 }
664
665 if( dtype < 0 )
666 {
667 if( _dst.fixedType() )
668 dtype = _dst.type();
669 else
670 {
671 if( !haveScalar && type1 != type2 )
672 CV_Error(CV_StsBadArg,
673 "When the input arrays in add/subtract/multiply/divide functions have different types, "
674 "the output array type must be explicitly specified");
675 dtype = type1;
676 }
677 }
678 dtype = CV_MAT_DEPTH(dtype);
679
680 if( depth1 == depth2 && dtype == depth1 )
681 wtype = dtype;
682 else if( !muldiv )
683 {
684 wtype = depth1 <= CV_8S && depth2 <= CV_8S ? CV_16S :
685 depth1 <= CV_32S && depth2 <= CV_32S ? CV_32S : std::max(depth1, depth2);
686 wtype = std::max(wtype, dtype);
687
688 // when the result of addition should be converted to an integer type,
689 // and just one of the input arrays is floating-point, it makes sense to convert that input to integer type before the operation,
690 // instead of converting the other input to floating-point and then converting the operation result back to integers.
691 if( dtype < CV_32F && (depth1 < CV_32F || depth2 < CV_32F) )
692 wtype = CV_32S;
693 }
694 else
695 {
696 wtype = std::max(depth1, std::max(depth2, CV_32F));
697 wtype = std::max(wtype, dtype);
698 }
699
700 dtype = CV_MAKETYPE(dtype, cn);
701 wtype = CV_MAKETYPE(wtype, cn);
702
703 if( haveMask )
704 {
705 int mtype = _mask.type();
706 CV_Assert( (mtype == CV_8UC1 || mtype == CV_8SC1) && _mask.sameSize(*psrc1) );
707 reallocate = !_dst.sameSize(*psrc1) || _dst.type() != dtype;
708 }
709
710 _dst.createSameSize(*psrc1, dtype);
711 if( reallocate )
712 _dst.setTo(0.);
713
714 CV_OCL_RUN(use_opencl,
715 ocl_arithm_op(*psrc1, *psrc2, _dst, _mask, wtype,
716 usrdata, oclop, haveScalar))
717
718 BinaryFunc cvtsrc1 = type1 == wtype ? 0 : getConvertFunc(type1, wtype);
719 BinaryFunc cvtsrc2 = type2 == type1 ? cvtsrc1 : type2 == wtype ? 0 : getConvertFunc(type2, wtype);
720 BinaryFunc cvtdst = dtype == wtype ? 0 : getConvertFunc(wtype, dtype);
721
722 size_t esz1 = CV_ELEM_SIZE(type1), esz2 = CV_ELEM_SIZE(type2);
723 size_t dsz = CV_ELEM_SIZE(dtype), wsz = CV_ELEM_SIZE(wtype);
724 size_t blocksize0 = (size_t)(BLOCK_SIZE + wsz-1)/wsz;
725 BinaryFunc copymask = getCopyMaskFunc(dsz);
726 Mat src1 = psrc1->getMat(), src2 = psrc2->getMat(), dst = _dst.getMat(), mask = _mask.getMat();
727
728 AutoBuffer<uchar> _buf;
729 uchar *buf, *maskbuf = 0, *buf1 = 0, *buf2 = 0, *wbuf = 0;
730 size_t bufesz = (cvtsrc1 ? wsz : 0) +
731 (cvtsrc2 || haveScalar ? wsz : 0) +
732 (cvtdst ? wsz : 0) +
733 (haveMask ? dsz : 0);
734 BinaryFuncC func = tab[CV_MAT_DEPTH(wtype)];
735 CV_Assert(func);
736
737 if( !haveScalar )
738 {
739 const Mat* arrays[] = { &src1, &src2, &dst, &mask, 0 };
740 uchar* ptrs[4] = {};
741
742 NAryMatIterator it(arrays, ptrs);
743 size_t total = it.size, blocksize = total;
744
745 if( haveMask || cvtsrc1 || cvtsrc2 || cvtdst )
746 blocksize = std::min(blocksize, blocksize0);
747
748 _buf.allocate(bufesz*blocksize + 64);
749 buf = _buf.data();
750 if( cvtsrc1 )
751 buf1 = buf, buf = alignPtr(buf + blocksize*wsz, 16);
752 if( cvtsrc2 )
753 buf2 = buf, buf = alignPtr(buf + blocksize*wsz, 16);
754 wbuf = maskbuf = buf;
755 if( cvtdst )
756 buf = alignPtr(buf + blocksize*wsz, 16);
757 if( haveMask )
758 maskbuf = buf;
759
760 for( size_t i = 0; i < it.nplanes; i++, ++it )
761 {
762 for( size_t j = 0; j < total; j += blocksize )
763 {
764 int bsz = (int)MIN(total - j, blocksize);
765 Size bszn(bsz*cn, 1);
766 const uchar *sptr1 = ptrs[0], *sptr2 = ptrs[1];
767 uchar* dptr = ptrs[2];
768 if( cvtsrc1 )
769 {
770 cvtsrc1( sptr1, 1, 0, 1, buf1, 1, bszn, 0 );
771 sptr1 = buf1;
772 }
773 if( ptrs[0] == ptrs[1] )
774 sptr2 = sptr1;
775 else if( cvtsrc2 )
776 {
777 cvtsrc2( sptr2, 1, 0, 1, buf2, 1, bszn, 0 );
778 sptr2 = buf2;
779 }
780
781 if( !haveMask && !cvtdst )
782 func( sptr1, 1, sptr2, 1, dptr, 1, bszn.width, bszn.height, usrdata );
783 else
784 {
785 func( sptr1, 1, sptr2, 1, wbuf, 0, bszn.width, bszn.height, usrdata );
786 if( !haveMask )
787 cvtdst( wbuf, 1, 0, 1, dptr, 1, bszn, 0 );
788 else if( !cvtdst )
789 {
790 copymask( wbuf, 1, ptrs[3], 1, dptr, 1, Size(bsz, 1), &dsz );
791 ptrs[3] += bsz;
792 }
793 else
794 {
795 cvtdst( wbuf, 1, 0, 1, maskbuf, 1, bszn, 0 );
796 copymask( maskbuf, 1, ptrs[3], 1, dptr, 1, Size(bsz, 1), &dsz );
797 ptrs[3] += bsz;
798 }
799 }
800 ptrs[0] += bsz*esz1; ptrs[1] += bsz*esz2; ptrs[2] += bsz*dsz;
801 }
802 }
803 }
804 else
805 {
806 const Mat* arrays[] = { &src1, &dst, &mask, 0 };
807 uchar* ptrs[3] = {};
808
809 NAryMatIterator it(arrays, ptrs);
810 size_t total = it.size, blocksize = std::min(total, blocksize0);
811
812 _buf.allocate(bufesz*blocksize + 64);
813 buf = _buf.data();
814 if( cvtsrc1 )
815 buf1 = buf, buf = alignPtr(buf + blocksize*wsz, 16);
816 buf2 = buf; buf = alignPtr(buf + blocksize*wsz, 16);
817 wbuf = maskbuf = buf;
818 if( cvtdst )
819 buf = alignPtr(buf + blocksize*wsz, 16);
820 if( haveMask )
821 maskbuf = buf;
822
823 convertAndUnrollScalar( src2, wtype, buf2, blocksize);
824
825 for( size_t i = 0; i < it.nplanes; i++, ++it )
826 {
827 for( size_t j = 0; j < total; j += blocksize )
828 {
829 int bsz = (int)MIN(total - j, blocksize);
830 Size bszn(bsz*cn, 1);
831 const uchar *sptr1 = ptrs[0];
832 const uchar* sptr2 = buf2;
833 uchar* dptr = ptrs[1];
834
835 if( cvtsrc1 )
836 {
837 cvtsrc1( sptr1, 1, 0, 1, buf1, 1, bszn, 0 );
838 sptr1 = buf1;
839 }
840
841 if( swapped12 )
842 std::swap(sptr1, sptr2);
843
844 if( !haveMask && !cvtdst )
845 func( sptr1, 1, sptr2, 1, dptr, 1, bszn.width, bszn.height, usrdata );
846 else
847 {
848 func( sptr1, 1, sptr2, 1, wbuf, 1, bszn.width, bszn.height, usrdata );
849 if( !haveMask )
850 cvtdst( wbuf, 1, 0, 1, dptr, 1, bszn, 0 );
851 else if( !cvtdst )
852 {
853 copymask( wbuf, 1, ptrs[2], 1, dptr, 1, Size(bsz, 1), &dsz );
854 ptrs[2] += bsz;
855 }
856 else
857 {
858 cvtdst( wbuf, 1, 0, 1, maskbuf, 1, bszn, 0 );
859 copymask( maskbuf, 1, ptrs[2], 1, dptr, 1, Size(bsz, 1), &dsz );
860 ptrs[2] += bsz;
861 }
862 }
863 ptrs[0] += bsz*esz1; ptrs[1] += bsz*dsz;
864 }
865 }
866 }
867 }
868
getAddTab()869 static BinaryFuncC* getAddTab()
870 {
871 static BinaryFuncC addTab[] =
872 {
873 (BinaryFuncC)GET_OPTIMIZED(cv::hal::add8u), (BinaryFuncC)GET_OPTIMIZED(cv::hal::add8s),
874 (BinaryFuncC)GET_OPTIMIZED(cv::hal::add16u), (BinaryFuncC)GET_OPTIMIZED(cv::hal::add16s),
875 (BinaryFuncC)GET_OPTIMIZED(cv::hal::add32s),
876 (BinaryFuncC)GET_OPTIMIZED(cv::hal::add32f), (BinaryFuncC)cv::hal::add64f,
877 0
878 };
879
880 return addTab;
881 }
882
getSubTab()883 static BinaryFuncC* getSubTab()
884 {
885 static BinaryFuncC subTab[] =
886 {
887 (BinaryFuncC)GET_OPTIMIZED(cv::hal::sub8u), (BinaryFuncC)GET_OPTIMIZED(cv::hal::sub8s),
888 (BinaryFuncC)GET_OPTIMIZED(cv::hal::sub16u), (BinaryFuncC)GET_OPTIMIZED(cv::hal::sub16s),
889 (BinaryFuncC)GET_OPTIMIZED(cv::hal::sub32s),
890 (BinaryFuncC)GET_OPTIMIZED(cv::hal::sub32f), (BinaryFuncC)cv::hal::sub64f,
891 0
892 };
893
894 return subTab;
895 }
896
getAbsDiffTab()897 static BinaryFuncC* getAbsDiffTab()
898 {
899 static BinaryFuncC absDiffTab[] =
900 {
901 (BinaryFuncC)GET_OPTIMIZED(cv::hal::absdiff8u), (BinaryFuncC)GET_OPTIMIZED(cv::hal::absdiff8s),
902 (BinaryFuncC)GET_OPTIMIZED(cv::hal::absdiff16u), (BinaryFuncC)GET_OPTIMIZED(cv::hal::absdiff16s),
903 (BinaryFuncC)GET_OPTIMIZED(cv::hal::absdiff32s),
904 (BinaryFuncC)GET_OPTIMIZED(cv::hal::absdiff32f), (BinaryFuncC)cv::hal::absdiff64f,
905 0
906 };
907
908 return absDiffTab;
909 }
910
911 }
912
add(InputArray src1,InputArray src2,OutputArray dst,InputArray mask,int dtype)913 void cv::add( InputArray src1, InputArray src2, OutputArray dst,
914 InputArray mask, int dtype )
915 {
916 CV_INSTRUMENT_REGION();
917
918 arithm_op(src1, src2, dst, mask, dtype, getAddTab(), false, 0, OCL_OP_ADD );
919 }
920
subtract(InputArray _src1,InputArray _src2,OutputArray _dst,InputArray mask,int dtype)921 void cv::subtract( InputArray _src1, InputArray _src2, OutputArray _dst,
922 InputArray mask, int dtype )
923 {
924 CV_INSTRUMENT_REGION();
925
926 arithm_op(_src1, _src2, _dst, mask, dtype, getSubTab(), false, 0, OCL_OP_SUB );
927 }
928
absdiff(InputArray src1,InputArray src2,OutputArray dst)929 void cv::absdiff( InputArray src1, InputArray src2, OutputArray dst )
930 {
931 CV_INSTRUMENT_REGION();
932
933 arithm_op(src1, src2, dst, noArray(), -1, getAbsDiffTab(), false, 0, OCL_OP_ABSDIFF);
934 }
935
copyTo(InputArray _src,OutputArray _dst,InputArray _mask)936 void cv::copyTo(InputArray _src, OutputArray _dst, InputArray _mask)
937 {
938 CV_INSTRUMENT_REGION();
939
940 _src.copyTo(_dst, _mask);
941 }
942
943 /****************************************************************************************\
944 * multiply/divide *
945 \****************************************************************************************/
946
947 namespace cv
948 {
949
getMulTab()950 static BinaryFuncC* getMulTab()
951 {
952 static BinaryFuncC mulTab[] =
953 {
954 (BinaryFuncC)cv::hal::mul8u, (BinaryFuncC)cv::hal::mul8s, (BinaryFuncC)cv::hal::mul16u,
955 (BinaryFuncC)cv::hal::mul16s, (BinaryFuncC)cv::hal::mul32s, (BinaryFuncC)cv::hal::mul32f,
956 (BinaryFuncC)cv::hal::mul64f, 0
957 };
958
959 return mulTab;
960 }
961
getDivTab()962 static BinaryFuncC* getDivTab()
963 {
964 static BinaryFuncC divTab[] =
965 {
966 (BinaryFuncC)cv::hal::div8u, (BinaryFuncC)cv::hal::div8s, (BinaryFuncC)cv::hal::div16u,
967 (BinaryFuncC)cv::hal::div16s, (BinaryFuncC)cv::hal::div32s, (BinaryFuncC)cv::hal::div32f,
968 (BinaryFuncC)cv::hal::div64f, 0
969 };
970
971 return divTab;
972 }
973
getRecipTab()974 static BinaryFuncC* getRecipTab()
975 {
976 static BinaryFuncC recipTab[] =
977 {
978 (BinaryFuncC)cv::hal::recip8u, (BinaryFuncC)cv::hal::recip8s, (BinaryFuncC)cv::hal::recip16u,
979 (BinaryFuncC)cv::hal::recip16s, (BinaryFuncC)cv::hal::recip32s, (BinaryFuncC)cv::hal::recip32f,
980 (BinaryFuncC)cv::hal::recip64f, 0
981 };
982
983 return recipTab;
984 }
985
multiply(InputArray src1,InputArray src2,OutputArray dst,double scale,int dtype)986 void multiply(InputArray src1, InputArray src2,
987 OutputArray dst, double scale, int dtype)
988 {
989 CV_INSTRUMENT_REGION();
990
991 arithm_op(src1, src2, dst, noArray(), dtype, getMulTab(),
992 true, &scale, std::abs(scale - 1.0) < DBL_EPSILON ? OCL_OP_MUL : OCL_OP_MUL_SCALE);
993 }
994
divide(InputArray src1,InputArray src2,OutputArray dst,double scale,int dtype)995 void divide(InputArray src1, InputArray src2,
996 OutputArray dst, double scale, int dtype)
997 {
998 CV_INSTRUMENT_REGION();
999
1000 arithm_op(src1, src2, dst, noArray(), dtype, getDivTab(), true, &scale, OCL_OP_DIV_SCALE);
1001 }
1002
divide(double scale,InputArray src2,OutputArray dst,int dtype)1003 void divide(double scale, InputArray src2,
1004 OutputArray dst, int dtype)
1005 {
1006 CV_INSTRUMENT_REGION();
1007
1008 arithm_op(src2, src2, dst, noArray(), dtype, getRecipTab(), true, &scale, OCL_OP_RECIP_SCALE);
1009 }
1010
mul(InputArray m,double scale) const1011 UMat UMat::mul(InputArray m, double scale) const
1012 {
1013 UMat dst;
1014 multiply(*this, m, dst, scale);
1015 return dst;
1016 }
1017
1018 /****************************************************************************************\
1019 * addWeighted *
1020 \****************************************************************************************/
1021
getAddWeightedTab()1022 static BinaryFuncC* getAddWeightedTab()
1023 {
1024 static BinaryFuncC addWeightedTab[] =
1025 {
1026 (BinaryFuncC)GET_OPTIMIZED(cv::hal::addWeighted8u), (BinaryFuncC)GET_OPTIMIZED(cv::hal::addWeighted8s), (BinaryFuncC)GET_OPTIMIZED(cv::hal::addWeighted16u),
1027 (BinaryFuncC)GET_OPTIMIZED(cv::hal::addWeighted16s), (BinaryFuncC)GET_OPTIMIZED(cv::hal::addWeighted32s), (BinaryFuncC)cv::hal::addWeighted32f,
1028 (BinaryFuncC)cv::hal::addWeighted64f, 0
1029 };
1030
1031 return addWeightedTab;
1032 }
1033
1034 }
1035
addWeighted(InputArray src1,double alpha,InputArray src2,double beta,double gamma,OutputArray dst,int dtype)1036 void cv::addWeighted( InputArray src1, double alpha, InputArray src2,
1037 double beta, double gamma, OutputArray dst, int dtype )
1038 {
1039 CV_INSTRUMENT_REGION();
1040
1041 double scalars[] = {alpha, beta, gamma};
1042 arithm_op(src1, src2, dst, noArray(), dtype, getAddWeightedTab(), true, scalars, OCL_OP_ADDW);
1043 }
1044
1045
1046 /****************************************************************************************\
1047 * compare *
1048 \****************************************************************************************/
1049
1050 namespace cv
1051 {
1052
getCmpFunc(int depth)1053 static BinaryFuncC getCmpFunc(int depth)
1054 {
1055 static BinaryFuncC cmpTab[] =
1056 {
1057 (BinaryFuncC)GET_OPTIMIZED(cv::hal::cmp8u), (BinaryFuncC)GET_OPTIMIZED(cv::hal::cmp8s),
1058 (BinaryFuncC)GET_OPTIMIZED(cv::hal::cmp16u), (BinaryFuncC)GET_OPTIMIZED(cv::hal::cmp16s),
1059 (BinaryFuncC)GET_OPTIMIZED(cv::hal::cmp32s),
1060 (BinaryFuncC)GET_OPTIMIZED(cv::hal::cmp32f), (BinaryFuncC)cv::hal::cmp64f,
1061 0
1062 };
1063
1064 return cmpTab[depth];
1065 }
1066
getMinVal(int depth)1067 static double getMinVal(int depth)
1068 {
1069 static const double tab[] = {0, -128, 0, -32768, INT_MIN, -FLT_MAX, -DBL_MAX, 0};
1070 return tab[depth];
1071 }
1072
getMaxVal(int depth)1073 static double getMaxVal(int depth)
1074 {
1075 static const double tab[] = {255, 127, 65535, 32767, INT_MAX, FLT_MAX, DBL_MAX, 0};
1076 return tab[depth];
1077 }
1078
1079 #ifdef HAVE_OPENCL
1080
ocl_compare(InputArray _src1,InputArray _src2,OutputArray _dst,int op,bool haveScalar)1081 static bool ocl_compare(InputArray _src1, InputArray _src2, OutputArray _dst, int op, bool haveScalar)
1082 {
1083 const ocl::Device& dev = ocl::Device::getDefault();
1084 bool doubleSupport = dev.doubleFPConfig() > 0;
1085 int type1 = _src1.type(), depth1 = CV_MAT_DEPTH(type1), cn = CV_MAT_CN(type1),
1086 type2 = _src2.type(), depth2 = CV_MAT_DEPTH(type2);
1087
1088 if (!doubleSupport && depth1 == CV_64F)
1089 return false;
1090
1091 if (!haveScalar && (!_src1.sameSize(_src2) || type1 != type2))
1092 return false;
1093
1094 int kercn = haveScalar ? cn : ocl::predictOptimalVectorWidth(_src1, _src2, _dst), rowsPerWI = dev.isIntel() ? 4 : 1;
1095 // Workaround for bug with "?:" operator in AMD OpenCL compiler
1096 if (depth1 >= CV_16U)
1097 kercn = 1;
1098
1099 int scalarcn = kercn == 3 ? 4 : kercn;
1100 const char * const operationMap[] = { "==", ">", ">=", "<", "<=", "!=" };
1101 char cvt[40];
1102
1103 String opts = format("-D %s -D srcT1=%s -D dstT=%s -D DEPTH_dst=%d -D workT=srcT1 -D cn=%d"
1104 " -D convertToDT=%s -D OP_CMP -D CMP_OPERATOR=%s -D srcT1_C1=%s"
1105 " -D srcT2_C1=%s -D dstT_C1=%s -D workST=%s -D rowsPerWI=%d%s",
1106 haveScalar ? "UNARY_OP" : "BINARY_OP",
1107 ocl::typeToStr(CV_MAKE_TYPE(depth1, kercn)),
1108 ocl::typeToStr(CV_8UC(kercn)), CV_8U, kercn,
1109 ocl::convertTypeStr(depth1, CV_8U, kercn, cvt),
1110 operationMap[op], ocl::typeToStr(depth1),
1111 ocl::typeToStr(depth1), ocl::typeToStr(CV_8U),
1112 ocl::typeToStr(CV_MAKE_TYPE(depth1, scalarcn)), rowsPerWI,
1113 doubleSupport ? " -D DOUBLE_SUPPORT" : "");
1114
1115 ocl::Kernel k("KF", ocl::core::arithm_oclsrc, opts);
1116 if (k.empty())
1117 return false;
1118
1119 UMat src1 = _src1.getUMat();
1120 Size size = src1.size();
1121 _dst.create(size, CV_8UC(cn));
1122 UMat dst = _dst.getUMat();
1123
1124 if (haveScalar)
1125 {
1126 size_t esz = CV_ELEM_SIZE1(type1) * scalarcn;
1127 double buf[4] = { 0, 0, 0, 0 };
1128 Mat src2 = _src2.getMat();
1129
1130 if( depth1 > CV_32S )
1131 convertAndUnrollScalar( src2, depth1, (uchar *)buf, kercn );
1132 else
1133 {
1134 double fval = 0;
1135 getConvertFunc(depth2, CV_64F)(src2.ptr(), 1, 0, 1, (uchar *)&fval, 1, Size(1, 1), 0);
1136 if( fval < getMinVal(depth1) )
1137 return dst.setTo(Scalar::all(op == CMP_GT || op == CMP_GE || op == CMP_NE ? 255 : 0)), true;
1138
1139 if( fval > getMaxVal(depth1) )
1140 return dst.setTo(Scalar::all(op == CMP_LT || op == CMP_LE || op == CMP_NE ? 255 : 0)), true;
1141
1142 int ival = cvRound(fval);
1143 if( fval != ival )
1144 {
1145 if( op == CMP_LT || op == CMP_GE )
1146 ival = cvCeil(fval);
1147 else if( op == CMP_LE || op == CMP_GT )
1148 ival = cvFloor(fval);
1149 else
1150 return dst.setTo(Scalar::all(op == CMP_NE ? 255 : 0)), true;
1151 }
1152 convertAndUnrollScalar(Mat(1, 1, CV_32S, &ival), depth1, (uchar *)buf, kercn);
1153 }
1154
1155 ocl::KernelArg scalararg = ocl::KernelArg(ocl::KernelArg::CONSTANT, 0, 0, 0, buf, esz);
1156
1157 k.args(ocl::KernelArg::ReadOnlyNoSize(src1, cn, kercn),
1158 ocl::KernelArg::WriteOnly(dst, cn, kercn), scalararg);
1159 }
1160 else
1161 {
1162 UMat src2 = _src2.getUMat();
1163
1164 k.args(ocl::KernelArg::ReadOnlyNoSize(src1),
1165 ocl::KernelArg::ReadOnlyNoSize(src2),
1166 ocl::KernelArg::WriteOnly(dst, cn, kercn));
1167 }
1168
1169 size_t globalsize[2] = { (size_t)dst.cols * cn / kercn, ((size_t)dst.rows + rowsPerWI - 1) / rowsPerWI };
1170 return k.run(2, globalsize, NULL, false);
1171 }
1172
1173 #endif
1174
1175 }
1176
compare(InputArray _src1,InputArray _src2,OutputArray _dst,int op)1177 void cv::compare(InputArray _src1, InputArray _src2, OutputArray _dst, int op)
1178 {
1179 CV_INSTRUMENT_REGION();
1180
1181 CV_Assert( op == CMP_LT || op == CMP_LE || op == CMP_EQ ||
1182 op == CMP_NE || op == CMP_GE || op == CMP_GT );
1183
1184 CV_Assert(_src1.empty() == _src2.empty());
1185 if (_src1.empty() && _src2.empty())
1186 {
1187 _dst.release();
1188 return;
1189 }
1190
1191 bool haveScalar = false;
1192
1193 if ((_src1.isMatx() + _src2.isMatx()) == 1
1194 || !_src1.sameSize(_src2)
1195 || _src1.type() != _src2.type())
1196 {
1197 bool is_src1_scalar = checkScalar(_src1, _src2.type(), _src1.kind(), _src2.kind());
1198 bool is_src2_scalar = checkScalar(_src2, _src1.type(), _src2.kind(), _src1.kind());
1199
1200 if (is_src1_scalar && !is_src2_scalar)
1201 {
1202 op = op == CMP_LT ? CMP_GT : op == CMP_LE ? CMP_GE :
1203 op == CMP_GE ? CMP_LE : op == CMP_GT ? CMP_LT : op;
1204 // src1 is a scalar; swap it with src2
1205 compare(_src2, _src1, _dst, op);
1206 return;
1207 }
1208 else if(is_src1_scalar == is_src2_scalar)
1209 CV_Error( CV_StsUnmatchedSizes,
1210 "The operation is neither 'array op array' (where arrays have the same size and the same type), "
1211 "nor 'array op scalar', nor 'scalar op array'" );
1212 haveScalar = true;
1213 }
1214
1215 CV_OCL_RUN(_src1.dims() <= 2 && _src2.dims() <= 2 && OCL_PERFORMANCE_CHECK(_dst.isUMat()),
1216 ocl_compare(_src1, _src2, _dst, op, haveScalar))
1217
1218 _InputArray::KindFlag kind1 = _src1.kind(), kind2 = _src2.kind();
1219 Mat src1 = _src1.getMat(), src2 = _src2.getMat();
1220
1221 int depth1 = src1.depth(), depth2 = src2.depth();
1222 if (depth1 == CV_16F || depth2 == CV_16F)
1223 CV_Error(Error::StsNotImplemented, "Unsupported depth value CV_16F");
1224
1225 if( kind1 == kind2 && src1.dims <= 2 && src2.dims <= 2 && src1.size() == src2.size() && src1.type() == src2.type() )
1226 {
1227 int cn = src1.channels();
1228 _dst.create(src1.size(), CV_8UC(cn));
1229 Mat dst = _dst.getMat();
1230 Size sz = getContinuousSize2D(src1, src2, dst, src1.channels());
1231 BinaryFuncC cmpFn = getCmpFunc(depth1);
1232 CV_Assert(cmpFn);
1233 cmpFn(src1.ptr(), src1.step, src2.ptr(), src2.step, dst.ptr(), dst.step, sz.width, sz.height, &op);
1234 return;
1235 }
1236
1237 int cn = src1.channels();
1238
1239 _dst.create(src1.dims, src1.size, CV_8UC(cn));
1240 src1 = src1.reshape(1); src2 = src2.reshape(1);
1241 Mat dst = _dst.getMat().reshape(1);
1242
1243 size_t esz = std::max(src1.elemSize(), (size_t)1);
1244 size_t blocksize0 = (size_t)(BLOCK_SIZE + esz-1)/esz;
1245 BinaryFuncC func = getCmpFunc(depth1);
1246 CV_Assert(func);
1247
1248 if( !haveScalar )
1249 {
1250 const Mat* arrays[] = { &src1, &src2, &dst, 0 };
1251 uchar* ptrs[3] = {};
1252
1253 NAryMatIterator it(arrays, ptrs);
1254 size_t total = it.size;
1255
1256 for( size_t i = 0; i < it.nplanes; i++, ++it )
1257 func( ptrs[0], 0, ptrs[1], 0, ptrs[2], 0, (int)total, 1, &op );
1258 }
1259 else
1260 {
1261 const Mat* arrays[] = { &src1, &dst, 0 };
1262 uchar* ptrs[2] = {};
1263
1264 NAryMatIterator it(arrays, ptrs);
1265 size_t total = it.size, blocksize = std::min(total, blocksize0);
1266
1267 AutoBuffer<uchar> _buf(blocksize*esz);
1268 uchar *buf = _buf.data();
1269
1270 if( depth1 > CV_32S )
1271 convertAndUnrollScalar( src2, depth1, buf, blocksize );
1272 else
1273 {
1274 double fval=0;
1275 BinaryFunc cvtFn = getConvertFunc(depth2, CV_64F);
1276 CV_Assert(cvtFn);
1277 cvtFn(src2.ptr(), 1, 0, 1, (uchar*)&fval, 1, Size(1,1), 0);
1278 if( fval < getMinVal(depth1) )
1279 {
1280 dst = Scalar::all(op == CMP_GT || op == CMP_GE || op == CMP_NE ? 255 : 0);
1281 return;
1282 }
1283
1284 if( fval > getMaxVal(depth1) )
1285 {
1286 dst = Scalar::all(op == CMP_LT || op == CMP_LE || op == CMP_NE ? 255 : 0);
1287 return;
1288 }
1289
1290 int ival = cvRound(fval);
1291 if( fval != ival )
1292 {
1293 if( op == CMP_LT || op == CMP_GE )
1294 ival = cvCeil(fval);
1295 else if( op == CMP_LE || op == CMP_GT )
1296 ival = cvFloor(fval);
1297 else
1298 {
1299 dst = Scalar::all(op == CMP_NE ? 255 : 0);
1300 return;
1301 }
1302 }
1303 convertAndUnrollScalar(Mat(1, 1, CV_32S, &ival), depth1, buf, blocksize);
1304 }
1305
1306 for( size_t i = 0; i < it.nplanes; i++, ++it )
1307 {
1308 for( size_t j = 0; j < total; j += blocksize )
1309 {
1310 int bsz = (int)MIN(total - j, blocksize);
1311 func( ptrs[0], 0, buf, 0, ptrs[1], 0, bsz, 1, &op);
1312 ptrs[0] += bsz*esz;
1313 ptrs[1] += bsz;
1314 }
1315 }
1316 }
1317 }
1318
1319 /****************************************************************************************\
1320 * inRange *
1321 \****************************************************************************************/
1322
1323 namespace cv
1324 {
1325
1326 template <typename T>
1327 struct InRange_SIMD
1328 {
operator ()cv::InRange_SIMD1329 int operator () (const T *, const T *, const T *, uchar *, int) const
1330 {
1331 return 0;
1332 }
1333 };
1334
1335 #if CV_SIMD
1336
1337 template <>
1338 struct InRange_SIMD<uchar>
1339 {
operator ()cv::InRange_SIMD1340 int operator () (const uchar * src1, const uchar * src2, const uchar * src3,
1341 uchar * dst, int len) const
1342 {
1343 int x = 0;
1344 const int width = v_uint8::nlanes;
1345
1346 for (; x <= len - width; x += width)
1347 {
1348 v_uint8 values = vx_load(src1 + x);
1349 v_uint8 low = vx_load(src2 + x);
1350 v_uint8 high = vx_load(src3 + x);
1351
1352 v_store(dst + x, (values >= low) & (high >= values));
1353 }
1354 vx_cleanup();
1355 return x;
1356 }
1357 };
1358
1359 template <>
1360 struct InRange_SIMD<schar>
1361 {
operator ()cv::InRange_SIMD1362 int operator () (const schar * src1, const schar * src2, const schar * src3,
1363 uchar * dst, int len) const
1364 {
1365 int x = 0;
1366 const int width = v_int8::nlanes;
1367
1368 for (; x <= len - width; x += width)
1369 {
1370 v_int8 values = vx_load(src1 + x);
1371 v_int8 low = vx_load(src2 + x);
1372 v_int8 high = vx_load(src3 + x);
1373
1374 v_store((schar*)(dst + x), (values >= low) & (high >= values));
1375 }
1376 vx_cleanup();
1377 return x;
1378 }
1379 };
1380
1381 template <>
1382 struct InRange_SIMD<ushort>
1383 {
operator ()cv::InRange_SIMD1384 int operator () (const ushort * src1, const ushort * src2, const ushort * src3,
1385 uchar * dst, int len) const
1386 {
1387 int x = 0;
1388 const int width = v_uint16::nlanes * 2;
1389
1390 for (; x <= len - width; x += width)
1391 {
1392 v_uint16 values1 = vx_load(src1 + x);
1393 v_uint16 low1 = vx_load(src2 + x);
1394 v_uint16 high1 = vx_load(src3 + x);
1395
1396 v_uint16 values2 = vx_load(src1 + x + v_uint16::nlanes);
1397 v_uint16 low2 = vx_load(src2 + x + v_uint16::nlanes);
1398 v_uint16 high2 = vx_load(src3 + x + v_uint16::nlanes);
1399
1400 v_store(dst + x, v_pack((values1 >= low1) & (high1 >= values1), (values2 >= low2) & (high2 >= values2)));
1401 }
1402 vx_cleanup();
1403 return x;
1404 }
1405 };
1406
1407 template <>
1408 struct InRange_SIMD<short>
1409 {
operator ()cv::InRange_SIMD1410 int operator () (const short * src1, const short * src2, const short * src3,
1411 uchar * dst, int len) const
1412 {
1413 int x = 0;
1414 const int width = (int)v_int16::nlanes * 2;
1415
1416 for (; x <= len - width; x += width)
1417 {
1418 v_int16 values1 = vx_load(src1 + x);
1419 v_int16 low1 = vx_load(src2 + x);
1420 v_int16 high1 = vx_load(src3 + x);
1421
1422 v_int16 values2 = vx_load(src1 + x + v_int16::nlanes);
1423 v_int16 low2 = vx_load(src2 + x + v_int16::nlanes);
1424 v_int16 high2 = vx_load(src3 + x + v_int16::nlanes);
1425
1426 v_store((schar*)(dst + x), v_pack((values1 >= low1) & (high1 >= values1), (values2 >= low2) & (high2 >= values2)));
1427 }
1428 vx_cleanup();
1429 return x;
1430 }
1431 };
1432
1433 template <>
1434 struct InRange_SIMD<int>
1435 {
operator ()cv::InRange_SIMD1436 int operator () (const int * src1, const int * src2, const int * src3,
1437 uchar * dst, int len) const
1438 {
1439 int x = 0;
1440 const int width = (int)v_int32::nlanes * 2;
1441
1442 for (; x <= len - width; x += width)
1443 {
1444 v_int32 values1 = vx_load(src1 + x);
1445 v_int32 low1 = vx_load(src2 + x);
1446 v_int32 high1 = vx_load(src3 + x);
1447
1448 v_int32 values2 = vx_load(src1 + x + v_int32::nlanes);
1449 v_int32 low2 = vx_load(src2 + x + v_int32::nlanes);
1450 v_int32 high2 = vx_load(src3 + x + v_int32::nlanes);
1451
1452 v_pack_store(dst + x, v_reinterpret_as_u16(v_pack((values1 >= low1) & (high1 >= values1), (values2 >= low2) & (high2 >= values2))));
1453 }
1454 vx_cleanup();
1455 return x;
1456 }
1457 };
1458
1459 template <>
1460 struct InRange_SIMD<float>
1461 {
operator ()cv::InRange_SIMD1462 int operator () (const float * src1, const float * src2, const float * src3,
1463 uchar * dst, int len) const
1464 {
1465 int x = 0;
1466 const int width = (int)v_float32::nlanes * 2;
1467
1468 for (; x <= len - width; x += width)
1469 {
1470 v_float32 values1 = vx_load(src1 + x);
1471 v_float32 low1 = vx_load(src2 + x);
1472 v_float32 high1 = vx_load(src3 + x);
1473
1474 v_float32 values2 = vx_load(src1 + x + v_float32::nlanes);
1475 v_float32 low2 = vx_load(src2 + x + v_float32::nlanes);
1476 v_float32 high2 = vx_load(src3 + x + v_float32::nlanes);
1477
1478 v_pack_store(dst + x, v_pack(v_reinterpret_as_u32(values1 >= low1) & v_reinterpret_as_u32(high1 >= values1),
1479 v_reinterpret_as_u32(values2 >= low2) & v_reinterpret_as_u32(high2 >= values2)));
1480 }
1481 vx_cleanup();
1482 return x;
1483 }
1484 };
1485
1486 #endif
1487
1488 template <typename T>
inRange_(const T * src1,size_t step1,const T * src2,size_t step2,const T * src3,size_t step3,uchar * dst,size_t step,Size size)1489 static void inRange_(const T* src1, size_t step1, const T* src2, size_t step2,
1490 const T* src3, size_t step3, uchar* dst, size_t step,
1491 Size size)
1492 {
1493 step1 /= sizeof(src1[0]);
1494 step2 /= sizeof(src2[0]);
1495 step3 /= sizeof(src3[0]);
1496
1497 InRange_SIMD<T> vop;
1498
1499 for( ; size.height--; src1 += step1, src2 += step2, src3 += step3, dst += step )
1500 {
1501 int x = vop(src1, src2, src3, dst, size.width);
1502 #if CV_ENABLE_UNROLLED
1503 for( ; x <= size.width - 4; x += 4 )
1504 {
1505 int t0, t1;
1506 t0 = src2[x] <= src1[x] && src1[x] <= src3[x];
1507 t1 = src2[x+1] <= src1[x+1] && src1[x+1] <= src3[x+1];
1508 dst[x] = (uchar)-t0; dst[x+1] = (uchar)-t1;
1509 t0 = src2[x+2] <= src1[x+2] && src1[x+2] <= src3[x+2];
1510 t1 = src2[x+3] <= src1[x+3] && src1[x+3] <= src3[x+3];
1511 dst[x+2] = (uchar)-t0; dst[x+3] = (uchar)-t1;
1512 }
1513 #endif
1514 for( ; x < size.width; x++ )
1515 dst[x] = (uchar)-(src2[x] <= src1[x] && src1[x] <= src3[x]);
1516 }
1517 }
1518
1519
inRange8u(const uchar * src1,size_t step1,const uchar * src2,size_t step2,const uchar * src3,size_t step3,uchar * dst,size_t step,Size size)1520 static void inRange8u(const uchar* src1, size_t step1, const uchar* src2, size_t step2,
1521 const uchar* src3, size_t step3, uchar* dst, size_t step, Size size)
1522 {
1523 inRange_(src1, step1, src2, step2, src3, step3, dst, step, size);
1524 }
1525
inRange8s(const schar * src1,size_t step1,const schar * src2,size_t step2,const schar * src3,size_t step3,uchar * dst,size_t step,Size size)1526 static void inRange8s(const schar* src1, size_t step1, const schar* src2, size_t step2,
1527 const schar* src3, size_t step3, uchar* dst, size_t step, Size size)
1528 {
1529 inRange_(src1, step1, src2, step2, src3, step3, dst, step, size);
1530 }
1531
inRange16u(const ushort * src1,size_t step1,const ushort * src2,size_t step2,const ushort * src3,size_t step3,uchar * dst,size_t step,Size size)1532 static void inRange16u(const ushort* src1, size_t step1, const ushort* src2, size_t step2,
1533 const ushort* src3, size_t step3, uchar* dst, size_t step, Size size)
1534 {
1535 inRange_(src1, step1, src2, step2, src3, step3, dst, step, size);
1536 }
1537
inRange16s(const short * src1,size_t step1,const short * src2,size_t step2,const short * src3,size_t step3,uchar * dst,size_t step,Size size)1538 static void inRange16s(const short* src1, size_t step1, const short* src2, size_t step2,
1539 const short* src3, size_t step3, uchar* dst, size_t step, Size size)
1540 {
1541 inRange_(src1, step1, src2, step2, src3, step3, dst, step, size);
1542 }
1543
inRange32s(const int * src1,size_t step1,const int * src2,size_t step2,const int * src3,size_t step3,uchar * dst,size_t step,Size size)1544 static void inRange32s(const int* src1, size_t step1, const int* src2, size_t step2,
1545 const int* src3, size_t step3, uchar* dst, size_t step, Size size)
1546 {
1547 inRange_(src1, step1, src2, step2, src3, step3, dst, step, size);
1548 }
1549
inRange32f(const float * src1,size_t step1,const float * src2,size_t step2,const float * src3,size_t step3,uchar * dst,size_t step,Size size)1550 static void inRange32f(const float* src1, size_t step1, const float* src2, size_t step2,
1551 const float* src3, size_t step3, uchar* dst, size_t step, Size size)
1552 {
1553 inRange_(src1, step1, src2, step2, src3, step3, dst, step, size);
1554 }
1555
inRange64f(const double * src1,size_t step1,const double * src2,size_t step2,const double * src3,size_t step3,uchar * dst,size_t step,Size size)1556 static void inRange64f(const double* src1, size_t step1, const double* src2, size_t step2,
1557 const double* src3, size_t step3, uchar* dst, size_t step, Size size)
1558 {
1559 inRange_(src1, step1, src2, step2, src3, step3, dst, step, size);
1560 }
1561
inRangeReduce(const uchar * src,uchar * dst,size_t len,int cn)1562 static void inRangeReduce(const uchar* src, uchar* dst, size_t len, int cn)
1563 {
1564 int k = cn % 4 ? cn % 4 : 4;
1565 size_t i, j;
1566 if( k == 1 )
1567 for( i = j = 0; i < len; i++, j += cn )
1568 dst[i] = src[j];
1569 else if( k == 2 )
1570 for( i = j = 0; i < len; i++, j += cn )
1571 dst[i] = src[j] & src[j+1];
1572 else if( k == 3 )
1573 for( i = j = 0; i < len; i++, j += cn )
1574 dst[i] = src[j] & src[j+1] & src[j+2];
1575 else
1576 for( i = j = 0; i < len; i++, j += cn )
1577 dst[i] = src[j] & src[j+1] & src[j+2] & src[j+3];
1578
1579 for( ; k < cn; k += 4 )
1580 {
1581 for( i = 0, j = k; i < len; i++, j += cn )
1582 dst[i] &= src[j] & src[j+1] & src[j+2] & src[j+3];
1583 }
1584 }
1585
1586 typedef void (*InRangeFunc)( const uchar* src1, size_t step1, const uchar* src2, size_t step2,
1587 const uchar* src3, size_t step3, uchar* dst, size_t step, Size sz );
1588
getInRangeFunc(int depth)1589 static InRangeFunc getInRangeFunc(int depth)
1590 {
1591 static InRangeFunc inRangeTab[] =
1592 {
1593 (InRangeFunc)GET_OPTIMIZED(inRange8u), (InRangeFunc)GET_OPTIMIZED(inRange8s), (InRangeFunc)GET_OPTIMIZED(inRange16u),
1594 (InRangeFunc)GET_OPTIMIZED(inRange16s), (InRangeFunc)GET_OPTIMIZED(inRange32s), (InRangeFunc)GET_OPTIMIZED(inRange32f),
1595 (InRangeFunc)inRange64f, 0
1596 };
1597
1598 return inRangeTab[depth];
1599 }
1600
1601 #ifdef HAVE_OPENCL
1602
ocl_inRange(InputArray _src,InputArray _lowerb,InputArray _upperb,OutputArray _dst)1603 static bool ocl_inRange( InputArray _src, InputArray _lowerb,
1604 InputArray _upperb, OutputArray _dst )
1605 {
1606 const ocl::Device & d = ocl::Device::getDefault();
1607 _InputArray::KindFlag skind = _src.kind(), lkind = _lowerb.kind(), ukind = _upperb.kind();
1608 Size ssize = _src.size(), lsize = _lowerb.size(), usize = _upperb.size();
1609 int stype = _src.type(), ltype = _lowerb.type(), utype = _upperb.type();
1610 int sdepth = CV_MAT_DEPTH(stype), ldepth = CV_MAT_DEPTH(ltype), udepth = CV_MAT_DEPTH(utype);
1611 int cn = CV_MAT_CN(stype), rowsPerWI = d.isIntel() ? 4 : 1;
1612 bool lbScalar = false, ubScalar = false;
1613
1614 if( (lkind == _InputArray::MATX && skind != _InputArray::MATX) ||
1615 ssize != lsize || stype != ltype )
1616 {
1617 if( !checkScalar(_lowerb, stype, lkind, skind) )
1618 CV_Error( CV_StsUnmatchedSizes,
1619 "The lower boundary is neither an array of the same size and same type as src, nor a scalar");
1620 lbScalar = true;
1621 }
1622
1623 if( (ukind == _InputArray::MATX && skind != _InputArray::MATX) ||
1624 ssize != usize || stype != utype )
1625 {
1626 if( !checkScalar(_upperb, stype, ukind, skind) )
1627 CV_Error( CV_StsUnmatchedSizes,
1628 "The upper boundary is neither an array of the same size and same type as src, nor a scalar");
1629 ubScalar = true;
1630 }
1631
1632 if (lbScalar != ubScalar)
1633 return false;
1634
1635 bool doubleSupport = d.doubleFPConfig() > 0,
1636 haveScalar = lbScalar && ubScalar;
1637
1638 if ( (!doubleSupport && sdepth == CV_64F) ||
1639 (!haveScalar && (sdepth != ldepth || sdepth != udepth)) )
1640 return false;
1641
1642 int kercn = haveScalar ? cn : std::max(std::min(ocl::predictOptimalVectorWidth(_src, _lowerb, _upperb, _dst), 4), cn);
1643 if (kercn % cn != 0)
1644 kercn = cn;
1645 int colsPerWI = kercn / cn;
1646 String opts = format("%s-D cn=%d -D srcT=%s -D srcT1=%s -D dstT=%s -D kercn=%d -D depth=%d%s -D colsPerWI=%d",
1647 haveScalar ? "-D HAVE_SCALAR " : "", cn, ocl::typeToStr(CV_MAKE_TYPE(sdepth, kercn)),
1648 ocl::typeToStr(sdepth), ocl::typeToStr(CV_8UC(colsPerWI)), kercn, sdepth,
1649 doubleSupport ? " -D DOUBLE_SUPPORT" : "", colsPerWI);
1650
1651 ocl::Kernel ker("inrange", ocl::core::inrange_oclsrc, opts);
1652 if (ker.empty())
1653 return false;
1654
1655 _dst.create(ssize, CV_8UC1);
1656 UMat src = _src.getUMat(), dst = _dst.getUMat(), lscalaru, uscalaru;
1657 Mat lscalar, uscalar;
1658
1659 if (lbScalar && ubScalar)
1660 {
1661 lscalar = _lowerb.getMat();
1662 uscalar = _upperb.getMat();
1663
1664 size_t esz = src.elemSize();
1665 size_t blocksize = 36;
1666
1667 AutoBuffer<uchar> _buf(blocksize*(((int)lbScalar + (int)ubScalar)*esz + cn) + 2*cn*sizeof(int) + 128);
1668 uchar *buf = alignPtr(_buf.data() + blocksize*cn, 16);
1669
1670 if( ldepth != sdepth && sdepth < CV_32S )
1671 {
1672 int* ilbuf = (int*)alignPtr(buf + blocksize*esz, 16);
1673 int* iubuf = ilbuf + cn;
1674
1675 BinaryFunc sccvtfunc = getConvertFunc(ldepth, CV_32S);
1676 sccvtfunc(lscalar.ptr(), 1, 0, 1, (uchar*)ilbuf, 1, Size(cn, 1), 0);
1677 sccvtfunc(uscalar.ptr(), 1, 0, 1, (uchar*)iubuf, 1, Size(cn, 1), 0);
1678 int minval = cvRound(getMinVal(sdepth)), maxval = cvRound(getMaxVal(sdepth));
1679
1680 for( int k = 0; k < cn; k++ )
1681 {
1682 if( ilbuf[k] > iubuf[k] || ilbuf[k] > maxval || iubuf[k] < minval )
1683 ilbuf[k] = minval+1, iubuf[k] = minval;
1684 }
1685 lscalar = Mat(cn, 1, CV_32S, ilbuf);
1686 uscalar = Mat(cn, 1, CV_32S, iubuf);
1687 }
1688
1689 lscalar.convertTo(lscalar, stype);
1690 uscalar.convertTo(uscalar, stype);
1691 }
1692 else
1693 {
1694 lscalaru = _lowerb.getUMat();
1695 uscalaru = _upperb.getUMat();
1696 }
1697
1698 ocl::KernelArg srcarg = ocl::KernelArg::ReadOnlyNoSize(src),
1699 dstarg = ocl::KernelArg::WriteOnly(dst, 1, colsPerWI);
1700
1701 if (haveScalar)
1702 {
1703 lscalar.copyTo(lscalaru);
1704 uscalar.copyTo(uscalaru);
1705
1706 ker.args(srcarg, dstarg, ocl::KernelArg::PtrReadOnly(lscalaru),
1707 ocl::KernelArg::PtrReadOnly(uscalaru), rowsPerWI);
1708 }
1709 else
1710 ker.args(srcarg, dstarg, ocl::KernelArg::ReadOnlyNoSize(lscalaru),
1711 ocl::KernelArg::ReadOnlyNoSize(uscalaru), rowsPerWI);
1712
1713 size_t globalsize[2] = { (size_t)ssize.width / colsPerWI, ((size_t)ssize.height + rowsPerWI - 1) / rowsPerWI };
1714 return ker.run(2, globalsize, NULL, false);
1715 }
1716
1717 #endif
1718
1719 }
1720
inRange(InputArray _src,InputArray _lowerb,InputArray _upperb,OutputArray _dst)1721 void cv::inRange(InputArray _src, InputArray _lowerb,
1722 InputArray _upperb, OutputArray _dst)
1723 {
1724 CV_INSTRUMENT_REGION();
1725
1726 CV_Assert(! _src.empty());
1727
1728 CV_OCL_RUN(_src.dims() <= 2 && _lowerb.dims() <= 2 &&
1729 _upperb.dims() <= 2 && OCL_PERFORMANCE_CHECK(_dst.isUMat()),
1730 ocl_inRange(_src, _lowerb, _upperb, _dst))
1731
1732 _InputArray::KindFlag skind = _src.kind(), lkind = _lowerb.kind(), ukind = _upperb.kind();
1733 Mat src = _src.getMat(), lb = _lowerb.getMat(), ub = _upperb.getMat();
1734
1735 bool lbScalar = false, ubScalar = false;
1736
1737 if( (lkind == _InputArray::MATX && skind != _InputArray::MATX) ||
1738 src.size != lb.size || src.type() != lb.type() )
1739 {
1740 if( !checkScalar(lb, src.type(), lkind, skind) )
1741 CV_Error( CV_StsUnmatchedSizes,
1742 "The lower boundary is neither an array of the same size and same type as src, nor a scalar");
1743 lbScalar = true;
1744 }
1745
1746 if( (ukind == _InputArray::MATX && skind != _InputArray::MATX) ||
1747 src.size != ub.size || src.type() != ub.type() )
1748 {
1749 if( !checkScalar(ub, src.type(), ukind, skind) )
1750 CV_Error( CV_StsUnmatchedSizes,
1751 "The upper boundary is neither an array of the same size and same type as src, nor a scalar");
1752 ubScalar = true;
1753 }
1754
1755 CV_Assert(lbScalar == ubScalar);
1756
1757 int cn = src.channels(), depth = src.depth();
1758
1759 size_t esz = src.elemSize();
1760 size_t blocksize0 = (size_t)(BLOCK_SIZE + esz-1)/esz;
1761
1762 _dst.create(src.dims, src.size, CV_8UC1);
1763 Mat dst = _dst.getMat();
1764 InRangeFunc func = getInRangeFunc(depth);
1765
1766 const Mat* arrays_sc[] = { &src, &dst, 0 };
1767 const Mat* arrays_nosc[] = { &src, &dst, &lb, &ub, 0 };
1768 uchar* ptrs[4] = {};
1769
1770 NAryMatIterator it(lbScalar && ubScalar ? arrays_sc : arrays_nosc, ptrs);
1771 size_t total = it.size, blocksize = std::min(total, blocksize0);
1772
1773 AutoBuffer<uchar> _buf(blocksize*(((int)lbScalar + (int)ubScalar)*esz + cn) + 2*cn*sizeof(int) + 128);
1774 uchar *buf = _buf.data(), *mbuf = buf, *lbuf = 0, *ubuf = 0;
1775 buf = alignPtr(buf + blocksize*cn, 16);
1776
1777 if( lbScalar && ubScalar )
1778 {
1779 lbuf = buf;
1780 ubuf = buf = alignPtr(buf + blocksize*esz, 16);
1781
1782 CV_Assert( lb.type() == ub.type() );
1783 int scdepth = lb.depth();
1784
1785 if( scdepth != depth && depth < CV_32S )
1786 {
1787 int* ilbuf = (int*)alignPtr(buf + blocksize*esz, 16);
1788 int* iubuf = ilbuf + cn;
1789
1790 BinaryFunc sccvtfunc = getConvertFunc(scdepth, CV_32S);
1791 sccvtfunc(lb.ptr(), 1, 0, 1, (uchar*)ilbuf, 1, Size(cn, 1), 0);
1792 sccvtfunc(ub.ptr(), 1, 0, 1, (uchar*)iubuf, 1, Size(cn, 1), 0);
1793 int minval = cvRound(getMinVal(depth)), maxval = cvRound(getMaxVal(depth));
1794
1795 for( int k = 0; k < cn; k++ )
1796 {
1797 if( ilbuf[k] > iubuf[k] || ilbuf[k] > maxval || iubuf[k] < minval )
1798 ilbuf[k] = minval+1, iubuf[k] = minval;
1799 }
1800 lb = Mat(cn, 1, CV_32S, ilbuf);
1801 ub = Mat(cn, 1, CV_32S, iubuf);
1802 }
1803
1804 convertAndUnrollScalar( lb, src.type(), lbuf, blocksize );
1805 convertAndUnrollScalar( ub, src.type(), ubuf, blocksize );
1806 }
1807
1808 for( size_t i = 0; i < it.nplanes; i++, ++it )
1809 {
1810 for( size_t j = 0; j < total; j += blocksize )
1811 {
1812 int bsz = (int)MIN(total - j, blocksize);
1813 size_t delta = bsz*esz;
1814 uchar *lptr = lbuf, *uptr = ubuf;
1815 if( !lbScalar )
1816 {
1817 lptr = ptrs[2];
1818 ptrs[2] += delta;
1819 }
1820 if( !ubScalar )
1821 {
1822 int idx = !lbScalar ? 3 : 2;
1823 uptr = ptrs[idx];
1824 ptrs[idx] += delta;
1825 }
1826 func( ptrs[0], 0, lptr, 0, uptr, 0, cn == 1 ? ptrs[1] : mbuf, 0, Size(bsz*cn, 1));
1827 if( cn > 1 )
1828 inRangeReduce(mbuf, ptrs[1], bsz, cn);
1829 ptrs[0] += delta;
1830 ptrs[1] += bsz;
1831 }
1832 }
1833 }
1834
1835
1836 #ifndef OPENCV_EXCLUDE_C_API
1837
1838 /****************************************************************************************\
1839 * Earlier API: cvAdd etc. *
1840 \****************************************************************************************/
1841
1842 CV_IMPL void
cvNot(const CvArr * srcarr,CvArr * dstarr)1843 cvNot( const CvArr* srcarr, CvArr* dstarr )
1844 {
1845 cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
1846 CV_Assert( src.size == dst.size && src.type() == dst.type() );
1847 cv::bitwise_not( src, dst );
1848 }
1849
1850
1851 CV_IMPL void
cvAnd(const CvArr * srcarr1,const CvArr * srcarr2,CvArr * dstarr,const CvArr * maskarr)1852 cvAnd( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr, const CvArr* maskarr )
1853 {
1854 cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2),
1855 dst = cv::cvarrToMat(dstarr), mask;
1856 CV_Assert( src1.size == dst.size && src1.type() == dst.type() );
1857 if( maskarr )
1858 mask = cv::cvarrToMat(maskarr);
1859 cv::bitwise_and( src1, src2, dst, mask );
1860 }
1861
1862
1863 CV_IMPL void
cvOr(const CvArr * srcarr1,const CvArr * srcarr2,CvArr * dstarr,const CvArr * maskarr)1864 cvOr( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr, const CvArr* maskarr )
1865 {
1866 cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2),
1867 dst = cv::cvarrToMat(dstarr), mask;
1868 CV_Assert( src1.size == dst.size && src1.type() == dst.type() );
1869 if( maskarr )
1870 mask = cv::cvarrToMat(maskarr);
1871 cv::bitwise_or( src1, src2, dst, mask );
1872 }
1873
1874
1875 CV_IMPL void
cvXor(const CvArr * srcarr1,const CvArr * srcarr2,CvArr * dstarr,const CvArr * maskarr)1876 cvXor( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr, const CvArr* maskarr )
1877 {
1878 cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2),
1879 dst = cv::cvarrToMat(dstarr), mask;
1880 CV_Assert( src1.size == dst.size && src1.type() == dst.type() );
1881 if( maskarr )
1882 mask = cv::cvarrToMat(maskarr);
1883 cv::bitwise_xor( src1, src2, dst, mask );
1884 }
1885
1886
1887 CV_IMPL void
cvAndS(const CvArr * srcarr,CvScalar s,CvArr * dstarr,const CvArr * maskarr)1888 cvAndS( const CvArr* srcarr, CvScalar s, CvArr* dstarr, const CvArr* maskarr )
1889 {
1890 cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), mask;
1891 CV_Assert( src.size == dst.size && src.type() == dst.type() );
1892 if( maskarr )
1893 mask = cv::cvarrToMat(maskarr);
1894 cv::bitwise_and( src, (const cv::Scalar&)s, dst, mask );
1895 }
1896
1897
1898 CV_IMPL void
cvOrS(const CvArr * srcarr,CvScalar s,CvArr * dstarr,const CvArr * maskarr)1899 cvOrS( const CvArr* srcarr, CvScalar s, CvArr* dstarr, const CvArr* maskarr )
1900 {
1901 cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), mask;
1902 CV_Assert( src.size == dst.size && src.type() == dst.type() );
1903 if( maskarr )
1904 mask = cv::cvarrToMat(maskarr);
1905 cv::bitwise_or( src, (const cv::Scalar&)s, dst, mask );
1906 }
1907
1908
1909 CV_IMPL void
cvXorS(const CvArr * srcarr,CvScalar s,CvArr * dstarr,const CvArr * maskarr)1910 cvXorS( const CvArr* srcarr, CvScalar s, CvArr* dstarr, const CvArr* maskarr )
1911 {
1912 cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), mask;
1913 CV_Assert( src.size == dst.size && src.type() == dst.type() );
1914 if( maskarr )
1915 mask = cv::cvarrToMat(maskarr);
1916 cv::bitwise_xor( src, (const cv::Scalar&)s, dst, mask );
1917 }
1918
1919
cvAdd(const CvArr * srcarr1,const CvArr * srcarr2,CvArr * dstarr,const CvArr * maskarr)1920 CV_IMPL void cvAdd( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr, const CvArr* maskarr )
1921 {
1922 cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2),
1923 dst = cv::cvarrToMat(dstarr), mask;
1924 CV_Assert( src1.size == dst.size && src1.channels() == dst.channels() );
1925 if( maskarr )
1926 mask = cv::cvarrToMat(maskarr);
1927 cv::add( src1, src2, dst, mask, dst.type() );
1928 }
1929
1930
cvSub(const CvArr * srcarr1,const CvArr * srcarr2,CvArr * dstarr,const CvArr * maskarr)1931 CV_IMPL void cvSub( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr, const CvArr* maskarr )
1932 {
1933 cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2),
1934 dst = cv::cvarrToMat(dstarr), mask;
1935 CV_Assert( src1.size == dst.size && src1.channels() == dst.channels() );
1936 if( maskarr )
1937 mask = cv::cvarrToMat(maskarr);
1938 cv::subtract( src1, src2, dst, mask, dst.type() );
1939 }
1940
1941
cvAddS(const CvArr * srcarr1,CvScalar value,CvArr * dstarr,const CvArr * maskarr)1942 CV_IMPL void cvAddS( const CvArr* srcarr1, CvScalar value, CvArr* dstarr, const CvArr* maskarr )
1943 {
1944 cv::Mat src1 = cv::cvarrToMat(srcarr1),
1945 dst = cv::cvarrToMat(dstarr), mask;
1946 CV_Assert( src1.size == dst.size && src1.channels() == dst.channels() );
1947 if( maskarr )
1948 mask = cv::cvarrToMat(maskarr);
1949 cv::add( src1, (const cv::Scalar&)value, dst, mask, dst.type() );
1950 }
1951
1952
cvSubRS(const CvArr * srcarr1,CvScalar value,CvArr * dstarr,const CvArr * maskarr)1953 CV_IMPL void cvSubRS( const CvArr* srcarr1, CvScalar value, CvArr* dstarr, const CvArr* maskarr )
1954 {
1955 cv::Mat src1 = cv::cvarrToMat(srcarr1),
1956 dst = cv::cvarrToMat(dstarr), mask;
1957 CV_Assert( src1.size == dst.size && src1.channels() == dst.channels() );
1958 if( maskarr )
1959 mask = cv::cvarrToMat(maskarr);
1960 cv::subtract( (const cv::Scalar&)value, src1, dst, mask, dst.type() );
1961 }
1962
1963
cvMul(const CvArr * srcarr1,const CvArr * srcarr2,CvArr * dstarr,double scale)1964 CV_IMPL void cvMul( const CvArr* srcarr1, const CvArr* srcarr2,
1965 CvArr* dstarr, double scale )
1966 {
1967 cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2),
1968 dst = cv::cvarrToMat(dstarr);
1969 CV_Assert( src1.size == dst.size && src1.channels() == dst.channels() );
1970 cv::multiply( src1, src2, dst, scale, dst.type() );
1971 }
1972
1973
cvDiv(const CvArr * srcarr1,const CvArr * srcarr2,CvArr * dstarr,double scale)1974 CV_IMPL void cvDiv( const CvArr* srcarr1, const CvArr* srcarr2,
1975 CvArr* dstarr, double scale )
1976 {
1977 cv::Mat src2 = cv::cvarrToMat(srcarr2),
1978 dst = cv::cvarrToMat(dstarr), mask;
1979 CV_Assert( src2.size == dst.size && src2.channels() == dst.channels() );
1980
1981 if( srcarr1 )
1982 cv::divide( cv::cvarrToMat(srcarr1), src2, dst, scale, dst.type() );
1983 else
1984 cv::divide( scale, src2, dst, dst.type() );
1985 }
1986
1987
1988 CV_IMPL void
cvAddWeighted(const CvArr * srcarr1,double alpha,const CvArr * srcarr2,double beta,double gamma,CvArr * dstarr)1989 cvAddWeighted( const CvArr* srcarr1, double alpha,
1990 const CvArr* srcarr2, double beta,
1991 double gamma, CvArr* dstarr )
1992 {
1993 cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2),
1994 dst = cv::cvarrToMat(dstarr);
1995 CV_Assert( src1.size == dst.size && src1.channels() == dst.channels() );
1996 cv::addWeighted( src1, alpha, src2, beta, gamma, dst, dst.type() );
1997 }
1998
1999
2000 CV_IMPL void
cvAbsDiff(const CvArr * srcarr1,const CvArr * srcarr2,CvArr * dstarr)2001 cvAbsDiff( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr )
2002 {
2003 cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
2004 CV_Assert( src1.size == dst.size && src1.type() == dst.type() );
2005
2006 cv::absdiff( src1, cv::cvarrToMat(srcarr2), dst );
2007 }
2008
2009
2010 CV_IMPL void
cvAbsDiffS(const CvArr * srcarr1,CvArr * dstarr,CvScalar scalar)2011 cvAbsDiffS( const CvArr* srcarr1, CvArr* dstarr, CvScalar scalar )
2012 {
2013 cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
2014 CV_Assert( src1.size == dst.size && src1.type() == dst.type() );
2015
2016 cv::absdiff( src1, (const cv::Scalar&)scalar, dst );
2017 }
2018
2019
2020 CV_IMPL void
cvInRange(const void * srcarr1,const void * srcarr2,const void * srcarr3,void * dstarr)2021 cvInRange( const void* srcarr1, const void* srcarr2,
2022 const void* srcarr3, void* dstarr )
2023 {
2024 cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
2025 CV_Assert( src1.size == dst.size && dst.type() == CV_8U );
2026
2027 cv::inRange( src1, cv::cvarrToMat(srcarr2), cv::cvarrToMat(srcarr3), dst );
2028 }
2029
2030
2031 CV_IMPL void
cvInRangeS(const void * srcarr1,CvScalar lowerb,CvScalar upperb,void * dstarr)2032 cvInRangeS( const void* srcarr1, CvScalar lowerb, CvScalar upperb, void* dstarr )
2033 {
2034 cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
2035 CV_Assert( src1.size == dst.size && dst.type() == CV_8U );
2036
2037 cv::inRange( src1, (const cv::Scalar&)lowerb, (const cv::Scalar&)upperb, dst );
2038 }
2039
2040
2041 CV_IMPL void
cvCmp(const void * srcarr1,const void * srcarr2,void * dstarr,int cmp_op)2042 cvCmp( const void* srcarr1, const void* srcarr2, void* dstarr, int cmp_op )
2043 {
2044 cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
2045 CV_Assert( src1.size == dst.size && dst.type() == CV_8U );
2046
2047 cv::compare( src1, cv::cvarrToMat(srcarr2), dst, cmp_op );
2048 }
2049
2050
2051 CV_IMPL void
cvCmpS(const void * srcarr1,double value,void * dstarr,int cmp_op)2052 cvCmpS( const void* srcarr1, double value, void* dstarr, int cmp_op )
2053 {
2054 cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
2055 CV_Assert( src1.size == dst.size && dst.type() == CV_8U );
2056
2057 cv::compare( src1, value, dst, cmp_op );
2058 }
2059
2060
2061 CV_IMPL void
cvMin(const void * srcarr1,const void * srcarr2,void * dstarr)2062 cvMin( const void* srcarr1, const void* srcarr2, void* dstarr )
2063 {
2064 cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
2065 CV_Assert( src1.size == dst.size && src1.type() == dst.type() );
2066
2067 cv::min( src1, cv::cvarrToMat(srcarr2), dst );
2068 }
2069
2070
2071 CV_IMPL void
cvMax(const void * srcarr1,const void * srcarr2,void * dstarr)2072 cvMax( const void* srcarr1, const void* srcarr2, void* dstarr )
2073 {
2074 cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
2075 CV_Assert( src1.size == dst.size && src1.type() == dst.type() );
2076
2077 cv::max( src1, cv::cvarrToMat(srcarr2), dst );
2078 }
2079
2080
2081 CV_IMPL void
cvMinS(const void * srcarr1,double value,void * dstarr)2082 cvMinS( const void* srcarr1, double value, void* dstarr )
2083 {
2084 cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
2085 CV_Assert( src1.size == dst.size && src1.type() == dst.type() );
2086
2087 cv::min( src1, value, dst );
2088 }
2089
2090
2091 CV_IMPL void
cvMaxS(const void * srcarr1,double value,void * dstarr)2092 cvMaxS( const void* srcarr1, double value, void* dstarr )
2093 {
2094 cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
2095 CV_Assert( src1.size == dst.size && src1.type() == dst.type() );
2096
2097 cv::max( src1, value, dst );
2098 }
2099
2100 #endif // OPENCV_EXCLUDE_C_API
2101 /* End of file. */
2102