• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41 #include "precomp.hpp"
42 
43 namespace cv
44 {
45 
intersectLines(double x1,double dx1,double y1,double dy1,double x2,double dx2,double y2,double dy2,double * t2)46 static int intersectLines( double x1, double dx1, double y1, double dy1,
47                           double x2, double dx2, double y2, double dy2, double *t2 )
48 {
49     double d = dx1 * dy2 - dx2 * dy1;
50     int result = -1;
51 
52     if( d != 0 )
53     {
54         *t2 = ((x2 - x1) * dy1 - (y2 - y1) * dx1) / d;
55         result = 0;
56     }
57     return result;
58 }
59 
findCircle(Point2f pt0,Point2f pt1,Point2f pt2,Point2f * center,float * radius)60 static bool findCircle( Point2f pt0, Point2f pt1, Point2f pt2,
61                        Point2f* center, float* radius )
62 {
63     double x1 = (pt0.x + pt1.x) * 0.5;
64     double dy1 = pt0.x - pt1.x;
65     double x2 = (pt1.x + pt2.x) * 0.5;
66     double dy2 = pt1.x - pt2.x;
67     double y1 = (pt0.y + pt1.y) * 0.5;
68     double dx1 = pt1.y - pt0.y;
69     double y2 = (pt1.y + pt2.y) * 0.5;
70     double dx2 = pt2.y - pt1.y;
71     double t = 0;
72 
73     if( intersectLines( x1, dx1, y1, dy1, x2, dx2, y2, dy2, &t ) >= 0 )
74     {
75         center->x = (float) (x2 + dx2 * t);
76         center->y = (float) (y2 + dy2 * t);
77         *radius = (float)norm(*center - pt0);
78         return true;
79     }
80 
81     center->x = center->y = 0.f;
82     *radius = 0;
83     return false;
84 }
85 
86 
pointInCircle(Point2f pt,Point2f center,float radius)87 static double pointInCircle( Point2f pt, Point2f center, float radius )
88 {
89     double dx = pt.x - center.x;
90     double dy = pt.y - center.y;
91     return (double)radius*radius - dx*dx - dy*dy;
92 }
93 
94 
findEnslosingCicle4pts_32f(Point2f * pts,Point2f & _center,float & _radius)95 static int findEnslosingCicle4pts_32f( Point2f* pts, Point2f& _center, float& _radius )
96 {
97     int shuffles[4][4] = { {0, 1, 2, 3}, {0, 1, 3, 2}, {2, 3, 0, 1}, {2, 3, 1, 0} };
98 
99     int idxs[4] = { 0, 1, 2, 3 };
100     int i, j, k = 1, mi = 0;
101     float max_dist = 0;
102     Point2f center;
103     Point2f min_center;
104     float radius, min_radius = FLT_MAX;
105     Point2f res_pts[4];
106 
107     center = min_center = pts[0];
108     radius = 1.f;
109 
110     for( i = 0; i < 4; i++ )
111         for( j = i + 1; j < 4; j++ )
112         {
113             float dist = (float)norm(pts[i] - pts[j]);
114 
115             if( max_dist < dist )
116             {
117                 max_dist = dist;
118                 idxs[0] = i;
119                 idxs[1] = j;
120             }
121         }
122 
123     if( max_dist > 0 )
124     {
125         k = 2;
126         for( i = 0; i < 4; i++ )
127         {
128             for( j = 0; j < k; j++ )
129                 if( i == idxs[j] )
130                     break;
131             if( j == k )
132                 idxs[k++] = i;
133         }
134 
135         center = Point2f( (pts[idxs[0]].x + pts[idxs[1]].x)*0.5f,
136                           (pts[idxs[0]].y + pts[idxs[1]].y)*0.5f );
137         radius = (float)(norm(pts[idxs[0]] - center)*1.03);
138         if( radius < 1.f )
139             radius = 1.f;
140 
141         if( pointInCircle( pts[idxs[2]], center, radius ) >= 0 &&
142             pointInCircle( pts[idxs[3]], center, radius ) >= 0 )
143         {
144             k = 2; //rand()%2+2;
145         }
146         else
147         {
148             mi = -1;
149             for( i = 0; i < 4; i++ )
150             {
151                 if( findCircle( pts[shuffles[i][0]], pts[shuffles[i][1]],
152                                 pts[shuffles[i][2]], &center, &radius ) )
153                 {
154                     radius *= 1.03f;
155                     if( radius < 2.f )
156                         radius = 2.f;
157 
158                     if( pointInCircle( pts[shuffles[i][3]], center, radius ) >= 0 &&
159                         min_radius > radius )
160                     {
161                         min_radius = radius;
162                         min_center = center;
163                         mi = i;
164                     }
165                 }
166             }
167             CV_Assert( mi >= 0 );
168             if( mi < 0 )
169                 mi = 0;
170             k = 3;
171             center = min_center;
172             radius = min_radius;
173             for( i = 0; i < 4; i++ )
174                 idxs[i] = shuffles[mi][i];
175         }
176     }
177 
178     _center = center;
179     _radius = radius;
180 
181     /* reorder output points */
182     for( i = 0; i < 4; i++ )
183         res_pts[i] = pts[idxs[i]];
184 
185     for( i = 0; i < 4; i++ )
186     {
187         pts[i] = res_pts[i];
188         CV_Assert( pointInCircle( pts[i], center, radius ) >= 0 );
189     }
190 
191     return k;
192 }
193 
194 }
195 
minEnclosingCircle(InputArray _points,Point2f & _center,float & _radius)196 void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radius )
197 {
198     int max_iters = 100;
199     const float eps = FLT_EPSILON*2;
200     bool result = false;
201     Mat points = _points.getMat();
202     int i, j, k, count = points.checkVector(2);
203     int depth = points.depth();
204     Point2f center;
205     float radius = 0.f;
206     CV_Assert(count >= 0 && (depth == CV_32F || depth == CV_32S));
207 
208     _center.x = _center.y = 0.f;
209     _radius = 0.f;
210 
211     if( count == 0 )
212         return;
213 
214     bool is_float = depth == CV_32F;
215     const Point* ptsi = points.ptr<Point>();
216     const Point2f* ptsf = points.ptr<Point2f>();
217 
218     Point2f pt = is_float ? ptsf[0] : Point2f((float)ptsi[0].x,(float)ptsi[0].y);
219     Point2f pts[4] = {pt, pt, pt, pt};
220 
221     for( i = 1; i < count; i++ )
222     {
223         pt = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
224 
225         if( pt.x < pts[0].x )
226             pts[0] = pt;
227         if( pt.x > pts[1].x )
228             pts[1] = pt;
229         if( pt.y < pts[2].y )
230             pts[2] = pt;
231         if( pt.y > pts[3].y )
232             pts[3] = pt;
233     }
234 
235     for( k = 0; k < max_iters; k++ )
236     {
237         double min_delta = 0, delta;
238         Point2f farAway(0,0);
239         /*only for first iteration because the alg is repared at the loop's foot*/
240         if( k == 0 )
241             findEnslosingCicle4pts_32f( pts, center, radius );
242 
243         for( i = 0; i < count; i++ )
244         {
245             pt = is_float ? ptsf[i] : Point2f((float)ptsi[i].x,(float)ptsi[i].y);
246 
247             delta = pointInCircle( pt, center, radius );
248             if( delta < min_delta )
249             {
250                 min_delta = delta;
251                 farAway = pt;
252             }
253         }
254         result = min_delta >= 0;
255         if( result )
256             break;
257 
258         Point2f ptsCopy[4];
259         // find good replacement partner for the point which is at most far away,
260         // starting with the one that lays in the actual circle (i=3)
261         for( i = 3; i >= 0; i-- )
262         {
263             for( j = 0; j < 4; j++ )
264                 ptsCopy[j] = i != j ? pts[j] : farAway;
265 
266             findEnslosingCicle4pts_32f( ptsCopy, center, radius );
267             if( pointInCircle( pts[i], center, radius ) >= 0)
268             {
269                 // replaced one again in the new circle?
270                 pts[i] = farAway;
271                 break;
272             }
273         }
274     }
275 
276     if( !result )
277     {
278         radius = 0.f;
279         for( i = 0; i < count; i++ )
280         {
281             pt = is_float ? ptsf[i] : Point2f((float)ptsi[i].x,(float)ptsi[i].y);
282             float dx = center.x - pt.x, dy = center.y - pt.y;
283             float t = dx*dx + dy*dy;
284             radius = MAX(radius, t);
285         }
286 
287         radius = (float)(std::sqrt(radius)*(1 + eps));
288     }
289 
290     _center = center;
291     _radius = radius;
292 }
293 
294 
295 // calculates length of a curve (e.g. contour perimeter)
arcLength(InputArray _curve,bool is_closed)296 double cv::arcLength( InputArray _curve, bool is_closed )
297 {
298     Mat curve = _curve.getMat();
299     int count = curve.checkVector(2);
300     int depth = curve.depth();
301     CV_Assert( count >= 0 && (depth == CV_32F || depth == CV_32S));
302     double perimeter = 0;
303 
304     int i, j = 0;
305     const int N = 16;
306     float buf[N];
307 
308     if( count <= 1 )
309         return 0.;
310 
311     bool is_float = depth == CV_32F;
312     int last = is_closed ? count-1 : 0;
313     const Point* pti = curve.ptr<Point>();
314     const Point2f* ptf = curve.ptr<Point2f>();
315 
316     Point2f prev = is_float ? ptf[last] : Point2f((float)pti[last].x,(float)pti[last].y);
317 
318     for( i = 0; i < count; i++ )
319     {
320         Point2f p = is_float ? ptf[i] : Point2f((float)pti[i].x,(float)pti[i].y);
321         float dx = p.x - prev.x, dy = p.y - prev.y;
322         buf[j] = dx*dx + dy*dy;
323 
324         if( ++j == N || i == count-1 )
325         {
326             Mat bufmat(1, j, CV_32F, buf);
327             sqrt(bufmat, bufmat);
328             for( ; j > 0; j-- )
329                 perimeter += buf[j-1];
330         }
331         prev = p;
332     }
333 
334     return perimeter;
335 }
336 
337 // area of a whole sequence
contourArea(InputArray _contour,bool oriented)338 double cv::contourArea( InputArray _contour, bool oriented )
339 {
340     Mat contour = _contour.getMat();
341     int npoints = contour.checkVector(2);
342     int depth = contour.depth();
343     CV_Assert(npoints >= 0 && (depth == CV_32F || depth == CV_32S));
344 
345     if( npoints == 0 )
346         return 0.;
347 
348     double a00 = 0;
349     bool is_float = depth == CV_32F;
350     const Point* ptsi = contour.ptr<Point>();
351     const Point2f* ptsf = contour.ptr<Point2f>();
352     Point2f prev = is_float ? ptsf[npoints-1] : Point2f((float)ptsi[npoints-1].x, (float)ptsi[npoints-1].y);
353 
354     for( int i = 0; i < npoints; i++ )
355     {
356         Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
357         a00 += (double)prev.x * p.y - (double)prev.y * p.x;
358         prev = p;
359     }
360 
361     a00 *= 0.5;
362     if( !oriented )
363         a00 = fabs(a00);
364 
365     return a00;
366 }
367 
368 
fitEllipse(InputArray _points)369 cv::RotatedRect cv::fitEllipse( InputArray _points )
370 {
371     Mat points = _points.getMat();
372     int i, n = points.checkVector(2);
373     int depth = points.depth();
374     CV_Assert( n >= 0 && (depth == CV_32F || depth == CV_32S));
375 
376     RotatedRect box;
377 
378     if( n < 5 )
379         CV_Error( CV_StsBadSize, "There should be at least 5 points to fit the ellipse" );
380 
381     // New fitellipse algorithm, contributed by Dr. Daniel Weiss
382     Point2f c(0,0);
383     double gfp[5], rp[5], t;
384     const double min_eps = 1e-8;
385     bool is_float = depth == CV_32F;
386     const Point* ptsi = points.ptr<Point>();
387     const Point2f* ptsf = points.ptr<Point2f>();
388 
389     AutoBuffer<double> _Ad(n*5), _bd(n);
390     double *Ad = _Ad, *bd = _bd;
391 
392     // first fit for parameters A - E
393     Mat A( n, 5, CV_64F, Ad );
394     Mat b( n, 1, CV_64F, bd );
395     Mat x( 5, 1, CV_64F, gfp );
396 
397     for( i = 0; i < n; i++ )
398     {
399         Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
400         c += p;
401     }
402     c.x /= n;
403     c.y /= n;
404 
405     for( i = 0; i < n; i++ )
406     {
407         Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
408         p -= c;
409 
410         bd[i] = 10000.0; // 1.0?
411         Ad[i*5] = -(double)p.x * p.x; // A - C signs inverted as proposed by APP
412         Ad[i*5 + 1] = -(double)p.y * p.y;
413         Ad[i*5 + 2] = -(double)p.x * p.y;
414         Ad[i*5 + 3] = p.x;
415         Ad[i*5 + 4] = p.y;
416     }
417 
418     solve(A, b, x, DECOMP_SVD);
419 
420     // now use general-form parameters A - E to find the ellipse center:
421     // differentiate general form wrt x/y to get two equations for cx and cy
422     A = Mat( 2, 2, CV_64F, Ad );
423     b = Mat( 2, 1, CV_64F, bd );
424     x = Mat( 2, 1, CV_64F, rp );
425     Ad[0] = 2 * gfp[0];
426     Ad[1] = Ad[2] = gfp[2];
427     Ad[3] = 2 * gfp[1];
428     bd[0] = gfp[3];
429     bd[1] = gfp[4];
430     solve( A, b, x, DECOMP_SVD );
431 
432     // re-fit for parameters A - C with those center coordinates
433     A = Mat( n, 3, CV_64F, Ad );
434     b = Mat( n, 1, CV_64F, bd );
435     x = Mat( 3, 1, CV_64F, gfp );
436     for( i = 0; i < n; i++ )
437     {
438         Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
439         p -= c;
440         bd[i] = 1.0;
441         Ad[i * 3] = (p.x - rp[0]) * (p.x - rp[0]);
442         Ad[i * 3 + 1] = (p.y - rp[1]) * (p.y - rp[1]);
443         Ad[i * 3 + 2] = (p.x - rp[0]) * (p.y - rp[1]);
444     }
445     solve(A, b, x, DECOMP_SVD);
446 
447     // store angle and radii
448     rp[4] = -0.5 * atan2(gfp[2], gfp[1] - gfp[0]); // convert from APP angle usage
449     if( fabs(gfp[2]) > min_eps )
450         t = gfp[2]/sin(-2.0 * rp[4]);
451     else // ellipse is rotated by an integer multiple of pi/2
452         t = gfp[1] - gfp[0];
453     rp[2] = fabs(gfp[0] + gfp[1] - t);
454     if( rp[2] > min_eps )
455         rp[2] = std::sqrt(2.0 / rp[2]);
456     rp[3] = fabs(gfp[0] + gfp[1] + t);
457     if( rp[3] > min_eps )
458         rp[3] = std::sqrt(2.0 / rp[3]);
459 
460     box.center.x = (float)rp[0] + c.x;
461     box.center.y = (float)rp[1] + c.y;
462     box.size.width = (float)(rp[2]*2);
463     box.size.height = (float)(rp[3]*2);
464     if( box.size.width > box.size.height )
465     {
466         float tmp;
467         CV_SWAP( box.size.width, box.size.height, tmp );
468         box.angle = (float)(90 + rp[4]*180/CV_PI);
469     }
470     if( box.angle < -180 )
471         box.angle += 360;
472     if( box.angle > 360 )
473         box.angle -= 360;
474 
475     return box;
476 }
477 
478 
479 namespace cv
480 {
481 
482 // Calculates bounding rectagnle of a point set or retrieves already calculated
pointSetBoundingRect(const Mat & points)483 static Rect pointSetBoundingRect( const Mat& points )
484 {
485     int npoints = points.checkVector(2);
486     int depth = points.depth();
487     CV_Assert(npoints >= 0 && (depth == CV_32F || depth == CV_32S));
488 
489     int  xmin = 0, ymin = 0, xmax = -1, ymax = -1, i;
490     bool is_float = depth == CV_32F;
491 
492     if( npoints == 0 )
493         return Rect();
494 
495     const Point* pts = points.ptr<Point>();
496     Point pt = pts[0];
497 
498 #if CV_SSE4_2
499     if(cv::checkHardwareSupport(CV_CPU_SSE4_2))
500     {
501         if( !is_float )
502         {
503             __m128i minval, maxval;
504             minval = maxval = _mm_loadl_epi64((const __m128i*)(&pt)); //min[0]=pt.x, min[1]=pt.y
505 
506             for( i = 1; i < npoints; i++ )
507             {
508                 __m128i ptXY = _mm_loadl_epi64((const __m128i*)&pts[i]);
509                 minval = _mm_min_epi32(ptXY, minval);
510                 maxval = _mm_max_epi32(ptXY, maxval);
511             }
512             xmin = _mm_cvtsi128_si32(minval);
513             ymin = _mm_cvtsi128_si32(_mm_srli_si128(minval, 4));
514             xmax = _mm_cvtsi128_si32(maxval);
515             ymax = _mm_cvtsi128_si32(_mm_srli_si128(maxval, 4));
516         }
517         else
518         {
519             __m128 minvalf, maxvalf, z = _mm_setzero_ps(), ptXY = _mm_setzero_ps();
520             minvalf = maxvalf = _mm_loadl_pi(z, (const __m64*)(&pt));
521 
522             for( i = 1; i < npoints; i++ )
523             {
524                 ptXY = _mm_loadl_pi(ptXY, (const __m64*)&pts[i]);
525 
526                 minvalf = _mm_min_ps(minvalf, ptXY);
527                 maxvalf = _mm_max_ps(maxvalf, ptXY);
528             }
529 
530             float xyminf[2], xymaxf[2];
531             _mm_storel_pi((__m64*)xyminf, minvalf);
532             _mm_storel_pi((__m64*)xymaxf, maxvalf);
533             xmin = cvFloor(xyminf[0]);
534             ymin = cvFloor(xyminf[1]);
535             xmax = cvFloor(xymaxf[0]);
536             ymax = cvFloor(xymaxf[1]);
537         }
538     }
539     else
540 #endif
541     {
542         if( !is_float )
543         {
544             xmin = xmax = pt.x;
545             ymin = ymax = pt.y;
546 
547             for( i = 1; i < npoints; i++ )
548             {
549                 pt = pts[i];
550 
551                 if( xmin > pt.x )
552                     xmin = pt.x;
553 
554                 if( xmax < pt.x )
555                     xmax = pt.x;
556 
557                 if( ymin > pt.y )
558                     ymin = pt.y;
559 
560                 if( ymax < pt.y )
561                     ymax = pt.y;
562             }
563         }
564         else
565         {
566             Cv32suf v;
567             // init values
568             xmin = xmax = CV_TOGGLE_FLT(pt.x);
569             ymin = ymax = CV_TOGGLE_FLT(pt.y);
570 
571             for( i = 1; i < npoints; i++ )
572             {
573                 pt = pts[i];
574                 pt.x = CV_TOGGLE_FLT(pt.x);
575                 pt.y = CV_TOGGLE_FLT(pt.y);
576 
577                 if( xmin > pt.x )
578                     xmin = pt.x;
579 
580                 if( xmax < pt.x )
581                     xmax = pt.x;
582 
583                 if( ymin > pt.y )
584                     ymin = pt.y;
585 
586                 if( ymax < pt.y )
587                     ymax = pt.y;
588             }
589 
590             v.i = CV_TOGGLE_FLT(xmin); xmin = cvFloor(v.f);
591             v.i = CV_TOGGLE_FLT(ymin); ymin = cvFloor(v.f);
592             // because right and bottom sides of the bounding rectangle are not inclusive
593             // (note +1 in width and height calculation below), cvFloor is used here instead of cvCeil
594             v.i = CV_TOGGLE_FLT(xmax); xmax = cvFloor(v.f);
595             v.i = CV_TOGGLE_FLT(ymax); ymax = cvFloor(v.f);
596         }
597     }
598 
599     return Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
600 }
601 
602 
maskBoundingRect(const Mat & img)603 static Rect maskBoundingRect( const Mat& img )
604 {
605     CV_Assert( img.depth() <= CV_8S && img.channels() == 1 );
606 
607     Size size = img.size();
608     int xmin = size.width, ymin = -1, xmax = -1, ymax = -1, i, j, k;
609 
610     for( i = 0; i < size.height; i++ )
611     {
612         const uchar* _ptr = img.ptr(i);
613         const uchar* ptr = (const uchar*)alignPtr(_ptr, 4);
614         int have_nz = 0, k_min, offset = (int)(ptr - _ptr);
615         j = 0;
616         offset = MIN(offset, size.width);
617         for( ; j < offset; j++ )
618             if( _ptr[j] )
619             {
620                 have_nz = 1;
621                 break;
622             }
623         if( j < offset )
624         {
625             if( j < xmin )
626                 xmin = j;
627             if( j > xmax )
628                 xmax = j;
629         }
630         if( offset < size.width )
631         {
632             xmin -= offset;
633             xmax -= offset;
634             size.width -= offset;
635             j = 0;
636             for( ; j <= xmin - 4; j += 4 )
637                 if( *((int*)(ptr+j)) )
638                     break;
639             for( ; j < xmin; j++ )
640                 if( ptr[j] )
641                 {
642                     xmin = j;
643                     if( j > xmax )
644                         xmax = j;
645                     have_nz = 1;
646                     break;
647                 }
648             k_min = MAX(j-1, xmax);
649             k = size.width - 1;
650             for( ; k > k_min && (k&3) != 3; k-- )
651                 if( ptr[k] )
652                     break;
653             if( k > k_min && (k&3) == 3 )
654             {
655                 for( ; k > k_min+3; k -= 4 )
656                     if( *((int*)(ptr+k-3)) )
657                         break;
658             }
659             for( ; k > k_min; k-- )
660                 if( ptr[k] )
661                 {
662                     xmax = k;
663                     have_nz = 1;
664                     break;
665                 }
666             if( !have_nz )
667             {
668                 j &= ~3;
669                 for( ; j <= k - 3; j += 4 )
670                     if( *((int*)(ptr+j)) )
671                         break;
672                 for( ; j <= k; j++ )
673                     if( ptr[j] )
674                     {
675                         have_nz = 1;
676                         break;
677                     }
678             }
679             xmin += offset;
680             xmax += offset;
681             size.width += offset;
682         }
683         if( have_nz )
684         {
685             if( ymin < 0 )
686                 ymin = i;
687             ymax = i;
688         }
689     }
690 
691     if( xmin >= size.width )
692         xmin = ymin = 0;
693     return Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
694 }
695 
696 }
697 
boundingRect(InputArray array)698 cv::Rect cv::boundingRect(InputArray array)
699 {
700     Mat m = array.getMat();
701     return m.depth() <= CV_8U ? maskBoundingRect(m) : pointSetBoundingRect(m);
702 }
703 
704 ////////////////////////////////////////////// C API ///////////////////////////////////////////
705 
706 CV_IMPL int
cvMinEnclosingCircle(const void * array,CvPoint2D32f * _center,float * _radius)707 cvMinEnclosingCircle( const void* array, CvPoint2D32f * _center, float *_radius )
708 {
709     cv::AutoBuffer<double> abuf;
710     cv::Mat points = cv::cvarrToMat(array, false, false, 0, &abuf);
711     cv::Point2f center;
712     float radius;
713 
714     cv::minEnclosingCircle(points, center, radius);
715     if(_center)
716         *_center = center;
717     if(_radius)
718         *_radius = radius;
719     return 1;
720 }
721 
722 static void
icvMemCopy(double ** buf1,double ** buf2,double ** buf3,int * b_max)723 icvMemCopy( double **buf1, double **buf2, double **buf3, int *b_max )
724 {
725     CV_Assert( (*buf1 != NULL || *buf2 != NULL) && *buf3 != NULL );
726 
727     int bb = *b_max;
728     if( *buf2 == NULL )
729     {
730         *b_max = 2 * (*b_max);
731         *buf2 = (double *)cvAlloc( (*b_max) * sizeof( double ));
732 
733         memcpy( *buf2, *buf3, bb * sizeof( double ));
734 
735         *buf3 = *buf2;
736         cvFree( buf1 );
737         *buf1 = NULL;
738     }
739     else
740     {
741         *b_max = 2 * (*b_max);
742         *buf1 = (double *) cvAlloc( (*b_max) * sizeof( double ));
743 
744         memcpy( *buf1, *buf3, bb * sizeof( double ));
745 
746         *buf3 = *buf1;
747         cvFree( buf2 );
748         *buf2 = NULL;
749     }
750 }
751 
752 
753 /* area of a contour sector */
icvContourSecArea(CvSeq * contour,CvSlice slice)754 static double icvContourSecArea( CvSeq * contour, CvSlice slice )
755 {
756     CvPoint pt;                 /*  pointer to points   */
757     CvPoint pt_s, pt_e;         /*  first and last points  */
758     CvSeqReader reader;         /*  points reader of contour   */
759 
760     int p_max = 2, p_ind;
761     int lpt, flag, i;
762     double a00;                 /* unnormalized moments m00    */
763     double xi, yi, xi_1, yi_1, x0, y0, dxy, sk, sk1, t;
764     double x_s, y_s, nx, ny, dx, dy, du, dv;
765     double eps = 1.e-5;
766     double *p_are1, *p_are2, *p_are;
767     double area = 0;
768 
769     CV_Assert( contour != NULL && CV_IS_SEQ_POINT_SET( contour ));
770 
771     lpt = cvSliceLength( slice, contour );
772     /*if( n2 >= n1 )
773         lpt = n2 - n1 + 1;
774     else
775         lpt = contour->total - n1 + n2 + 1;*/
776 
777     if( contour->total <= 0 || lpt <= 2 )
778         return 0.;
779 
780     a00 = x0 = y0 = xi_1 = yi_1 = 0;
781     sk1 = 0;
782     flag = 0;
783     dxy = 0;
784     p_are1 = (double *) cvAlloc( p_max * sizeof( double ));
785 
786     p_are = p_are1;
787     p_are2 = NULL;
788 
789     cvStartReadSeq( contour, &reader, 0 );
790     cvSetSeqReaderPos( &reader, slice.start_index );
791     CV_READ_SEQ_ELEM( pt_s, reader );
792     p_ind = 0;
793     cvSetSeqReaderPos( &reader, slice.end_index );
794     CV_READ_SEQ_ELEM( pt_e, reader );
795 
796 /*    normal coefficients    */
797     nx = pt_s.y - pt_e.y;
798     ny = pt_e.x - pt_s.x;
799     cvSetSeqReaderPos( &reader, slice.start_index );
800 
801     while( lpt-- > 0 )
802     {
803         CV_READ_SEQ_ELEM( pt, reader );
804 
805         if( flag == 0 )
806         {
807             xi_1 = (double) pt.x;
808             yi_1 = (double) pt.y;
809             x0 = xi_1;
810             y0 = yi_1;
811             sk1 = 0;
812             flag = 1;
813         }
814         else
815         {
816             xi = (double) pt.x;
817             yi = (double) pt.y;
818 
819 /****************   edges intersection examination   **************************/
820             sk = nx * (xi - pt_s.x) + ny * (yi - pt_s.y);
821             if( (fabs( sk ) < eps && lpt > 0) || sk * sk1 < -eps )
822             {
823                 if( fabs( sk ) < eps )
824                 {
825                     dxy = xi_1 * yi - xi * yi_1;
826                     a00 = a00 + dxy;
827                     dxy = xi * y0 - x0 * yi;
828                     a00 = a00 + dxy;
829 
830                     if( p_ind >= p_max )
831                         icvMemCopy( &p_are1, &p_are2, &p_are, &p_max );
832 
833                     p_are[p_ind] = a00 / 2.;
834                     p_ind++;
835                     a00 = 0;
836                     sk1 = 0;
837                     x0 = xi;
838                     y0 = yi;
839                     dxy = 0;
840                 }
841                 else
842                 {
843 /*  define intersection point    */
844                     dv = yi - yi_1;
845                     du = xi - xi_1;
846                     dx = ny;
847                     dy = -nx;
848                     if( fabs( du ) > eps )
849                         t = ((yi_1 - pt_s.y) * du + dv * (pt_s.x - xi_1)) /
850                             (du * dy - dx * dv);
851                     else
852                         t = (xi_1 - pt_s.x) / dx;
853                     if( t > eps && t < 1 - eps )
854                     {
855                         x_s = pt_s.x + t * dx;
856                         y_s = pt_s.y + t * dy;
857                         dxy = xi_1 * y_s - x_s * yi_1;
858                         a00 += dxy;
859                         dxy = x_s * y0 - x0 * y_s;
860                         a00 += dxy;
861                         if( p_ind >= p_max )
862                             icvMemCopy( &p_are1, &p_are2, &p_are, &p_max );
863 
864                         p_are[p_ind] = a00 / 2.;
865                         p_ind++;
866 
867                         a00 = 0;
868                         sk1 = 0;
869                         x0 = x_s;
870                         y0 = y_s;
871                         dxy = x_s * yi - xi * y_s;
872                     }
873                 }
874             }
875             else
876                 dxy = xi_1 * yi - xi * yi_1;
877 
878             a00 += dxy;
879             xi_1 = xi;
880             yi_1 = yi;
881             sk1 = sk;
882 
883         }
884     }
885 
886     xi = x0;
887     yi = y0;
888     dxy = xi_1 * yi - xi * yi_1;
889 
890     a00 += dxy;
891 
892     if( p_ind >= p_max )
893         icvMemCopy( &p_are1, &p_are2, &p_are, &p_max );
894 
895     p_are[p_ind] = a00 / 2.;
896     p_ind++;
897 
898     // common area calculation
899     area = 0;
900     for( i = 0; i < p_ind; i++ )
901         area += fabs( p_are[i] );
902 
903     if( p_are1 != NULL )
904         cvFree( &p_are1 );
905     else if( p_are2 != NULL )
906         cvFree( &p_are2 );
907 
908     return area;
909 }
910 
911 
912 /* external contour area function */
913 CV_IMPL double
cvContourArea(const void * array,CvSlice slice,int oriented)914 cvContourArea( const void *array, CvSlice slice, int oriented )
915 {
916     double area = 0;
917 
918     CvContour contour_header;
919     CvSeq* contour = 0;
920     CvSeqBlock block;
921 
922     if( CV_IS_SEQ( array ))
923     {
924         contour = (CvSeq*)array;
925         if( !CV_IS_SEQ_POLYLINE( contour ))
926             CV_Error( CV_StsBadArg, "Unsupported sequence type" );
927     }
928     else
929     {
930         contour = cvPointSeqFromMat( CV_SEQ_KIND_CURVE, array, &contour_header, &block );
931     }
932 
933     if( cvSliceLength( slice, contour ) == contour->total )
934     {
935         cv::AutoBuffer<double> abuf;
936         cv::Mat points = cv::cvarrToMat(contour, false, false, 0, &abuf);
937         return cv::contourArea( points, oriented !=0 );
938     }
939 
940     if( CV_SEQ_ELTYPE( contour ) != CV_32SC2 )
941         CV_Error( CV_StsUnsupportedFormat,
942         "Only curves with integer coordinates are supported in case of contour slice" );
943     area = icvContourSecArea( contour, slice );
944     return oriented ? area : fabs(area);
945 }
946 
947 
948 /* calculates length of a curve (e.g. contour perimeter) */
949 CV_IMPL  double
cvArcLength(const void * array,CvSlice slice,int is_closed)950 cvArcLength( const void *array, CvSlice slice, int is_closed )
951 {
952     double perimeter = 0;
953 
954     int i, j = 0, count;
955     const int N = 16;
956     float buf[N];
957     CvMat buffer = cvMat( 1, N, CV_32F, buf );
958     CvSeqReader reader;
959     CvContour contour_header;
960     CvSeq* contour = 0;
961     CvSeqBlock block;
962 
963     if( CV_IS_SEQ( array ))
964     {
965         contour = (CvSeq*)array;
966         if( !CV_IS_SEQ_POLYLINE( contour ))
967             CV_Error( CV_StsBadArg, "Unsupported sequence type" );
968         if( is_closed < 0 )
969             is_closed = CV_IS_SEQ_CLOSED( contour );
970     }
971     else
972     {
973         is_closed = is_closed > 0;
974         contour = cvPointSeqFromMat(
975                                     CV_SEQ_KIND_CURVE | (is_closed ? CV_SEQ_FLAG_CLOSED : 0),
976                                     array, &contour_header, &block );
977     }
978 
979     if( contour->total > 1 )
980     {
981         int is_float = CV_SEQ_ELTYPE( contour ) == CV_32FC2;
982 
983         cvStartReadSeq( contour, &reader, 0 );
984         cvSetSeqReaderPos( &reader, slice.start_index );
985         count = cvSliceLength( slice, contour );
986 
987         count -= !is_closed && count == contour->total;
988 
989         // scroll the reader by 1 point
990         reader.prev_elem = reader.ptr;
991         CV_NEXT_SEQ_ELEM( sizeof(CvPoint), reader );
992 
993         for( i = 0; i < count; i++ )
994         {
995             float dx, dy;
996 
997             if( !is_float )
998             {
999                 CvPoint* pt = (CvPoint*)reader.ptr;
1000                 CvPoint* prev_pt = (CvPoint*)reader.prev_elem;
1001 
1002                 dx = (float)pt->x - (float)prev_pt->x;
1003                 dy = (float)pt->y - (float)prev_pt->y;
1004             }
1005             else
1006             {
1007                 CvPoint2D32f* pt = (CvPoint2D32f*)reader.ptr;
1008                 CvPoint2D32f* prev_pt = (CvPoint2D32f*)reader.prev_elem;
1009 
1010                 dx = pt->x - prev_pt->x;
1011                 dy = pt->y - prev_pt->y;
1012             }
1013 
1014             reader.prev_elem = reader.ptr;
1015             CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
1016             // Bugfix by Axel at rubico.com 2010-03-22, affects closed slices only
1017             // wraparound not handled by CV_NEXT_SEQ_ELEM
1018             if( is_closed && i == count - 2 )
1019                 cvSetSeqReaderPos( &reader, slice.start_index );
1020 
1021             buffer.data.fl[j] = dx * dx + dy * dy;
1022             if( ++j == N || i == count - 1 )
1023             {
1024                 buffer.cols = j;
1025                 cvPow( &buffer, &buffer, 0.5 );
1026                 for( ; j > 0; j-- )
1027                     perimeter += buffer.data.fl[j-1];
1028             }
1029         }
1030     }
1031 
1032     return perimeter;
1033 }
1034 
1035 
1036 CV_IMPL CvBox2D
cvFitEllipse2(const CvArr * array)1037 cvFitEllipse2( const CvArr* array )
1038 {
1039     cv::AutoBuffer<double> abuf;
1040     cv::Mat points = cv::cvarrToMat(array, false, false, 0, &abuf);
1041     return cv::fitEllipse(points);
1042 }
1043 
1044 /* Calculates bounding rectagnle of a point set or retrieves already calculated */
1045 CV_IMPL  CvRect
cvBoundingRect(CvArr * array,int update)1046 cvBoundingRect( CvArr* array, int update )
1047 {
1048     CvRect  rect;
1049     CvContour contour_header;
1050     CvSeq* ptseq = 0;
1051     CvSeqBlock block;
1052 
1053     CvMat stub, *mat = 0;
1054     int calculate = update;
1055 
1056     if( CV_IS_SEQ( array ))
1057     {
1058         ptseq = (CvSeq*)array;
1059         if( !CV_IS_SEQ_POINT_SET( ptseq ))
1060             CV_Error( CV_StsBadArg, "Unsupported sequence type" );
1061 
1062         if( ptseq->header_size < (int)sizeof(CvContour))
1063         {
1064             update = 0;
1065             calculate = 1;
1066         }
1067     }
1068     else
1069     {
1070         mat = cvGetMat( array, &stub );
1071         if( CV_MAT_TYPE(mat->type) == CV_32SC2 ||
1072             CV_MAT_TYPE(mat->type) == CV_32FC2 )
1073         {
1074             ptseq = cvPointSeqFromMat(CV_SEQ_KIND_GENERIC, mat, &contour_header, &block);
1075             mat = 0;
1076         }
1077         else if( CV_MAT_TYPE(mat->type) != CV_8UC1 &&
1078                 CV_MAT_TYPE(mat->type) != CV_8SC1 )
1079             CV_Error( CV_StsUnsupportedFormat,
1080                 "The image/matrix format is not supported by the function" );
1081         update = 0;
1082         calculate = 1;
1083     }
1084 
1085     if( !calculate )
1086         return ((CvContour*)ptseq)->rect;
1087 
1088     if( mat )
1089     {
1090         rect = cv::maskBoundingRect(cv::cvarrToMat(mat));
1091     }
1092     else if( ptseq->total )
1093     {
1094         cv::AutoBuffer<double> abuf;
1095         rect = cv::pointSetBoundingRect(cv::cvarrToMat(ptseq, false, false, 0, &abuf));
1096     }
1097     if( update )
1098         ((CvContour*)ptseq)->rect = rect;
1099     return rect;
1100 }
1101 
1102 
1103 /* End of file. */
1104