next: drop HAVE_TEGRA_OPTIMIZATION/TADP
[platform/upstream/opencv.git] / modules / imgproc / src / corner.cpp
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, 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 #include "precomp.hpp"
45 #include "opencl_kernels_imgproc.hpp"
46 #include "opencv2/core/hal/intrin.hpp"
47 #include "corner.hpp"
48
49 namespace cv
50 {
51
52 static void calcMinEigenVal( const Mat& _cov, Mat& _dst )
53 {
54     int i, j;
55     Size size = _cov.size();
56 #if CV_TRY_AVX
57     bool haveAvx = CV_CPU_HAS_SUPPORT_AVX;
58 #endif
59 #if CV_SIMD128
60     bool haveSimd = hasSIMD128();
61 #endif
62
63     if( _cov.isContinuous() && _dst.isContinuous() )
64     {
65         size.width *= size.height;
66         size.height = 1;
67     }
68
69     for( i = 0; i < size.height; i++ )
70     {
71         const float* cov = _cov.ptr<float>(i);
72         float* dst = _dst.ptr<float>(i);
73 #if CV_TRY_AVX
74         if( haveAvx )
75             j = calcMinEigenValLine_AVX(cov, dst, size.width);
76         else
77 #endif // CV_TRY_AVX
78             j = 0;
79
80 #if CV_SIMD128
81         if( haveSimd )
82         {
83             v_float32x4 half = v_setall_f32(0.5f);
84             for( ; j <= size.width - v_float32x4::nlanes; j += v_float32x4::nlanes )
85             {
86                 v_float32x4 v_a, v_b, v_c, v_t;
87                 v_load_deinterleave(cov + j*3, v_a, v_b, v_c);
88                 v_a *= half;
89                 v_c *= half;
90                 v_t = v_a - v_c;
91                 v_t = v_muladd(v_b, v_b, (v_t * v_t));
92                 v_store(dst + j, (v_a + v_c) - v_sqrt(v_t));
93             }
94         }
95 #endif // CV_SIMD128
96
97         for( ; j < size.width; j++ )
98         {
99             float a = cov[j*3]*0.5f;
100             float b = cov[j*3+1];
101             float c = cov[j*3+2]*0.5f;
102             dst[j] = (float)((a + c) - std::sqrt((a - c)*(a - c) + b*b));
103         }
104     }
105 }
106
107
108 static void calcHarris( const Mat& _cov, Mat& _dst, double k )
109 {
110     int i, j;
111     Size size = _cov.size();
112 #if CV_TRY_AVX
113     bool haveAvx = CV_CPU_HAS_SUPPORT_AVX;
114 #endif
115 #if CV_SIMD128
116     bool haveSimd = hasSIMD128();
117 #endif
118
119     if( _cov.isContinuous() && _dst.isContinuous() )
120     {
121         size.width *= size.height;
122         size.height = 1;
123     }
124
125     for( i = 0; i < size.height; i++ )
126     {
127         const float* cov = _cov.ptr<float>(i);
128         float* dst = _dst.ptr<float>(i);
129
130 #if CV_TRY_AVX
131         if( haveAvx )
132             j = calcHarrisLine_AVX(cov, dst, k, size.width);
133         else
134 #endif // CV_TRY_AVX
135             j = 0;
136
137 #if CV_SIMD128
138         if( haveSimd )
139         {
140             v_float32x4 v_k = v_setall_f32((float)k);
141
142             for( ; j <= size.width - v_float32x4::nlanes; j += v_float32x4::nlanes )
143             {
144                 v_float32x4 v_a, v_b, v_c;
145                 v_load_deinterleave(cov + j * 3, v_a, v_b, v_c);
146
147                 v_float32x4 v_ac_bb = v_a * v_c - v_b * v_b;
148                 v_float32x4 v_ac = v_a + v_c;
149                 v_float32x4 v_dst = v_ac_bb - v_k * v_ac * v_ac;
150                 v_store(dst + j, v_dst);
151             }
152         }
153 #endif // CV_SIMD128
154
155         for( ; j < size.width; j++ )
156         {
157             float a = cov[j*3];
158             float b = cov[j*3+1];
159             float c = cov[j*3+2];
160             dst[j] = (float)(a*c - b*b - k*(a + c)*(a + c));
161         }
162     }
163 }
164
165
166 static void eigen2x2( const float* cov, float* dst, int n )
167 {
168     for( int j = 0; j < n; j++ )
169     {
170         double a = cov[j*3];
171         double b = cov[j*3+1];
172         double c = cov[j*3+2];
173
174         double u = (a + c)*0.5;
175         double v = std::sqrt((a - c)*(a - c)*0.25 + b*b);
176         double l1 = u + v;
177         double l2 = u - v;
178
179         double x = b;
180         double y = l1 - a;
181         double e = fabs(x);
182
183         if( e + fabs(y) < 1e-4 )
184         {
185             y = b;
186             x = l1 - c;
187             e = fabs(x);
188             if( e + fabs(y) < 1e-4 )
189             {
190                 e = 1./(e + fabs(y) + FLT_EPSILON);
191                 x *= e, y *= e;
192             }
193         }
194
195         double d = 1./std::sqrt(x*x + y*y + DBL_EPSILON);
196         dst[6*j] = (float)l1;
197         dst[6*j + 2] = (float)(x*d);
198         dst[6*j + 3] = (float)(y*d);
199
200         x = b;
201         y = l2 - a;
202         e = fabs(x);
203
204         if( e + fabs(y) < 1e-4 )
205         {
206             y = b;
207             x = l2 - c;
208             e = fabs(x);
209             if( e + fabs(y) < 1e-4 )
210             {
211                 e = 1./(e + fabs(y) + FLT_EPSILON);
212                 x *= e, y *= e;
213             }
214         }
215
216         d = 1./std::sqrt(x*x + y*y + DBL_EPSILON);
217         dst[6*j + 1] = (float)l2;
218         dst[6*j + 4] = (float)(x*d);
219         dst[6*j + 5] = (float)(y*d);
220     }
221 }
222
223 static void calcEigenValsVecs( const Mat& _cov, Mat& _dst )
224 {
225     Size size = _cov.size();
226     if( _cov.isContinuous() && _dst.isContinuous() )
227     {
228         size.width *= size.height;
229         size.height = 1;
230     }
231
232     for( int i = 0; i < size.height; i++ )
233     {
234         const float* cov = _cov.ptr<float>(i);
235         float* dst = _dst.ptr<float>(i);
236
237         eigen2x2(cov, dst, size.width);
238     }
239 }
240
241
242 enum { MINEIGENVAL=0, HARRIS=1, EIGENVALSVECS=2 };
243
244
245 static void
246 cornerEigenValsVecs( const Mat& src, Mat& eigenv, int block_size,
247                      int aperture_size, int op_type, double k=0.,
248                      int borderType=BORDER_DEFAULT )
249 {
250 #if CV_TRY_AVX
251     bool haveAvx = CV_CPU_HAS_SUPPORT_AVX;
252 #endif
253 #if CV_SIMD128
254     bool haveSimd = hasSIMD128();
255 #endif
256
257     int depth = src.depth();
258     double scale = (double)(1 << ((aperture_size > 0 ? aperture_size : 3) - 1)) * block_size;
259     if( aperture_size < 0 )
260         scale *= 2.0;
261     if( depth == CV_8U )
262         scale *= 255.0;
263     scale = 1.0/scale;
264
265     CV_Assert( src.type() == CV_8UC1 || src.type() == CV_32FC1 );
266
267     Mat Dx, Dy;
268     if( aperture_size > 0 )
269     {
270         Sobel( src, Dx, CV_32F, 1, 0, aperture_size, scale, 0, borderType );
271         Sobel( src, Dy, CV_32F, 0, 1, aperture_size, scale, 0, borderType );
272     }
273     else
274     {
275         Scharr( src, Dx, CV_32F, 1, 0, scale, 0, borderType );
276         Scharr( src, Dy, CV_32F, 0, 1, scale, 0, borderType );
277     }
278
279     Size size = src.size();
280     Mat cov( size, CV_32FC3 );
281     int i, j;
282
283     for( i = 0; i < size.height; i++ )
284     {
285         float* cov_data = cov.ptr<float>(i);
286         const float* dxdata = Dx.ptr<float>(i);
287         const float* dydata = Dy.ptr<float>(i);
288
289 #if CV_TRY_AVX
290         if( haveAvx )
291             j = cornerEigenValsVecsLine_AVX(dxdata, dydata, cov_data, size.width);
292         else
293 #endif // CV_TRY_AVX
294             j = 0;
295
296 #if CV_SIMD128
297         if( haveSimd )
298         {
299             for( ; j <= size.width - v_float32x4::nlanes; j += v_float32x4::nlanes )
300             {
301                 v_float32x4 v_dx = v_load(dxdata + j);
302                 v_float32x4 v_dy = v_load(dydata + j);
303
304                 v_float32x4 v_dst0, v_dst1, v_dst2;
305                 v_dst0 = v_dx * v_dx;
306                 v_dst1 = v_dx * v_dy;
307                 v_dst2 = v_dy * v_dy;
308
309                 v_store_interleave(cov_data + j * 3, v_dst0, v_dst1, v_dst2);
310             }
311         }
312 #endif // CV_SIMD128
313
314         for( ; j < size.width; j++ )
315         {
316             float dx = dxdata[j];
317             float dy = dydata[j];
318
319             cov_data[j*3] = dx*dx;
320             cov_data[j*3+1] = dx*dy;
321             cov_data[j*3+2] = dy*dy;
322         }
323     }
324
325     boxFilter(cov, cov, cov.depth(), Size(block_size, block_size),
326         Point(-1,-1), false, borderType );
327
328     if( op_type == MINEIGENVAL )
329         calcMinEigenVal( cov, eigenv );
330     else if( op_type == HARRIS )
331         calcHarris( cov, eigenv, k );
332     else if( op_type == EIGENVALSVECS )
333         calcEigenValsVecs( cov, eigenv );
334 }
335
336 #ifdef HAVE_OPENCL
337
338 static bool extractCovData(InputArray _src, UMat & Dx, UMat & Dy, int depth,
339                            float scale, int aperture_size, int borderType)
340 {
341     UMat src = _src.getUMat();
342
343     Size wholeSize;
344     Point ofs;
345     src.locateROI(wholeSize, ofs);
346
347     const int sobel_lsz = 16;
348     if ((aperture_size == 3 || aperture_size == 5 || aperture_size == 7 || aperture_size == -1) &&
349         wholeSize.height > sobel_lsz + (aperture_size >> 1) &&
350         wholeSize.width > sobel_lsz + (aperture_size >> 1))
351     {
352         CV_Assert(depth == CV_8U || depth == CV_32F);
353
354         Dx.create(src.size(), CV_32FC1);
355         Dy.create(src.size(), CV_32FC1);
356
357         size_t localsize[2] = { (size_t)sobel_lsz, (size_t)sobel_lsz };
358         size_t globalsize[2] = { localsize[0] * (1 + (src.cols - 1) / localsize[0]),
359                                  localsize[1] * (1 + (src.rows - 1) / localsize[1]) };
360
361         int src_offset_x = (int)((src.offset % src.step) / src.elemSize());
362         int src_offset_y = (int)(src.offset / src.step);
363
364         const char * const borderTypes[] = { "BORDER_CONSTANT", "BORDER_REPLICATE", "BORDER_REFLECT",
365                                              "BORDER_WRAP", "BORDER_REFLECT101" };
366
367         ocl::Kernel k(format("sobel%d", aperture_size).c_str(), ocl::imgproc::covardata_oclsrc,
368                       cv::format("-D BLK_X=%d -D BLK_Y=%d -D %s -D SRCTYPE=%s%s",
369                                  (int)localsize[0], (int)localsize[1], borderTypes[borderType], ocl::typeToStr(depth),
370                                  aperture_size < 0 ? " -D SCHARR" : ""));
371         if (k.empty())
372             return false;
373
374         k.args(ocl::KernelArg::PtrReadOnly(src), (int)src.step, src_offset_x, src_offset_y,
375                ocl::KernelArg::WriteOnlyNoSize(Dx), ocl::KernelArg::WriteOnly(Dy),
376                wholeSize.height, wholeSize.width, scale);
377
378         return k.run(2, globalsize, localsize, false);
379     }
380     else
381     {
382         if (aperture_size > 0)
383         {
384             Sobel(_src, Dx, CV_32F, 1, 0, aperture_size, scale, 0, borderType);
385             Sobel(_src, Dy, CV_32F, 0, 1, aperture_size, scale, 0, borderType);
386         }
387         else
388         {
389             Scharr(_src, Dx, CV_32F, 1, 0, scale, 0, borderType);
390             Scharr(_src, Dy, CV_32F, 0, 1, scale, 0, borderType);
391         }
392     }
393
394     return true;
395 }
396
397 static bool ocl_cornerMinEigenValVecs(InputArray _src, OutputArray _dst, int block_size,
398                                       int aperture_size, double k, int borderType, int op_type)
399 {
400     CV_Assert(op_type == HARRIS || op_type == MINEIGENVAL);
401
402     if ( !(borderType == BORDER_CONSTANT || borderType == BORDER_REPLICATE ||
403            borderType == BORDER_REFLECT || borderType == BORDER_REFLECT_101) )
404         return false;
405
406     int type = _src.type(), depth = CV_MAT_DEPTH(type);
407     if ( !(type == CV_8UC1 || type == CV_32FC1) )
408         return false;
409
410     const char * const borderTypes[] = { "BORDER_CONSTANT", "BORDER_REPLICATE", "BORDER_REFLECT",
411                                          "BORDER_WRAP", "BORDER_REFLECT101" };
412     const char * const cornerType[] = { "CORNER_MINEIGENVAL", "CORNER_HARRIS", 0 };
413
414
415     double scale = (double)(1 << ((aperture_size > 0 ? aperture_size : 3) - 1)) * block_size;
416     if (aperture_size < 0)
417         scale *= 2.0;
418     if (depth == CV_8U)
419         scale *= 255.0;
420     scale = 1.0 / scale;
421
422     UMat Dx, Dy;
423     if (!extractCovData(_src, Dx, Dy, depth, (float)scale, aperture_size, borderType))
424         return false;
425
426     ocl::Kernel cornelKernel("corner", ocl::imgproc::corner_oclsrc,
427                              format("-D anX=%d -D anY=%d -D ksX=%d -D ksY=%d -D %s -D %s",
428                                     block_size / 2, block_size / 2, block_size, block_size,
429                                     borderTypes[borderType], cornerType[op_type]));
430     if (cornelKernel.empty())
431         return false;
432
433     _dst.createSameSize(_src, CV_32FC1);
434     UMat dst = _dst.getUMat();
435
436     cornelKernel.args(ocl::KernelArg::ReadOnly(Dx), ocl::KernelArg::ReadOnly(Dy),
437                       ocl::KernelArg::WriteOnly(dst), (float)k);
438
439     size_t blockSizeX = 256, blockSizeY = 1;
440     size_t gSize = blockSizeX - block_size / 2 * 2;
441     size_t globalSizeX = (Dx.cols) % gSize == 0 ? Dx.cols / gSize * blockSizeX : (Dx.cols / gSize + 1) * blockSizeX;
442     size_t rows_per_thread = 2;
443     size_t globalSizeY = ((Dx.rows + rows_per_thread - 1) / rows_per_thread) % blockSizeY == 0 ?
444                          ((Dx.rows + rows_per_thread - 1) / rows_per_thread) :
445                          (((Dx.rows + rows_per_thread - 1) / rows_per_thread) / blockSizeY + 1) * blockSizeY;
446
447     size_t globalsize[2] = { globalSizeX, globalSizeY }, localsize[2] = { blockSizeX, blockSizeY };
448     return cornelKernel.run(2, globalsize, localsize, false);
449 }
450
451 static bool ocl_preCornerDetect( InputArray _src, OutputArray _dst, int ksize, int borderType, int depth )
452 {
453     UMat Dx, Dy, D2x, D2y, Dxy;
454
455     if (!extractCovData(_src, Dx, Dy, depth, 1, ksize, borderType))
456         return false;
457
458     Sobel( _src, D2x, CV_32F, 2, 0, ksize, 1, 0, borderType );
459     Sobel( _src, D2y, CV_32F, 0, 2, ksize, 1, 0, borderType );
460     Sobel( _src, Dxy, CV_32F, 1, 1, ksize, 1, 0, borderType );
461
462     _dst.create( _src.size(), CV_32FC1 );
463     UMat dst = _dst.getUMat();
464
465     double factor = 1 << (ksize - 1);
466     if( depth == CV_8U )
467         factor *= 255;
468     factor = 1./(factor * factor * factor);
469
470     ocl::Kernel k("preCornerDetect", ocl::imgproc::precornerdetect_oclsrc);
471     if (k.empty())
472         return false;
473
474     k.args(ocl::KernelArg::ReadOnlyNoSize(Dx), ocl::KernelArg::ReadOnlyNoSize(Dy),
475            ocl::KernelArg::ReadOnlyNoSize(D2x), ocl::KernelArg::ReadOnlyNoSize(D2y),
476            ocl::KernelArg::ReadOnlyNoSize(Dxy), ocl::KernelArg::WriteOnly(dst), (float)factor);
477
478     size_t globalsize[2] = { (size_t)dst.cols, (size_t)dst.rows };
479     return k.run(2, globalsize, NULL, false);
480 }
481
482 #endif
483
484 }
485
486 #if defined(HAVE_IPP)
487 namespace cv
488 {
489 static bool ipp_cornerMinEigenVal( InputArray _src, OutputArray _dst, int blockSize, int ksize, int borderType )
490 {
491 #if IPP_VERSION_X100 >= 800
492     CV_INSTRUMENT_REGION_IPP()
493
494     Mat src = _src.getMat();
495     _dst.create( src.size(), CV_32FC1 );
496     Mat dst = _dst.getMat();
497
498     {
499         typedef IppStatus (CV_STDCALL * ippiMinEigenValGetBufferSize)(IppiSize, int, int, int*);
500         typedef IppStatus (CV_STDCALL * ippiMinEigenVal)(const void*, int, Ipp32f*, int, IppiSize, IppiKernelType, int, int, Ipp8u*);
501         IppiKernelType kerType;
502         int kerSize = ksize;
503         if (ksize < 0)
504         {
505             kerType = ippKernelScharr;
506             kerSize = 3;
507         } else
508         {
509             kerType = ippKernelSobel;
510         }
511         bool isolated = (borderType & BORDER_ISOLATED) != 0;
512         int borderTypeNI = borderType & ~BORDER_ISOLATED;
513         if ((borderTypeNI == BORDER_REPLICATE && (!src.isSubmatrix() || isolated)) &&
514             (kerSize == 3 || kerSize == 5) && (blockSize == 3 || blockSize == 5))
515         {
516             ippiMinEigenValGetBufferSize getBufferSizeFunc = 0;
517             ippiMinEigenVal ippiMinEigenVal_C1R = 0;
518             float norm_coef = 0.f;
519
520             if (src.type() == CV_8UC1)
521             {
522                 getBufferSizeFunc = (ippiMinEigenValGetBufferSize) ippiMinEigenValGetBufferSize_8u32f_C1R;
523                 ippiMinEigenVal_C1R = (ippiMinEigenVal) ippiMinEigenVal_8u32f_C1R;
524                 norm_coef = 1.f / 255.f;
525             } else if (src.type() == CV_32FC1)
526             {
527                 getBufferSizeFunc = (ippiMinEigenValGetBufferSize) ippiMinEigenValGetBufferSize_32f_C1R;
528                 ippiMinEigenVal_C1R = (ippiMinEigenVal) ippiMinEigenVal_32f_C1R;
529                 norm_coef = 255.f;
530             }
531             norm_coef = kerType == ippKernelSobel ? norm_coef : norm_coef / 2.45f;
532
533             if (getBufferSizeFunc && ippiMinEigenVal_C1R)
534             {
535                 int bufferSize;
536                 IppiSize srcRoi = { src.cols, src.rows };
537                 IppStatus ok = getBufferSizeFunc(srcRoi, kerSize, blockSize, &bufferSize);
538                 if (ok >= 0)
539                 {
540                     AutoBuffer<uchar> buffer(bufferSize);
541                     ok = CV_INSTRUMENT_FUN_IPP(ippiMinEigenVal_C1R, src.ptr(), (int) src.step, dst.ptr<Ipp32f>(), (int) dst.step, srcRoi, kerType, kerSize, blockSize, buffer);
542                     CV_SUPPRESS_DEPRECATED_START
543                     if (ok >= 0) ok = CV_INSTRUMENT_FUN_IPP(ippiMulC_32f_C1IR, norm_coef, dst.ptr<Ipp32f>(), (int) dst.step, srcRoi);
544                     CV_SUPPRESS_DEPRECATED_END
545                     if (ok >= 0)
546                     {
547                         CV_IMPL_ADD(CV_IMPL_IPP);
548                         return true;
549                     }
550                 }
551             }
552         }
553     }
554 #else
555     CV_UNUSED(_src); CV_UNUSED(_dst); CV_UNUSED(blockSize); CV_UNUSED(borderType);
556 #endif
557     return false;
558 }
559 }
560 #endif
561
562 void cv::cornerMinEigenVal( InputArray _src, OutputArray _dst, int blockSize, int ksize, int borderType )
563 {
564     CV_INSTRUMENT_REGION()
565
566     CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
567                ocl_cornerMinEigenValVecs(_src, _dst, blockSize, ksize, 0.0, borderType, MINEIGENVAL))
568
569 #ifdef HAVE_IPP
570     int kerSize = (ksize < 0)?3:ksize;
571     bool isolated = (borderType & BORDER_ISOLATED) != 0;
572     int borderTypeNI = borderType & ~BORDER_ISOLATED;
573 #endif
574     CV_IPP_RUN(((borderTypeNI == BORDER_REPLICATE && (!_src.isSubmatrix() || isolated)) &&
575             (kerSize == 3 || kerSize == 5) && (blockSize == 3 || blockSize == 5)) && IPP_VERSION_X100 >= 800,
576         ipp_cornerMinEigenVal( _src, _dst, blockSize, ksize, borderType ));
577
578
579     Mat src = _src.getMat();
580     _dst.create( src.size(), CV_32FC1 );
581     Mat dst = _dst.getMat();
582
583     cornerEigenValsVecs( src, dst, blockSize, ksize, MINEIGENVAL, 0, borderType );
584 }
585
586
587 #if defined(HAVE_IPP)
588 namespace cv
589 {
590 static bool ipp_cornerHarris( Mat &src, Mat &dst, int blockSize, int ksize, double k, int borderType )
591 {
592 #if IPP_VERSION_X100 >= 810
593     CV_INSTRUMENT_REGION_IPP()
594
595     {
596         int type = src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
597         int borderTypeNI = borderType & ~BORDER_ISOLATED;
598         bool isolated = (borderType & BORDER_ISOLATED) != 0;
599
600         if ( (ksize == 3 || ksize == 5) && (type == CV_8UC1 || type == CV_32FC1) &&
601             (borderTypeNI == BORDER_CONSTANT || borderTypeNI == BORDER_REPLICATE) && cn == 1 && (!src.isSubmatrix() || isolated) )
602         {
603             IppiSize roisize = { src.cols, src.rows };
604             IppiMaskSize masksize = ksize == 5 ? ippMskSize5x5 : ippMskSize3x3;
605             IppDataType datatype = type == CV_8UC1 ? ipp8u : ipp32f;
606             Ipp32s bufsize = 0;
607
608             double scale = (double)(1 << ((ksize > 0 ? ksize : 3) - 1)) * blockSize;
609             if (ksize < 0)
610                 scale *= 2.0;
611             if (depth == CV_8U)
612                 scale *= 255.0;
613             scale = std::pow(scale, -4.0);
614
615             if (ippiHarrisCornerGetBufferSize(roisize, masksize, blockSize, datatype, cn, &bufsize) >= 0)
616             {
617                 Ipp8u * buffer = (Ipp8u*)CV_IPP_MALLOC(bufsize);
618                 IppiDifferentialKernel filterType = ksize > 0 ? ippFilterSobel : ippFilterScharr;
619                 IppiBorderType borderTypeIpp = borderTypeNI == BORDER_CONSTANT ? ippBorderConst : ippBorderRepl;
620                 IppStatus status = (IppStatus)-1;
621
622                 if (depth == CV_8U)
623                     status = CV_INSTRUMENT_FUN_IPP(ippiHarrisCorner_8u32f_C1R, (const Ipp8u *)src.data, (int)src.step, (Ipp32f *)dst.data, (int)dst.step, roisize,
624                         filterType, masksize, blockSize, (Ipp32f)k, (Ipp32f)scale, borderTypeIpp, 0, buffer);
625                 else if (depth == CV_32F)
626                     status = CV_INSTRUMENT_FUN_IPP(ippiHarrisCorner_32f_C1R, (const Ipp32f *)src.data, (int)src.step, (Ipp32f *)dst.data, (int)dst.step, roisize,
627                         filterType, masksize, blockSize, (Ipp32f)k, (Ipp32f)scale, borderTypeIpp, 0, buffer);
628                 ippsFree(buffer);
629
630                 if (status >= 0)
631                 {
632                     CV_IMPL_ADD(CV_IMPL_IPP);
633                     return true;
634                 }
635             }
636         }
637     }
638 #else
639     CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(blockSize);  CV_UNUSED(ksize); CV_UNUSED(k); CV_UNUSED(borderType);
640 #endif
641     return false;
642 }
643 }
644 #endif
645
646 void cv::cornerHarris( InputArray _src, OutputArray _dst, int blockSize, int ksize, double k, int borderType )
647 {
648     CV_INSTRUMENT_REGION()
649
650     CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
651                ocl_cornerMinEigenValVecs(_src, _dst, blockSize, ksize, k, borderType, HARRIS))
652
653     Mat src = _src.getMat();
654     _dst.create( src.size(), CV_32FC1 );
655     Mat dst = _dst.getMat();
656
657 #ifdef HAVE_IPP
658     int borderTypeNI = borderType & ~BORDER_ISOLATED;
659     bool isolated = (borderType & BORDER_ISOLATED) != 0;
660 #endif
661     CV_IPP_RUN(((ksize == 3 || ksize == 5) && (_src.type() == CV_8UC1 || _src.type() == CV_32FC1) &&
662         (borderTypeNI == BORDER_CONSTANT || borderTypeNI == BORDER_REPLICATE) && CV_MAT_CN(_src.type()) == 1 &&
663         (!_src.isSubmatrix() || isolated)) && IPP_VERSION_X100 >= 810, ipp_cornerHarris( src, dst, blockSize, ksize, k, borderType ));
664
665     cornerEigenValsVecs( src, dst, blockSize, ksize, HARRIS, k, borderType );
666 }
667
668
669 void cv::cornerEigenValsAndVecs( InputArray _src, OutputArray _dst, int blockSize, int ksize, int borderType )
670 {
671     CV_INSTRUMENT_REGION()
672
673     Mat src = _src.getMat();
674     Size dsz = _dst.size();
675     int dtype = _dst.type();
676
677     if( dsz.height != src.rows || dsz.width*CV_MAT_CN(dtype) != src.cols*6 || CV_MAT_DEPTH(dtype) != CV_32F )
678         _dst.create( src.size(), CV_32FC(6) );
679     Mat dst = _dst.getMat();
680     cornerEigenValsVecs( src, dst, blockSize, ksize, EIGENVALSVECS, 0, borderType );
681 }
682
683
684 void cv::preCornerDetect( InputArray _src, OutputArray _dst, int ksize, int borderType )
685 {
686     CV_INSTRUMENT_REGION()
687
688     int type = _src.type();
689     CV_Assert( type == CV_8UC1 || type == CV_32FC1 );
690
691     CV_OCL_RUN( _src.dims() <= 2 && _dst.isUMat(),
692                 ocl_preCornerDetect(_src, _dst, ksize, borderType, CV_MAT_DEPTH(type)))
693
694     Mat Dx, Dy, D2x, D2y, Dxy, src = _src.getMat();
695     _dst.create( src.size(), CV_32FC1 );
696     Mat dst = _dst.getMat();
697
698     Sobel( src, Dx, CV_32F, 1, 0, ksize, 1, 0, borderType );
699     Sobel( src, Dy, CV_32F, 0, 1, ksize, 1, 0, borderType );
700     Sobel( src, D2x, CV_32F, 2, 0, ksize, 1, 0, borderType );
701     Sobel( src, D2y, CV_32F, 0, 2, ksize, 1, 0, borderType );
702     Sobel( src, Dxy, CV_32F, 1, 1, ksize, 1, 0, borderType );
703
704     double factor = 1 << (ksize - 1);
705     if( src.depth() == CV_8U )
706         factor *= 255;
707     factor = 1./(factor * factor * factor);
708 #if CV_SIMD128
709     float factor_f = (float)factor;
710     bool haveSimd = hasSIMD128();
711     v_float32x4 v_factor = v_setall_f32(factor_f), v_m2 = v_setall_f32(-2.0f);
712 #endif
713
714     Size size = src.size();
715     int i, j;
716     for( i = 0; i < size.height; i++ )
717     {
718         float* dstdata = dst.ptr<float>(i);
719         const float* dxdata = Dx.ptr<float>(i);
720         const float* dydata = Dy.ptr<float>(i);
721         const float* d2xdata = D2x.ptr<float>(i);
722         const float* d2ydata = D2y.ptr<float>(i);
723         const float* dxydata = Dxy.ptr<float>(i);
724
725         j = 0;
726
727 #if CV_SIMD128
728         if (haveSimd)
729         {
730             for( ; j <= size.width - v_float32x4::nlanes; j += v_float32x4::nlanes )
731             {
732                 v_float32x4 v_dx = v_load(dxdata + j);
733                 v_float32x4 v_dy = v_load(dydata + j);
734
735                 v_float32x4 v_s1 = (v_dx * v_dx) * v_load(d2ydata + j);
736                 v_float32x4 v_s2 = v_muladd((v_dy * v_dy),  v_load(d2xdata + j), v_s1);
737                 v_float32x4 v_s3 = v_muladd((v_dy * v_dx) * v_load(dxydata + j), v_m2, v_s2);
738
739                 v_store(dstdata + j, v_s3 * v_factor);
740             }
741         }
742 #endif
743
744         for( ; j < size.width; j++ )
745         {
746             float dx = dxdata[j];
747             float dy = dydata[j];
748             dstdata[j] = (float)(factor*(dx*dx*d2ydata[j] + dy*dy*d2xdata[j] - 2*dx*dy*dxydata[j]));
749         }
750     }
751 }
752
753 CV_IMPL void
754 cvCornerMinEigenVal( const CvArr* srcarr, CvArr* dstarr,
755                      int block_size, int aperture_size )
756 {
757     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
758
759     CV_Assert( src.size() == dst.size() && dst.type() == CV_32FC1 );
760     cv::cornerMinEigenVal( src, dst, block_size, aperture_size, cv::BORDER_REPLICATE );
761 }
762
763 CV_IMPL void
764 cvCornerHarris( const CvArr* srcarr, CvArr* dstarr,
765                 int block_size, int aperture_size, double k )
766 {
767     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
768
769     CV_Assert( src.size() == dst.size() && dst.type() == CV_32FC1 );
770     cv::cornerHarris( src, dst, block_size, aperture_size, k, cv::BORDER_REPLICATE );
771 }
772
773
774 CV_IMPL void
775 cvCornerEigenValsAndVecs( const void* srcarr, void* dstarr,
776                           int block_size, int aperture_size )
777 {
778     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
779
780     CV_Assert( src.rows == dst.rows && src.cols*6 == dst.cols*dst.channels() && dst.depth() == CV_32F );
781     cv::cornerEigenValsAndVecs( src, dst, block_size, aperture_size, cv::BORDER_REPLICATE );
782 }
783
784
785 CV_IMPL void
786 cvPreCornerDetect( const void* srcarr, void* dstarr, int aperture_size )
787 {
788     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
789
790     CV_Assert( src.size() == dst.size() && dst.type() == CV_32FC1 );
791     cv::preCornerDetect( src, dst, aperture_size, cv::BORDER_REPLICATE );
792 }
793
794 /* End of file */