From dc4d0398f3f98e8f0a2bd2ee9d059283cabd224a Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Tue, 22 Jan 2013 16:54:31 +0400 Subject: [PATCH] converted few more comp. geometry functions to C++ --- modules/imgproc/src/_geom.h | 10 - modules/imgproc/src/contours.cpp | 81 -- modules/imgproc/src/geometry.cpp | 142 +- modules/imgproc/src/matchcontours.cpp | 205 ++- modules/imgproc/src/rotcalipers.cpp | 720 +++++----- modules/imgproc/src/shapedescr.cpp | 1913 ++++++++++++------------- samples/cpp/minarea.cpp | 2 +- 7 files changed, 1381 insertions(+), 1692 deletions(-) diff --git a/modules/imgproc/src/_geom.h b/modules/imgproc/src/_geom.h index 25050390e2..bfde73d6d5 100644 --- a/modules/imgproc/src/_geom.h +++ b/modules/imgproc/src/_geom.h @@ -52,16 +52,6 @@ CV_INLINE float icvDistanceL2_32f( CvPoint2D32f pt1, CvPoint2D32f pt2 ) } -int icvIntersectLines( double x1, double dx1, double y1, double dy1, - double x2, double dx2, double y2, double dy2, - double* t2 ); - - -void icvIntersectLines3( double* a0, double* b0, double* c0, - double* a1, double* b1, double* c1, - CvPoint2D32f* point ); - - /* curvature: 0 - 1-curvature, 1 - k-cosine curvature. */ CvSeq* icvApproximateChainTC89( CvChain* chain, int header_size, CvMemStorage* storage, int method ); diff --git a/modules/imgproc/src/contours.cpp b/modules/imgproc/src/contours.cpp index 8c5dcb506d..75e18b2d84 100644 --- a/modules/imgproc/src/contours.cpp +++ b/modules/imgproc/src/contours.cpp @@ -1753,85 +1753,4 @@ void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours, findContours(_image, _contours, noArray(), mode, method, offset); } -double cv::arcLength( InputArray _curve, bool closed ) -{ - Mat curve = _curve.getMat(); - CV_Assert(curve.checkVector(2) >= 0 && (curve.depth() == CV_32F || curve.depth() == CV_32S)); - CvMat _ccurve = curve; - return cvArcLength(&_ccurve, CV_WHOLE_SEQ, closed); -} - - -cv::Rect cv::boundingRect( InputArray _points ) -{ - Mat points = _points.getMat(); - CV_Assert(points.checkVector(2) >= 0 && (points.depth() == CV_32F || points.depth() == CV_32S)); - CvMat _cpoints = points; - return cvBoundingRect(&_cpoints, 0); -} - - -double cv::contourArea( InputArray _contour, bool oriented ) -{ - Mat contour = _contour.getMat(); - CV_Assert(contour.checkVector(2) >= 0 && (contour.depth() == CV_32F || contour.depth() == CV_32S)); - CvMat _ccontour = contour; - return cvContourArea(&_ccontour, CV_WHOLE_SEQ, oriented); -} - - -cv::RotatedRect cv::minAreaRect( InputArray _points ) -{ - Mat points = _points.getMat(); - CV_Assert(points.checkVector(2) >= 0 && (points.depth() == CV_32F || points.depth() == CV_32S)); - CvMat _cpoints = points; - return cvMinAreaRect2(&_cpoints, 0); -} - - -void cv::minEnclosingCircle( InputArray _points, - Point2f& center, float& radius ) -{ - Mat points = _points.getMat(); - CV_Assert(points.checkVector(2) >= 0 && (points.depth() == CV_32F || points.depth() == CV_32S)); - CvMat _cpoints = points; - cvMinEnclosingCircle( &_cpoints, (CvPoint2D32f*)¢er, &radius ); -} - - -double cv::matchShapes( InputArray _contour1, - InputArray _contour2, - int method, double parameter ) -{ - Mat contour1 = _contour1.getMat(), contour2 = _contour2.getMat(); - CV_Assert(contour1.checkVector(2) >= 0 && contour2.checkVector(2) >= 0 && - (contour1.depth() == CV_32F || contour1.depth() == CV_32S) && - contour1.depth() == contour2.depth()); - - CvMat c1 = Mat(contour1), c2 = Mat(contour2); - return cvMatchShapes(&c1, &c2, method, parameter); -} - - - -cv::RotatedRect cv::fitEllipse( InputArray _points ) -{ - Mat points = _points.getMat(); - CV_Assert(points.checkVector(2) >= 0 && - (points.depth() == CV_32F || points.depth() == CV_32S)); - CvMat _cpoints = points; - return cvFitEllipse2(&_cpoints); -} - - -double cv::pointPolygonTest( InputArray _contour, - Point2f pt, bool measureDist ) -{ - Mat contour = _contour.getMat(); - CV_Assert(contour.checkVector(2) >= 0 && - (contour.depth() == CV_32F || contour.depth() == CV_32S)); - CvMat c = Mat(contour); - return cvPointPolygonTest( &c, pt, measureDist ); -} - /* End of file. */ diff --git a/modules/imgproc/src/geometry.cpp b/modules/imgproc/src/geometry.cpp index 337362f120..e0eb229714 100644 --- a/modules/imgproc/src/geometry.cpp +++ b/modules/imgproc/src/geometry.cpp @@ -92,97 +92,38 @@ cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] ) } -int -icvIntersectLines( double x1, double dx1, double y1, double dy1, - double x2, double dx2, double y2, double dy2, double *t2 ) -{ - double d = dx1 * dy2 - dx2 * dy1; - int result = -1; - - if( d != 0 ) - { - *t2 = ((x2 - x1) * dy1 - (y2 - y1) * dx1) / d; - result = 0; - } - return result; -} - - -void -icvIntersectLines3( double *a0, double *b0, double *c0, - double *a1, double *b1, double *c1, CvPoint2D32f * point ) -{ - double det = a0[0] * b1[0] - a1[0] * b0[0]; - - if( det != 0 ) - { - det = 1. / det; - point->x = (float) ((b0[0] * c1[0] - b1[0] * c0[0]) * det); - point->y = (float) ((a1[0] * c0[0] - a0[0] * c1[0]) * det); - } - else - { - point->x = point->y = FLT_MAX; - } -} - - -CV_IMPL double -cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist ) +double cv::pointPolygonTest( InputArray _contour, Point2f pt, bool measureDist ) { double result = 0; + Mat contour = _contour.getMat(); + int i, total = contour.checkVector(2), counter = 0; + int depth = contour.depth(); + CV_Assert( total >= 0 && (depth == CV_32S || depth == CV_32F)); - CvSeqBlock block; - CvContour header; - CvSeq* contour = (CvSeq*)_contour; - CvSeqReader reader; - int i, total, counter = 0; - int is_float; + bool is_float = depth == CV_32F; double min_dist_num = FLT_MAX, min_dist_denom = 1; - CvPoint ip = {0,0}; + Point ip(cvRound(pt.x), cvRound(pt.y)); - if( !CV_IS_SEQ(contour) ) - { - contour = cvPointSeqFromMat( CV_SEQ_KIND_CURVE + CV_SEQ_FLAG_CLOSED, - _contour, &header, &block ); - } - else if( CV_IS_SEQ_POINT_SET(contour) ) - { - if( contour->header_size == sizeof(CvContour) && !measure_dist ) - { - CvRect r = ((CvContour*)contour)->rect; - if( pt.x < r.x || pt.y < r.y || - pt.x >= r.x + r.width || pt.y >= r.y + r.height ) - return -1; - } - } - else if( CV_IS_SEQ_CHAIN(contour) ) - { - CV_Error( CV_StsBadArg, - "Chains are not supported. Convert them to polygonal representation using cvApproxChains()" ); - } - else - CV_Error( CV_StsBadArg, "Input contour is neither a valid sequence nor a matrix" ); + if( total == 0 ) + return measureDist ? -DBL_MAX : -1; - total = contour->total; - is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2; - cvStartReadSeq( contour, &reader, -1 ); + const Point* cnt = (const Point*)contour.data; + const Point2f* cntf = (const Point2f*)cnt; - if( !is_float && !measure_dist && (ip.x = cvRound(pt.x)) == pt.x && (ip.y = cvRound(pt.y)) == pt.y ) + if( !is_float && !measureDist && ip.x == pt.x && ip.y == pt.y ) { - // the fastest "pure integer" branch - CvPoint v0, v; - CV_READ_SEQ_ELEM( v, reader ); + // the fastest "purely integer" branch + Point v0, v = cnt[total-1]; for( i = 0; i < total; i++ ) { int dist; v0 = v; - CV_READ_SEQ_ELEM( v, reader ); + v = cnt[i]; if( (v0.y <= ip.y && v.y <= ip.y) || - (v0.y > ip.y && v.y > ip.y) || - (v0.x < ip.x && v.x < ip.x) ) + (v0.y > ip.y && v.y > ip.y) || + (v0.x < ip.x && v.x < ip.x) ) { if( ip.y == v.y && (ip.x == v.x || (ip.y == v0.y && ((v0.x <= ip.x && ip.x <= v.x) || (v.x <= ip.x && ip.x <= v0.x)))) ) @@ -202,38 +143,32 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist ) } else { - CvPoint2D32f v0, v; - CvPoint iv; + Point2f v0, v; + Point iv; if( is_float ) { - CV_READ_SEQ_ELEM( v, reader ); + v = cntf[total-1]; } else { - CV_READ_SEQ_ELEM( iv, reader ); - v = cvPointTo32f( iv ); + v = cnt[total-1]; } - if( !measure_dist ) + if( !measureDist ) { for( i = 0; i < total; i++ ) { double dist; v0 = v; if( is_float ) - { - CV_READ_SEQ_ELEM( v, reader ); - } + v = cntf[i]; else - { - CV_READ_SEQ_ELEM( iv, reader ); - v = cvPointTo32f( iv ); - } + v = cnt[i]; if( (v0.y <= pt.y && v.y <= pt.y) || - (v0.y > pt.y && v.y > pt.y) || - (v0.x < pt.x && v.x < pt.x) ) + (v0.y > pt.y && v.y > pt.y) || + (v0.x < pt.x && v.x < pt.x) ) { if( pt.y == v.y && (pt.x == v.x || (pt.y == v0.y && ((v0.x <= pt.x && pt.x <= v.x) || (v.x <= pt.x && pt.x <= v0.x)))) ) @@ -259,14 +194,9 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist ) v0 = v; if( is_float ) - { - CV_READ_SEQ_ELEM( v, reader ); - } + v = cntf[i]; else - { - CV_READ_SEQ_ELEM( iv, reader ); - v = cvPointTo32f( iv ); - } + v = cnt[i]; dx = v.x - v0.x; dy = v.y - v0.y; dx1 = pt.x - v0.x; dy1 = pt.y - v0.y; @@ -292,8 +222,8 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist ) } if( (v0.y <= pt.y && v.y <= pt.y) || - (v0.y > pt.y && v.y > pt.y) || - (v0.x < pt.x && v.x < pt.x) ) + (v0.y > pt.y && v.y > pt.y) || + (v0.x < pt.x && v.x < pt.x) ) continue; dist_num = dy1*dx - dx1*dy; @@ -301,17 +231,25 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist ) dist_num = -dist_num; counter += dist_num > 0; } - + result = sqrt(min_dist_num/min_dist_denom); if( counter % 2 == 0 ) result = -result; } } - + return result; } +CV_IMPL double +cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist ) +{ + cv::AutoBuffer abuf; + cv::Mat contour = cv::cvarrToMat(_contour, false, false, 0, &abuf); + return cv::pointPolygonTest(contour, pt, measure_dist != 0); +} + /* This code is described in "Computational Geometry in C" (Second Edition), Chapter 7. It is not written to be comprehensible without the diff --git a/modules/imgproc/src/matchcontours.cpp b/modules/imgproc/src/matchcontours.cpp index 44c01e02d2..eca3859001 100644 --- a/modules/imgproc/src/matchcontours.cpp +++ b/modules/imgproc/src/matchcontours.cpp @@ -40,159 +40,122 @@ //M*/ #include "precomp.hpp" -/*F/////////////////////////////////////////////////////////////////////////////////////// -// Name: cvMatchContours -// Purpose: -// Calculates matching of the two contours -// Context: -// Parameters: -// contour_1 - pointer to the first input contour object. -// contour_2 - pointer to the second input contour object. -// method - method for the matching calculation -// (now CV_IPPI_CONTOURS_MATCH_I1, CV_CONTOURS_MATCH_I2 or -// CV_CONTOURS_MATCH_I3 only ) -// rezult - output calculated measure -// -//F*/ -CV_IMPL double -cvMatchShapes( const void* contour1, const void* contour2, - int method, double /*parameter*/ ) + +double cv::matchShapes(InputArray contour1, InputArray contour2, int method, double) { - CvMoments moments; - CvHuMoments huMoments; double ma[7], mb[7]; int i, sma, smb; double eps = 1.e-5; double mmm; double result = 0; - if( !contour1 || !contour2 ) - CV_Error( CV_StsNullPtr, "" ); - - // calculate moments of the first shape - cvMoments( contour1, &moments ); - cvGetHuMoments( &moments, &huMoments ); - - ma[0] = huMoments.hu1; - ma[1] = huMoments.hu2; - ma[2] = huMoments.hu3; - ma[3] = huMoments.hu4; - ma[4] = huMoments.hu5; - ma[5] = huMoments.hu6; - ma[6] = huMoments.hu7; - - - // calculate moments of the second shape - cvMoments( contour2, &moments ); - cvGetHuMoments( &moments, &huMoments ); - - mb[0] = huMoments.hu1; - mb[1] = huMoments.hu2; - mb[2] = huMoments.hu3; - mb[3] = huMoments.hu4; - mb[4] = huMoments.hu5; - mb[5] = huMoments.hu6; - mb[6] = huMoments.hu7; + HuMoments( moments(contour1), ma ); + HuMoments( moments(contour2), mb ); switch (method) { case 1: + for( i = 0; i < 7; i++ ) { - for( i = 0; i < 7; i++ ) + double ama = fabs( ma[i] ); + double amb = fabs( mb[i] ); + + if( ma[i] > 0 ) + sma = 1; + else if( ma[i] < 0 ) + sma = -1; + else + sma = 0; + if( mb[i] > 0 ) + smb = 1; + else if( mb[i] < 0 ) + smb = -1; + else + smb = 0; + + if( ama > eps && amb > eps ) { - double ama = fabs( ma[i] ); - double amb = fabs( mb[i] ); - - if( ma[i] > 0 ) - sma = 1; - else if( ma[i] < 0 ) - sma = -1; - else - sma = 0; - if( mb[i] > 0 ) - smb = 1; - else if( mb[i] < 0 ) - smb = -1; - else - smb = 0; - - if( ama > eps && amb > eps ) - { - ama = 1. / (sma * log10( ama )); - amb = 1. / (smb * log10( amb )); - result += fabs( -ama + amb ); - } + ama = 1. / (sma * log10( ama )); + amb = 1. / (smb * log10( amb )); + result += fabs( -ama + amb ); } - break; } + break; case 2: + for( i = 0; i < 7; i++ ) { - for( i = 0; i < 7; i++ ) + double ama = fabs( ma[i] ); + double amb = fabs( mb[i] ); + + if( ma[i] > 0 ) + sma = 1; + else if( ma[i] < 0 ) + sma = -1; + else + sma = 0; + if( mb[i] > 0 ) + smb = 1; + else if( mb[i] < 0 ) + smb = -1; + else + smb = 0; + + if( ama > eps && amb > eps ) { - double ama = fabs( ma[i] ); - double amb = fabs( mb[i] ); - - if( ma[i] > 0 ) - sma = 1; - else if( ma[i] < 0 ) - sma = -1; - else - sma = 0; - if( mb[i] > 0 ) - smb = 1; - else if( mb[i] < 0 ) - smb = -1; - else - smb = 0; - - if( ama > eps && amb > eps ) - { - ama = sma * log10( ama ); - amb = smb * log10( amb ); - result += fabs( -ama + amb ); - } + ama = sma * log10( ama ); + amb = smb * log10( amb ); + result += fabs( -ama + amb ); } - break; } + break; case 3: + for( i = 0; i < 7; i++ ) { - for( i = 0; i < 7; i++ ) + double ama = fabs( ma[i] ); + double amb = fabs( mb[i] ); + + if( ma[i] > 0 ) + sma = 1; + else if( ma[i] < 0 ) + sma = -1; + else + sma = 0; + if( mb[i] > 0 ) + smb = 1; + else if( mb[i] < 0 ) + smb = -1; + else + smb = 0; + + if( ama > eps && amb > eps ) { - double ama = fabs( ma[i] ); - double amb = fabs( mb[i] ); - - if( ma[i] > 0 ) - sma = 1; - else if( ma[i] < 0 ) - sma = -1; - else - sma = 0; - if( mb[i] > 0 ) - smb = 1; - else if( mb[i] < 0 ) - smb = -1; - else - smb = 0; - - if( ama > eps && amb > eps ) - { - ama = sma * log10( ama ); - amb = smb * log10( amb ); - mmm = fabs( (ama - amb) / ama ); - if( result < mmm ) - result = mmm; - } + ama = sma * log10( ama ); + amb = smb * log10( amb ); + mmm = fabs( (ama - amb) / ama ); + if( result < mmm ) + result = mmm; } - break; } + break; default: CV_Error( CV_StsBadArg, "Unknown comparison method" ); } - + return result; } +CV_IMPL double +cvMatchShapes( const void* _contour1, const void* _contour2, + int method, double parameter ) +{ + cv::AutoBuffer abuf1, abuf2; + cv::Mat contour1 = cv::cvarrToMat(_contour1, false, false, 0, &abuf1); + cv::Mat contour2 = cv::cvarrToMat(_contour2, false, false, 0, &abuf2); + + return cv::matchShapes(contour1, contour2, method, parameter); +} + /* End of file. */ diff --git a/modules/imgproc/src/rotcalipers.cpp b/modules/imgproc/src/rotcalipers.cpp index 2171ec13e2..adb7405ded 100644 --- a/modules/imgproc/src/rotcalipers.cpp +++ b/modules/imgproc/src/rotcalipers.cpp @@ -1,418 +1,367 @@ /*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ + // + // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + // + // By downloading, copying, installing or using the software you agree to this license. + // If you do not agree to this license, do not download, install, + // copy or use the software. + // + // + // License Agreement + // For Open Source Computer Vision Library + // + // Copyright (C) 2000, Intel Corporation, all rights reserved. + // Third party copyrights are property of their respective owners. + // + // Redistribution and use in source and binary forms, with or without modification, + // are permitted provided that the following conditions are met: + // + // * Redistribution's of source code must retain the above copyright notice, + // this list of conditions and the following disclaimer. + // + // * Redistribution's in binary form must reproduce the above copyright notice, + // this list of conditions and the following disclaimer in the documentation + // and/or other materials provided with the distribution. + // + // * The name of OpenCV Foundation may not be used to endorse or promote products + // derived from this software without specific prior written permission. + // + // This software is provided by the copyright holders and contributors "as is" and + // any express or implied warranties, including, but not limited to, the implied + // warranties of merchantability and fitness for a particular purpose are disclaimed. + // In no event shall the OpenCV Foundation or contributors be liable for any direct, + // indirect, incidental, special, exemplary, or consequential damages + // (including, but not limited to, procurement of substitute goods or services; + // loss of use, data, or profits; or business interruption) however caused + // and on any theory of liability, whether in contract, strict liability, + // or tort (including negligence or otherwise) arising in any way out of + // the use of this software, even if advised of the possibility of such damage. + // + //M*/ #include "precomp.hpp" -typedef struct +namespace cv { - int bottom; - int left; - float height; - float width; - float base_a; - float base_b; -} -icvMinAreaState; -#define CV_CALIPERS_MAXHEIGHT 0 -#define CV_CALIPERS_MINAREARECT 1 -#define CV_CALIPERS_MAXDIST 2 - -/*F/////////////////////////////////////////////////////////////////////////////////////// -// Name: icvRotatingCalipers -// Purpose: -// Rotating calipers algorithm with some applications -// -// Context: -// Parameters: -// points - convex hull vertices ( any orientation ) -// n - number of vertices -// mode - concrete application of algorithm -// can be CV_CALIPERS_MAXDIST or -// CV_CALIPERS_MINAREARECT -// left, bottom, right, top - indexes of extremal points -// out - output info. -// In case CV_CALIPERS_MAXDIST it points to float value - -// maximal height of polygon. -// In case CV_CALIPERS_MINAREARECT -// ((CvPoint2D32f*)out)[0] - corner -// ((CvPoint2D32f*)out)[1] - vector1 -// ((CvPoint2D32f*)out)[0] - corner2 -// -// ^ -// | -// vector2 | -// | -// |____________\ -// corner / -// vector1 -// -// Returns: -// Notes: -//F*/ - -/* we will use usual cartesian coordinates */ -static void -icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out ) -{ - float minarea = FLT_MAX; - float max_dist = 0; - char buffer[32] = {}; - int i, k; - CvPoint2D32f* vect = (CvPoint2D32f*)cvAlloc( n * sizeof(vect[0]) ); - float* inv_vect_length = (float*)cvAlloc( n * sizeof(inv_vect_length[0]) ); - int left = 0, bottom = 0, right = 0, top = 0; - int seq[4] = { -1, -1, -1, -1 }; - - /* rotating calipers sides will always have coordinates - (a,b) (-b,a) (-a,-b) (b, -a) - */ - /* this is a first base bector (a,b) initialized by (1,0) */ - float orientation = 0; - float base_a; - float base_b = 0; - - float left_x, right_x, top_y, bottom_y; - CvPoint2D32f pt0 = points[0]; - - left_x = right_x = pt0.x; - top_y = bottom_y = pt0.y; - - for( i = 0; i < n; i++ ) + struct MinAreaState { - double dx, dy; + int bottom; + int left; + float height; + float width; + float base_a; + float base_b; + }; - if( pt0.x < left_x ) - left_x = pt0.x, left = i; + enum { CALIPERS_MAXHEIGHT=0, CALIPERS_MINAREARECT=1, CALIPERS_MAXDIST=2 }; - if( pt0.x > right_x ) - right_x = pt0.x, right = i; + /*F/////////////////////////////////////////////////////////////////////////////////////// + // Name: rotatingCalipers + // Purpose: + // Rotating calipers algorithm with some applications + // + // Context: + // Parameters: + // points - convex hull vertices ( any orientation ) + // n - number of vertices + // mode - concrete application of algorithm + // can be CV_CALIPERS_MAXDIST or + // CV_CALIPERS_MINAREARECT + // left, bottom, right, top - indexes of extremal points + // out - output info. + // In case CV_CALIPERS_MAXDIST it points to float value - + // maximal height of polygon. + // In case CV_CALIPERS_MINAREARECT + // ((CvPoint2D32f*)out)[0] - corner + // ((CvPoint2D32f*)out)[1] - vector1 + // ((CvPoint2D32f*)out)[0] - corner2 + // + // ^ + // | + // vector2 | + // | + // |____________\ + // corner / + // vector1 + // + // Returns: + // Notes: + //F*/ - if( pt0.y > top_y ) - top_y = pt0.y, top = i; - - if( pt0.y < bottom_y ) - bottom_y = pt0.y, bottom = i; - - CvPoint2D32f pt = points[(i+1) & (i+1 < n ? -1 : 0)]; - - dx = pt.x - pt0.x; - dy = pt.y - pt0.y; - - vect[i].x = (float)dx; - vect[i].y = (float)dy; - inv_vect_length[i] = (float)(1./sqrt(dx*dx + dy*dy)); - - pt0 = pt; - } - - //cvbInvSqrt( inv_vect_length, inv_vect_length, n ); - - /* find convex hull orientation */ + /* we will use usual cartesian coordinates */ + static void rotatingCalipers( const Point2f* points, int n, int mode, float* out ) { - double ax = vect[n-1].x; - double ay = vect[n-1].y; + float minarea = FLT_MAX; + float max_dist = 0; + char buffer[32] = {}; + int i, k; + AutoBuffer buf(n*3); + float* inv_vect_length = buf; + Point2f* vect = (Point2f*)(inv_vect_length + n); + int left = 0, bottom = 0, right = 0, top = 0; + int seq[4] = { -1, -1, -1, -1 }; + + /* rotating calipers sides will always have coordinates + (a,b) (-b,a) (-a,-b) (b, -a) + */ + /* this is a first base bector (a,b) initialized by (1,0) */ + float orientation = 0; + float base_a; + float base_b = 0; + + float left_x, right_x, top_y, bottom_y; + Point2f pt0 = points[0]; + + left_x = right_x = pt0.x; + top_y = bottom_y = pt0.y; for( i = 0; i < n; i++ ) { - double bx = vect[i].x; - double by = vect[i].y; + double dx, dy; - double convexity = ax * by - ay * bx; + if( pt0.x < left_x ) + left_x = pt0.x, left = i; - if( convexity != 0 ) - { - orientation = (convexity > 0) ? 1.f : (-1.f); - break; - } - ax = bx; - ay = by; + if( pt0.x > right_x ) + right_x = pt0.x, right = i; + + if( pt0.y > top_y ) + top_y = pt0.y, top = i; + + if( pt0.y < bottom_y ) + bottom_y = pt0.y, bottom = i; + + Point2f pt = points[(i+1) & (i+1 < n ? -1 : 0)]; + + dx = pt.x - pt0.x; + dy = pt.y - pt0.y; + + vect[i].x = (float)dx; + vect[i].y = (float)dy; + inv_vect_length[i] = (float)(1./sqrt(dx*dx + dy*dy)); + + pt0 = pt; } - assert( orientation != 0 ); - } - base_a = orientation; -/*****************************************************************************************/ -/* init calipers position */ - seq[0] = bottom; - seq[1] = right; - seq[2] = top; - seq[3] = left; -/*****************************************************************************************/ -/* Main loop - evaluate angles and rotate calipers */ - - /* all of edges will be checked while rotating calipers by 90 degrees */ - for( k = 0; k < n; k++ ) - { - /* sinus of minimal angle */ - /*float sinus;*/ - - /* compute cosine of angle between calipers side and polygon edge */ - /* dp - dot product */ - float dp0 = base_a * vect[seq[0]].x + base_b * vect[seq[0]].y; - float dp1 = -base_b * vect[seq[1]].x + base_a * vect[seq[1]].y; - float dp2 = -base_a * vect[seq[2]].x - base_b * vect[seq[2]].y; - float dp3 = base_b * vect[seq[3]].x - base_a * vect[seq[3]].y; - - float cosalpha = dp0 * inv_vect_length[seq[0]]; - float maxcos = cosalpha; - - /* number of calipers edges, that has minimal angle with edge */ - int main_element = 0; - - /* choose minimal angle */ - cosalpha = dp1 * inv_vect_length[seq[1]]; - maxcos = (cosalpha > maxcos) ? (main_element = 1, cosalpha) : maxcos; - cosalpha = dp2 * inv_vect_length[seq[2]]; - maxcos = (cosalpha > maxcos) ? (main_element = 2, cosalpha) : maxcos; - cosalpha = dp3 * inv_vect_length[seq[3]]; - maxcos = (cosalpha > maxcos) ? (main_element = 3, cosalpha) : maxcos; - - /*rotate calipers*/ + // find convex hull orientation { - //get next base - int pindex = seq[main_element]; - float lead_x = vect[pindex].x*inv_vect_length[pindex]; - float lead_y = vect[pindex].y*inv_vect_length[pindex]; - switch( main_element ) - { - case 0: - base_a = lead_x; - base_b = lead_y; - break; - case 1: - base_a = lead_y; - base_b = -lead_x; - break; - case 2: - base_a = -lead_x; - base_b = -lead_y; - break; - case 3: - base_a = -lead_y; - base_b = lead_x; - break; - default: assert(0); - } - } - /* change base point of main edge */ - seq[main_element] += 1; - seq[main_element] = (seq[main_element] == n) ? 0 : seq[main_element]; + double ax = vect[n-1].x; + double ay = vect[n-1].y; + for( i = 0; i < n; i++ ) + { + double bx = vect[i].x; + double by = vect[i].y; + + double convexity = ax * by - ay * bx; + + if( convexity != 0 ) + { + orientation = (convexity > 0) ? 1.f : (-1.f); + break; + } + ax = bx; + ay = by; + } + CV_Assert( orientation != 0 ); + } + base_a = orientation; + + /*****************************************************************************************/ + /* init calipers position */ + seq[0] = bottom; + seq[1] = right; + seq[2] = top; + seq[3] = left; + /*****************************************************************************************/ + /* Main loop - evaluate angles and rotate calipers */ + + /* all of edges will be checked while rotating calipers by 90 degrees */ + for( k = 0; k < n; k++ ) + { + /* sinus of minimal angle */ + /*float sinus;*/ + + /* compute cosine of angle between calipers side and polygon edge */ + /* dp - dot product */ + float dp0 = base_a * vect[seq[0]].x + base_b * vect[seq[0]].y; + float dp1 = -base_b * vect[seq[1]].x + base_a * vect[seq[1]].y; + float dp2 = -base_a * vect[seq[2]].x - base_b * vect[seq[2]].y; + float dp3 = base_b * vect[seq[3]].x - base_a * vect[seq[3]].y; + + float cosalpha = dp0 * inv_vect_length[seq[0]]; + float maxcos = cosalpha; + + /* number of calipers edges, that has minimal angle with edge */ + int main_element = 0; + + /* choose minimal angle */ + cosalpha = dp1 * inv_vect_length[seq[1]]; + maxcos = (cosalpha > maxcos) ? (main_element = 1, cosalpha) : maxcos; + cosalpha = dp2 * inv_vect_length[seq[2]]; + maxcos = (cosalpha > maxcos) ? (main_element = 2, cosalpha) : maxcos; + cosalpha = dp3 * inv_vect_length[seq[3]]; + maxcos = (cosalpha > maxcos) ? (main_element = 3, cosalpha) : maxcos; + + /*rotate calipers*/ + { + //get next base + int pindex = seq[main_element]; + float lead_x = vect[pindex].x*inv_vect_length[pindex]; + float lead_y = vect[pindex].y*inv_vect_length[pindex]; + switch( main_element ) + { + case 0: + base_a = lead_x; + base_b = lead_y; + break; + case 1: + base_a = lead_y; + base_b = -lead_x; + break; + case 2: + base_a = -lead_x; + base_b = -lead_y; + break; + case 3: + base_a = -lead_y; + base_b = lead_x; + break; + default: + CV_Error(CV_StsError, "main_element should be 0, 1, 2 or 3"); + } + } + /* change base point of main edge */ + seq[main_element] += 1; + seq[main_element] = (seq[main_element] == n) ? 0 : seq[main_element]; + + switch (mode) + { + case CALIPERS_MAXHEIGHT: + { + /* now main element lies on edge alligned to calipers side */ + + /* find opposite element i.e. transform */ + /* 0->2, 1->3, 2->0, 3->1 */ + int opposite_el = main_element ^ 2; + + float dx = points[seq[opposite_el]].x - points[seq[main_element]].x; + float dy = points[seq[opposite_el]].y - points[seq[main_element]].y; + float dist; + + if( main_element & 1 ) + dist = (float)fabs(dx * base_a + dy * base_b); + else + dist = (float)fabs(dx * (-base_b) + dy * base_a); + + if( dist > max_dist ) + max_dist = dist; + + break; + } + case CALIPERS_MINAREARECT: + /* find area of rectangle */ + { + float height; + float area; + + /* find vector left-right */ + float dx = points[seq[1]].x - points[seq[3]].x; + float dy = points[seq[1]].y - points[seq[3]].y; + + /* dotproduct */ + float width = dx * base_a + dy * base_b; + + /* find vector left-right */ + dx = points[seq[2]].x - points[seq[0]].x; + dy = points[seq[2]].y - points[seq[0]].y; + + /* dotproduct */ + height = -dx * base_b + dy * base_a; + + area = width * height; + if( area <= minarea ) + { + float *buf = (float *) buffer; + + minarea = area; + /* leftist point */ + ((int *) buf)[0] = seq[3]; + buf[1] = base_a; + buf[2] = width; + buf[3] = base_b; + buf[4] = height; + /* bottom point */ + ((int *) buf)[5] = seq[0]; + buf[6] = area; + } + break; + } + } /*switch */ + } /* for */ switch (mode) { - case CV_CALIPERS_MAXHEIGHT: + case CALIPERS_MINAREARECT: { - /* now main element lies on edge alligned to calipers side */ + float *buf = (float *) buffer; - /* find opposite element i.e. transform */ - /* 0->2, 1->3, 2->0, 3->1 */ - int opposite_el = main_element ^ 2; + float A1 = buf[1]; + float B1 = buf[3]; - float dx = points[seq[opposite_el]].x - points[seq[main_element]].x; - float dy = points[seq[opposite_el]].y - points[seq[main_element]].y; - float dist; + float A2 = -buf[3]; + float B2 = buf[1]; - if( main_element & 1 ) - dist = (float)fabs(dx * base_a + dy * base_b); - else - dist = (float)fabs(dx * (-base_b) + dy * base_a); + float C1 = A1 * points[((int *) buf)[0]].x + points[((int *) buf)[0]].y * B1; + float C2 = A2 * points[((int *) buf)[5]].x + points[((int *) buf)[5]].y * B2; - if( dist > max_dist ) - max_dist = dist; + float idet = 1.f / (A1 * B2 - A2 * B1); - break; + float px = (C1 * B2 - C2 * B1) * idet; + float py = (A1 * C2 - A2 * C1) * idet; + + out[0] = px; + out[1] = py; + + out[2] = A1 * buf[2]; + out[3] = B1 * buf[2]; + + out[4] = A2 * buf[4]; + out[5] = B2 * buf[4]; } - case CV_CALIPERS_MINAREARECT: - /* find area of rectangle */ + break; + case CALIPERS_MAXHEIGHT: { - float height; - float area; - - /* find vector left-right */ - float dx = points[seq[1]].x - points[seq[3]].x; - float dy = points[seq[1]].y - points[seq[3]].y; - - /* dotproduct */ - float width = dx * base_a + dy * base_b; - - /* find vector left-right */ - dx = points[seq[2]].x - points[seq[0]].x; - dy = points[seq[2]].y - points[seq[0]].y; - - /* dotproduct */ - height = -dx * base_b + dy * base_a; - - area = width * height; - if( area <= minarea ) - { - float *buf = (float *) buffer; - - minarea = area; - /* leftist point */ - ((int *) buf)[0] = seq[3]; - buf[1] = base_a; - buf[2] = width; - buf[3] = base_b; - buf[4] = height; - /* bottom point */ - ((int *) buf)[5] = seq[0]; - buf[6] = area; - } - break; + out[0] = max_dist; } - } /*switch */ - } /* for */ - - switch (mode) - { - case CV_CALIPERS_MINAREARECT: - { - float *buf = (float *) buffer; - - float A1 = buf[1]; - float B1 = buf[3]; - - float A2 = -buf[3]; - float B2 = buf[1]; - - float C1 = A1 * points[((int *) buf)[0]].x + points[((int *) buf)[0]].y * B1; - float C2 = A2 * points[((int *) buf)[5]].x + points[((int *) buf)[5]].y * B2; - - float idet = 1.f / (A1 * B2 - A2 * B1); - - float px = (C1 * B2 - C2 * B1) * idet; - float py = (A1 * C2 - A2 * C1) * idet; - - out[0] = px; - out[1] = py; - - out[2] = A1 * buf[2]; - out[3] = B1 * buf[2]; - - out[4] = A2 * buf[4]; - out[5] = B2 * buf[4]; + break; } - break; - case CV_CALIPERS_MAXHEIGHT: - { - out[0] = max_dist; - } - break; } - - cvFree( &vect ); - cvFree( &inv_vect_length ); + } -CV_IMPL CvBox2D -cvMinAreaRect2( const CvArr* array, CvMemStorage* storage ) +cv::RotatedRect cv::minAreaRect( InputArray _points ) { - cv::Ptr temp_storage; - CvBox2D box; - cv::AutoBuffer _points; - CvPoint2D32f* points; - - memset(&box, 0, sizeof(box)); - - int i, n; - CvSeqReader reader; - CvContour contour_header; - CvSeqBlock block; - CvSeq* ptseq = (CvSeq*)array; - CvPoint2D32f out[3]; - - if( CV_IS_SEQ(ptseq) ) + Mat hull; + Point2f out[3]; + RotatedRect box; + + convexHull(_points, hull, true, true); + + if( hull.depth() != CV_32F ) { - if( !CV_IS_SEQ_POINT_SET(ptseq) && - (CV_SEQ_KIND(ptseq) != CV_SEQ_KIND_CURVE || - CV_SEQ_ELTYPE(ptseq) != CV_SEQ_ELTYPE_PPOINT )) - CV_Error( CV_StsUnsupportedFormat, - "Input sequence must consist of 2d points or pointers to 2d points" ); - if( !storage ) - storage = ptseq->storage; + Mat temp; + hull.convertTo(temp, CV_32F); + hull = temp; } - else - { - ptseq = cvPointSeqFromMat( CV_SEQ_KIND_GENERIC, array, &contour_header, &block ); - } - - if( storage ) - { - temp_storage = cvCreateChildMemStorage( storage ); - } - else - { - temp_storage = cvCreateMemStorage(1 << 10); - } - - ptseq = cvConvexHull2( ptseq, temp_storage, CV_CLOCKWISE, 1 ); - n = ptseq->total; - - _points.allocate(n); - points = _points; - cvStartReadSeq( ptseq, &reader ); - - if( CV_SEQ_ELTYPE( ptseq ) == CV_32SC2 ) - { - for( i = 0; i < n; i++ ) - { - CvPoint pt; - CV_READ_SEQ_ELEM( pt, reader ); - points[i].x = (float)pt.x; - points[i].y = (float)pt.y; - } - } - else - { - for( i = 0; i < n; i++ ) - { - CV_READ_SEQ_ELEM( points[i], reader ); - } - } - + + int n = hull.checkVector(2); + const Point2f* hpoints = (const Point2f*)hull.data; + if( n > 2 ) { - icvRotatingCalipers( points, n, CV_CALIPERS_MINAREARECT, (float*)out ); + rotatingCalipers( hpoints, n, CALIPERS_MINAREARECT, (float*)out ); box.center.x = out[0].x + (out[1].x + out[2].x)*0.5f; box.center.y = out[0].y + (out[1].y + out[2].y)*0.5f; box.size.width = (float)sqrt((double)out[1].x*out[1].x + (double)out[1].y*out[1].y); @@ -421,10 +370,10 @@ cvMinAreaRect2( const CvArr* array, CvMemStorage* storage ) } else if( n == 2 ) { - box.center.x = (points[0].x + points[1].x)*0.5f; - box.center.y = (points[0].y + points[1].y)*0.5f; - double dx = points[1].x - points[0].x; - double dy = points[1].y - points[0].y; + box.center.x = (hpoints[0].x + hpoints[1].x)*0.5f; + box.center.y = (hpoints[0].y + hpoints[1].y)*0.5f; + double dx = hpoints[1].x - hpoints[0].x; + double dy = hpoints[1].y - hpoints[0].y; box.size.width = (float)sqrt(dx*dx + dy*dy); box.size.height = 0; box.angle = (float)atan2( dy, dx ); @@ -432,10 +381,21 @@ cvMinAreaRect2( const CvArr* array, CvMemStorage* storage ) else { if( n == 1 ) - box.center = points[0]; + box.center = hpoints[0]; } - + box.angle = (float)(box.angle*180/CV_PI); return box; } + +CV_IMPL CvBox2D +cvMinAreaRect2( const CvArr* array, CvMemStorage* storage ) +{ + cv::AutoBuffer abuf; + cv::Mat points = cv::cvarrToMat(array, false, false, 0, &abuf); + + cv::RotatedRect rr = cv::minAreaRect(points); + return (CvBox2D)rr; +} + diff --git a/modules/imgproc/src/shapedescr.cpp b/modules/imgproc/src/shapedescr.cpp index b1bc1babe2..7c2d1ee259 100644 --- a/modules/imgproc/src/shapedescr.cpp +++ b/modules/imgproc/src/shapedescr.cpp @@ -40,6 +40,911 @@ //M*/ #include "precomp.hpp" +namespace cv +{ + +static int intersectLines( double x1, double dx1, double y1, double dy1, + double x2, double dx2, double y2, double dy2, double *t2 ) +{ + double d = dx1 * dy2 - dx2 * dy1; + int result = -1; + + if( d != 0 ) + { + *t2 = ((x2 - x1) * dy1 - (y2 - y1) * dx1) / d; + result = 0; + } + return result; +} + +static bool findCircle( Point2f pt0, Point2f pt1, Point2f pt2, + Point2f* center, float* radius ) +{ + double x1 = (pt0.x + pt1.x) * 0.5; + double dy1 = pt0.x - pt1.x; + double x2 = (pt1.x + pt2.x) * 0.5; + double dy2 = pt1.x - pt2.x; + double y1 = (pt0.y + pt1.y) * 0.5; + double dx1 = pt1.y - pt0.y; + double y2 = (pt1.y + pt2.y) * 0.5; + double dx2 = pt2.y - pt1.y; + double t = 0; + + if( intersectLines( x1, dx1, y1, dy1, x2, dx2, y2, dy2, &t ) >= 0 ) + { + center->x = (float) (x2 + dx2 * t); + center->y = (float) (y2 + dy2 * t); + *radius = (float)norm(*center - pt0); + return true; + } + + center->x = center->y = 0.f; + radius = 0; + return false; +} + + +static double pointInCircle( Point2f pt, Point2f center, float radius ) +{ + double dx = pt.x - center.x; + double dy = pt.y - center.y; + return (double)radius*radius - dx*dx - dy*dy; +} + + +static int findEnslosingCicle4pts_32f( Point2f* pts, Point2f& _center, float& _radius ) +{ + int shuffles[4][4] = { {0, 1, 2, 3}, {0, 1, 3, 2}, {2, 3, 0, 1}, {2, 3, 1, 0} }; + + int idxs[4] = { 0, 1, 2, 3 }; + int i, j, k = 1, mi = 0; + float max_dist = 0; + Point2f center; + Point2f min_center; + float radius, min_radius = FLT_MAX; + Point2f res_pts[4]; + + center = min_center = pts[0]; + radius = 1.f; + + for( i = 0; i < 4; i++ ) + for( j = i + 1; j < 4; j++ ) + { + float dist = norm(pts[i] - pts[j]); + + if( max_dist < dist ) + { + max_dist = dist; + idxs[0] = i; + idxs[1] = j; + } + } + + if( max_dist > 0 ) + { + k = 2; + for( i = 0; i < 4; i++ ) + { + for( j = 0; j < k; j++ ) + if( i == idxs[j] ) + break; + if( j == k ) + idxs[k++] = i; + } + + center = Point2f( (pts[idxs[0]].x + pts[idxs[1]].x)*0.5f, (pts[idxs[0]].y + pts[idxs[1]].y)*0.5f ); + radius = (float)(norm(pts[idxs[0]] - center)*1.03); + if( radius < 1.f ) + radius = 1.f; + + if( pointInCircle( pts[idxs[2]], center, radius ) >= 0 && + pointInCircle( pts[idxs[3]], center, radius ) >= 0 ) + { + k = 2; //rand()%2+2; + } + else + { + mi = -1; + for( i = 0; i < 4; i++ ) + { + if( findCircle( pts[shuffles[i][0]], pts[shuffles[i][1]], + pts[shuffles[i][2]], ¢er, &radius ) >= 0 ) + { + radius *= 1.03f; + if( radius < 2.f ) + radius = 2.f; + + if( pointInCircle( pts[shuffles[i][3]], center, radius ) >= 0 && + min_radius > radius ) + { + min_radius = radius; + min_center = center; + mi = i; + } + } + } + CV_Assert( mi >= 0 ); + if( mi < 0 ) + mi = 0; + k = 3; + center = min_center; + radius = min_radius; + for( i = 0; i < 4; i++ ) + idxs[i] = shuffles[mi][i]; + } + } + + _center = center; + _radius = radius; + + /* reorder output points */ + for( i = 0; i < 4; i++ ) + res_pts[i] = pts[idxs[i]]; + + for( i = 0; i < 4; i++ ) + { + pts[i] = res_pts[i]; + CV_Assert( pointInCircle( pts[i], center, radius ) >= 0 ); + } + + return k; +} + +} + +void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radius ) +{ + int max_iters = 100; + const float eps = FLT_EPSILON*2; + bool result = false; + Mat points = _points.getMat(); + int i, j, k, count = points.checkVector(2); + int depth = points.depth(); + Point2f center; + float radius = 0.f; + CV_Assert(count >= 0 && (depth == CV_32F || depth == CV_32S)); + + _center.x = _center.y = 0.f; + _radius = 0.f; + + if( count == 0 ) + return; + + bool is_float = depth == CV_32F; + const Point* ptsi = (const Point*)points.data; + const Point2f* ptsf = (const Point2f*)points.data; + + Point2f pt = is_float ? ptsf[0] : Point2f((float)ptsi[0].x,(float)ptsi[0].y); + Point2f pts[4] = {pt, pt, pt, pt}; + + for(int i = 1; i < count; i++ ) + { + Point2f pt = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y); + + if( pt.x < pts[0].x ) + pts[0] = pt; + if( pt.x > pts[1].x ) + pts[1] = pt; + if( pt.y < pts[2].y ) + pts[2] = pt; + if( pt.y > pts[3].y ) + pts[3] = pt; + } + + for( k = 0; k < max_iters; k++ ) + { + double min_delta = 0, delta; + Point2f ptf, farAway(0,0); + /*only for first iteration because the alg is repared at the loop's foot*/ + if( k == 0 ) + findEnslosingCicle4pts_32f( pts, center, radius ); + + for( i = 0; i < count; i++ ) + { + ptf = is_float ? ptsf[i] : Point2f((float)ptsi[i].x,(float)ptsi[i].y); + + delta = pointInCircle( ptf, center, radius ); + if( delta < min_delta ) + { + min_delta = delta; + farAway = ptf; + } + } + result = min_delta >= 0; + if( result ) + break; + + Point2f ptsCopy[4]; + // find good replacement partner for the point which is at most far away, + // starting with the one that lays in the actual circle (i=3) + for( i = 3; i >= 0; i-- ) + { + for( j = 0; j < 4; j++ ) + ptsCopy[j] = i != j ? pts[j] : farAway; + + findEnslosingCicle4pts_32f( ptsCopy, center, radius ); + if( pointInCircle( pts[i], center, radius ) >= 0) + { + // replaced one again in the new circle? + pts[i] = farAway; + break; + } + } + } + + if( !result ) + { + radius = 0.f; + for(int i = 0; i < count; i++ ) + { + Point2f ptf = is_float ? ptsf[i] : Point2f((float)ptsi[i].x,(float)ptsi[i].y); + float dx = center.x - ptf.x, dy = center.y - ptf.y; + float t = dx*dx + dy*dy; + radius = MAX(radius, t); + } + + radius = (float)(sqrt(radius)*(1 + eps)); + } + + _center = center; + _radius = radius; +} + + +// calculates length of a curve (e.g. contour perimeter) +double cv::arcLength( InputArray _curve, bool is_closed ) +{ + Mat curve = _curve.getMat(); + int count = curve.checkVector(2); + int depth = curve.depth(); + CV_Assert( count >= 0 && (depth == CV_32F || depth == CV_32S)); + double perimeter = 0; + + int i, j = 0; + const int N = 16; + float buf[N]; + + if( count <= 1 ) + return 0.; + + bool is_float = depth == CV_32F; + int last = is_closed ? count-1 : 0; + const Point* pti = (const Point*)curve.data; + const Point2f* ptf = (const Point2f*)curve.data; + + Point2f prev = is_float ? ptf[last] : Point2f((float)pti[last].x,(float)pti[last].y); + + for( i = 0; i < count; i++ ) + { + Point2f p = is_float ? ptf[i] : Point2f((float)pti[i].x,(float)pti[i].y); + float dx = p.x - prev.x, dy = p.y - prev.y; + buf[j] = dx*dx + dy*dy; + + if( ++j == N || i == count-1 ) + { + Mat bufmat(1, j, CV_32F, buf); + sqrt(bufmat, bufmat); + for( ; j > 0; j-- ) + perimeter += buf[j-1]; + } + prev = p; + } + + return perimeter; +} + +// area of a whole sequence +double cv::contourArea( InputArray _contour, bool oriented ) +{ + Mat contour = _contour.getMat(); + int npoints = contour.checkVector(2); + int depth = contour.depth(); + CV_Assert(npoints >= 0 && (depth == CV_32F || depth == CV_32S)); + + if( npoints == 0 ) + return 0.; + + double a00 = 0; + bool is_float = depth == CV_32F; + const Point* ptsi = (const Point*)contour.data; + const Point2f* ptsf = (const Point2f*)contour.data; + Point2f prev = is_float ? ptsf[npoints-1] : Point2f((float)ptsi[npoints-1].x, (float)ptsi[npoints-1].y); + + for( int i = 0; i < npoints; i++ ) + { + Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y); + a00 += (double)prev.x * p.y - (double)prev.y * p.x; + prev = p; + } + + a00 *= 0.5; + if( !oriented ) + a00 = fabs(a00); + + return a00; +} + + +cv::RotatedRect cv::fitEllipse( InputArray _points ) +{ + Mat points = _points.getMat(); + int i, n = points.checkVector(2); + int depth = points.depth(); + CV_Assert( n >= 0 && (depth == CV_32F || depth == CV_32S)); + + RotatedRect box; + + if( n < 5 ) + CV_Error( CV_StsBadSize, "There should be at least 5 points to fit the ellipse" ); + + // New fitellipse algorithm, contributed by Dr. Daniel Weiss + Point2f c(0,0); + double gfp[5], rp[5], t; + const double min_eps = 1e-6; + bool is_float = depth == CV_32F; + const Point* ptsi = (const Point*)points.data; + const Point2f* ptsf = (const Point2f*)points.data; + + AutoBuffer _Ad(n*5), _bd(n); + double *Ad = _Ad, *bd = _bd; + + // first fit for parameters A - E + Mat A( n, 5, CV_64F, Ad ); + Mat b( n, 1, CV_64F, bd ); + Mat x( 5, 1, CV_64F, gfp ); + + for( i = 0; i < n; i++ ) + { + Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y); + c += p; + } + c.x /= n; + c.y /= n; + + for( i = 0; i < n; i++ ) + { + Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y); + p -= c; + + bd[i] = 10000.0; // 1.0? + Ad[i*5] = -(double)p.x * p.x; // A - C signs inverted as proposed by APP + Ad[i*5 + 1] = -(double)p.y * p.y; + Ad[i*5 + 2] = -(double)p.x * p.y; + Ad[i*5 + 3] = p.x; + Ad[i*5 + 4] = p.y; + } + + solve(A, b, x, DECOMP_SVD); + + // now use general-form parameters A - E to find the ellipse center: + // differentiate general form wrt x/y to get two equations for cx and cy + A = Mat( 2, 2, CV_64F, Ad ); + b = Mat( 2, 1, CV_64F, bd ); + x = Mat( 2, 1, CV_64F, rp ); + Ad[0] = 2 * gfp[0]; + Ad[1] = Ad[2] = gfp[2]; + Ad[3] = 2 * gfp[1]; + bd[0] = gfp[3]; + bd[1] = gfp[4]; + solve( A, b, x, DECOMP_SVD ); + + // re-fit for parameters A - C with those center coordinates + A = Mat( n, 3, CV_64F, Ad ); + b = Mat( n, 1, CV_64F, bd ); + x = Mat( 3, 1, CV_64F, gfp ); + for( i = 0; i < n; i++ ) + { + Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y); + p -= c; + bd[i] = 1.0; + Ad[i * 3] = (p.x - rp[0]) * (p.x - rp[0]); + Ad[i * 3 + 1] = (p.y - rp[1]) * (p.y - rp[1]); + Ad[i * 3 + 2] = (p.x - rp[0]) * (p.y - rp[1]); + } + solve(A, b, x, DECOMP_SVD); + + // store angle and radii + rp[4] = -0.5 * atan2(gfp[2], gfp[1] - gfp[0]); // convert from APP angle usage + t = sin(-2.0 * rp[4]); + if( fabs(t) > fabs(gfp[2])*min_eps ) + t = gfp[2]/t; + else + t = gfp[1] - gfp[0]; + rp[2] = fabs(gfp[0] + gfp[1] - t); + if( rp[2] > min_eps ) + rp[2] = sqrt(2.0 / rp[2]); + rp[3] = fabs(gfp[0] + gfp[1] + t); + if( rp[3] > min_eps ) + rp[3] = sqrt(2.0 / rp[3]); + + box.center.x = (float)rp[0] + c.x; + box.center.y = (float)rp[1] + c.y; + box.size.width = (float)(rp[2]*2); + box.size.height = (float)(rp[3]*2); + if( box.size.width > box.size.height ) + { + float tmp; + CV_SWAP( box.size.width, box.size.height, tmp ); + box.angle = (float)(90 + rp[4]*180/CV_PI); + } + if( box.angle < -180 ) + box.angle += 360; + if( box.angle > 360 ) + box.angle -= 360; + + return box; +} + + +namespace cv +{ + +// Calculates bounding rectagnle of a point set or retrieves already calculated +static Rect pointSetBoundingRect( const Mat& points ) +{ + int npoints = points.checkVector(2); + int depth = points.depth(); + CV_Assert(npoints >= 0 && (depth == CV_32F || depth == CV_32S)); + + int xmin = 0, ymin = 0, xmax = -1, ymax = -1, i; + bool is_float = depth == CV_32F; + + if( npoints == 0 ) + return Rect(); + + const Point* pts = (const Point*)points.data; + Point pt = pts[0]; + +#if CV_SSE4_2 + if(cv::checkHardwareSupport(CV_CPU_SSE4_2)) + { + if( !is_float ) + { + __m128i minval, maxval; + minval = maxval = _mm_loadl_epi64((const __m128i*)(&pt)); //min[0]=pt.x, min[1]=pt.y + + for( i = 1; i < npoints; i++ ) + { + __m128i ptXY = _mm_loadl_epi64((const __m128i*)&pts[i]); + minval = _mm_min_epi32(ptXY, minval); + maxval = _mm_max_epi32(ptXY, maxval); + } + xmin = _mm_cvtsi128_si32(minval); + ymin = _mm_cvtsi128_si32(_mm_srli_si128(minval, 4)); + xmax = _mm_cvtsi128_si32(maxval); + ymax = _mm_cvtsi128_si32(_mm_srli_si128(maxval, 4)); + } + else + { + __m128 minvalf, maxvalf, z = _mm_setzero_ps(), ptXY = _mm_setzero_ps(); + minvalf = maxvalf = _mm_loadl_pi(z, (const __m64*)(&pt)); + + for( i = 1; i < npoints; i++ ) + { + ptXY = _mm_loadl_pi(ptXY, (const __m64*)&pts[i]); + + minvalf = _mm_min_ps(minvalf, ptXY); + maxvalf = _mm_max_ps(maxvalf, ptXY); + } + + float xyminf[2], xymaxf[2]; + _mm_storel_pi((__m64*)xyminf, minvalf); + _mm_storel_pi((__m64*)xymaxf, maxvalf); + xmin = cvFloor(xyminf[0]); + ymin = cvFloor(xyminf[1]); + xmax = cvFloor(xymaxf[0]); + ymax = cvFloor(xymaxf[1]); + } + } + else +#endif + { + if( !is_float ) + { + xmin = xmax = pt.x; + ymin = ymax = pt.y; + + for( i = 1; i < npoints; i++ ) + { + pt = pts[i]; + + if( xmin > pt.x ) + xmin = pt.x; + + if( xmax < pt.x ) + xmax = pt.x; + + if( ymin > pt.y ) + ymin = pt.y; + + if( ymax < pt.y ) + ymax = pt.y; + } + } + else + { + Cv32suf v; + // init values + xmin = xmax = CV_TOGGLE_FLT(pt.x); + ymin = ymax = CV_TOGGLE_FLT(pt.y); + + for( i = 1; i < npoints; i++ ) + { + pt = pts[i]; + pt.x = CV_TOGGLE_FLT(pt.x); + pt.y = CV_TOGGLE_FLT(pt.y); + + if( xmin > pt.x ) + xmin = pt.x; + + if( xmax < pt.x ) + xmax = pt.x; + + if( ymin > pt.y ) + ymin = pt.y; + + if( ymax < pt.y ) + ymax = pt.y; + } + + v.i = CV_TOGGLE_FLT(xmin); xmin = cvFloor(v.f); + v.i = CV_TOGGLE_FLT(ymin); ymin = cvFloor(v.f); + // because right and bottom sides of the bounding rectangle are not inclusive + // (note +1 in width and height calculation below), cvFloor is used here instead of cvCeil + v.i = CV_TOGGLE_FLT(xmax); xmax = cvFloor(v.f); + v.i = CV_TOGGLE_FLT(ymax); ymax = cvFloor(v.f); + } + } + + return Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); +} + + +static Rect maskBoundingRect( const Mat& img ) +{ + CV_Assert( img.depth() <= CV_8S && img.channels() == 1 ); + + Size size = img.size(); + int xmin = size.width, ymin = -1, xmax = -1, ymax = -1, i, j, k; + + for( i = 0; i < size.height; i++ ) + { + const uchar* _ptr = img.ptr(i); + const uchar* ptr = (const uchar*)alignPtr(_ptr, 4); + int have_nz = 0, k_min, offset = (int)(ptr - _ptr); + j = 0; + offset = MIN(offset, size.width); + for( ; j < offset; j++ ) + if( _ptr[j] ) + { + have_nz = 1; + break; + } + if( j < offset ) + { + if( j < xmin ) + xmin = j; + if( j > xmax ) + xmax = j; + } + if( offset < size.width ) + { + xmin -= offset; + xmax -= offset; + size.width -= offset; + j = 0; + for( ; j <= xmin - 4; j += 4 ) + if( *((int*)(ptr+j)) ) + break; + for( ; j < xmin; j++ ) + if( ptr[j] ) + { + xmin = j; + if( j > xmax ) + xmax = j; + have_nz = 1; + break; + } + k_min = MAX(j-1, xmax); + k = size.width - 1; + for( ; k > k_min && (k&3) != 3; k-- ) + if( ptr[k] ) + break; + if( k > k_min && (k&3) == 3 ) + { + for( ; k > k_min+3; k -= 4 ) + if( *((int*)(ptr+k-3)) ) + break; + } + for( ; k > k_min; k-- ) + if( ptr[k] ) + { + xmax = k; + have_nz = 1; + break; + } + if( !have_nz ) + { + j &= ~3; + for( ; j <= k - 3; j += 4 ) + if( *((int*)(ptr+j)) ) + break; + for( ; j <= k; j++ ) + if( ptr[j] ) + { + have_nz = 1; + break; + } + } + xmin += offset; + xmax += offset; + size.width += offset; + } + if( have_nz ) + { + if( ymin < 0 ) + ymin = i; + ymax = i; + } + } + + if( xmin >= size.width ) + xmin = ymin = 0; + return Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); +} + +} + +cv::Rect cv::boundingRect(InputArray array) +{ + Mat m = array.getMat(); + return m.depth() <= CV_8U ? maskBoundingRect(m) : pointSetBoundingRect(m); +} + +////////////////////////////////////////////// C API /////////////////////////////////////////// + +CV_IMPL int +cvMinEnclosingCircle( const void* array, CvPoint2D32f * _center, float *_radius ) +{ + cv::AutoBuffer abuf; + cv::Mat points = cv::cvarrToMat(array, false, false, 0, &abuf); + cv::Point2f center; + float radius; + + cv::minEnclosingCircle(points, center, radius); + if(_center) + *_center = center; + if(_radius) + *_radius = radius; + return 1; +} + +static void +icvMemCopy( double **buf1, double **buf2, double **buf3, int *b_max ) +{ + CV_Assert( (*buf1 != NULL || *buf2 != NULL) && *buf3 != NULL ); + + int bb = *b_max; + if( *buf2 == NULL ) + { + *b_max = 2 * (*b_max); + *buf2 = (double *)cvAlloc( (*b_max) * sizeof( double )); + + memcpy( *buf2, *buf3, bb * sizeof( double )); + + *buf3 = *buf2; + cvFree( buf1 ); + *buf1 = NULL; + } + else + { + *b_max = 2 * (*b_max); + *buf1 = (double *) cvAlloc( (*b_max) * sizeof( double )); + + memcpy( *buf1, *buf3, bb * sizeof( double )); + + *buf3 = *buf1; + cvFree( buf2 ); + *buf2 = NULL; + } +} + + +/* area of a contour sector */ +static double icvContourSecArea( CvSeq * contour, CvSlice slice ) +{ + CvPoint pt; /* pointer to points */ + CvPoint pt_s, pt_e; /* first and last points */ + CvSeqReader reader; /* points reader of contour */ + + int p_max = 2, p_ind; + int lpt, flag, i; + double a00; /* unnormalized moments m00 */ + double xi, yi, xi_1, yi_1, x0, y0, dxy, sk, sk1, t; + double x_s, y_s, nx, ny, dx, dy, du, dv; + double eps = 1.e-5; + double *p_are1, *p_are2, *p_are; + double area = 0; + + CV_Assert( contour != NULL && CV_IS_SEQ_POINT_SET( contour )); + + lpt = cvSliceLength( slice, contour ); + /*if( n2 >= n1 ) + lpt = n2 - n1 + 1; + else + lpt = contour->total - n1 + n2 + 1;*/ + + if( contour->total <= 0 || lpt <= 2 ) + return 0.; + + a00 = x0 = y0 = xi_1 = yi_1 = 0; + sk1 = 0; + flag = 0; + dxy = 0; + p_are1 = (double *) cvAlloc( p_max * sizeof( double )); + + p_are = p_are1; + p_are2 = NULL; + + cvStartReadSeq( contour, &reader, 0 ); + cvSetSeqReaderPos( &reader, slice.start_index ); + CV_READ_SEQ_ELEM( pt_s, reader ); + p_ind = 0; + cvSetSeqReaderPos( &reader, slice.end_index ); + CV_READ_SEQ_ELEM( pt_e, reader ); + +/* normal coefficients */ + nx = pt_s.y - pt_e.y; + ny = pt_e.x - pt_s.x; + cvSetSeqReaderPos( &reader, slice.start_index ); + + while( lpt-- > 0 ) + { + CV_READ_SEQ_ELEM( pt, reader ); + + if( flag == 0 ) + { + xi_1 = (double) pt.x; + yi_1 = (double) pt.y; + x0 = xi_1; + y0 = yi_1; + sk1 = 0; + flag = 1; + } + else + { + xi = (double) pt.x; + yi = (double) pt.y; + +/**************** edges intersection examination **************************/ + sk = nx * (xi - pt_s.x) + ny * (yi - pt_s.y); + if( (fabs( sk ) < eps && lpt > 0) || sk * sk1 < -eps ) + { + if( fabs( sk ) < eps ) + { + dxy = xi_1 * yi - xi * yi_1; + a00 = a00 + dxy; + dxy = xi * y0 - x0 * yi; + a00 = a00 + dxy; + + if( p_ind >= p_max ) + icvMemCopy( &p_are1, &p_are2, &p_are, &p_max ); + + p_are[p_ind] = a00 / 2.; + p_ind++; + a00 = 0; + sk1 = 0; + x0 = xi; + y0 = yi; + dxy = 0; + } + else + { +/* define intersection point */ + dv = yi - yi_1; + du = xi - xi_1; + dx = ny; + dy = -nx; + if( fabs( du ) > eps ) + t = ((yi_1 - pt_s.y) * du + dv * (pt_s.x - xi_1)) / + (du * dy - dx * dv); + else + t = (xi_1 - pt_s.x) / dx; + if( t > eps && t < 1 - eps ) + { + x_s = pt_s.x + t * dx; + y_s = pt_s.y + t * dy; + dxy = xi_1 * y_s - x_s * yi_1; + a00 += dxy; + dxy = x_s * y0 - x0 * y_s; + a00 += dxy; + if( p_ind >= p_max ) + icvMemCopy( &p_are1, &p_are2, &p_are, &p_max ); + + p_are[p_ind] = a00 / 2.; + p_ind++; + + a00 = 0; + sk1 = 0; + x0 = x_s; + y0 = y_s; + dxy = x_s * yi - xi * y_s; + } + } + } + else + dxy = xi_1 * yi - xi * yi_1; + + a00 += dxy; + xi_1 = xi; + yi_1 = yi; + sk1 = sk; + + } + } + + xi = x0; + yi = y0; + dxy = xi_1 * yi - xi * yi_1; + + a00 += dxy; + + if( p_ind >= p_max ) + icvMemCopy( &p_are1, &p_are2, &p_are, &p_max ); + + p_are[p_ind] = a00 / 2.; + p_ind++; + + // common area calculation + area = 0; + for( i = 0; i < p_ind; i++ ) + area += fabs( p_are[i] ); + + if( p_are1 != NULL ) + cvFree( &p_are1 ); + else if( p_are2 != NULL ) + cvFree( &p_are2 ); + + return area; +} + + +/* external contour area function */ +CV_IMPL double +cvContourArea( const void *array, CvSlice slice, int oriented ) +{ + double area = 0; + + CvContour contour_header; + CvSeq* contour = 0; + CvSeqBlock block; + + if( CV_IS_SEQ( array )) + { + contour = (CvSeq*)array; + if( !CV_IS_SEQ_POLYLINE( contour )) + CV_Error( CV_StsBadArg, "Unsupported sequence type" ); + } + else + { + contour = cvPointSeqFromMat( CV_SEQ_KIND_CURVE, array, &contour_header, &block ); + } + + if( cvSliceLength( slice, contour ) == contour->total ) + { + cv::AutoBuffer abuf; + cv::Mat points = cv::cvarrToMat(contour, false, false, 0, &abuf); + return cv::contourArea( points, oriented !=0 ); + } + + if( CV_SEQ_ELTYPE( contour ) != CV_32SC2 ) + CV_Error( CV_StsUnsupportedFormat, + "Only curves with integer coordinates are supported in case of contour slice" ); + area = icvContourSecArea( contour, slice ); + return oriented ? area : fabs(area); +} + + /* calculates length of a curve (e.g. contour perimeter) */ CV_IMPL double cvArcLength( const void *array, CvSlice slice, int is_closed ) @@ -67,8 +972,8 @@ cvArcLength( const void *array, CvSlice slice, int is_closed ) { is_closed = is_closed > 0; contour = cvPointSeqFromMat( - CV_SEQ_KIND_CURVE | (is_closed ? CV_SEQ_FLAG_CLOSED : 0), - array, &contour_header, &block ); + CV_SEQ_KIND_CURVE | (is_closed ? CV_SEQ_FLAG_CLOSED : 0), + array, &contour_header, &block ); } if( contour->total > 1 ) @@ -81,7 +986,7 @@ cvArcLength( const void *array, CvSlice slice, int is_closed ) count -= !is_closed && count == contour->total; - /* scroll the reader by 1 point */ + // scroll the reader by 1 point reader.prev_elem = reader.ptr; CV_NEXT_SEQ_ELEM( sizeof(CvPoint), reader ); @@ -123,812 +1028,19 @@ cvArcLength( const void *array, CvSlice slice, int is_closed ) } } } - + return perimeter; } -static CvStatus -icvFindCircle( CvPoint2D32f pt0, CvPoint2D32f pt1, - CvPoint2D32f pt2, CvPoint2D32f * center, float *radius ) -{ - double x1 = (pt0.x + pt1.x) * 0.5; - double dy1 = pt0.x - pt1.x; - double x2 = (pt1.x + pt2.x) * 0.5; - double dy2 = pt1.x - pt2.x; - double y1 = (pt0.y + pt1.y) * 0.5; - double dx1 = pt1.y - pt0.y; - double y2 = (pt1.y + pt2.y) * 0.5; - double dx2 = pt2.y - pt1.y; - double t = 0; - - CvStatus result = CV_OK; - - if( icvIntersectLines( x1, dx1, y1, dy1, x2, dx2, y2, dy2, &t ) >= 0 ) - { - center->x = (float) (x2 + dx2 * t); - center->y = (float) (y2 + dy2 * t); - *radius = (float) icvDistanceL2_32f( *center, pt0 ); - } - else - { - center->x = center->y = 0.f; - radius = 0; - result = CV_NOTDEFINED_ERR; - } - - return result; -} - - -CV_INLINE double icvIsPtInCircle( CvPoint2D32f pt, CvPoint2D32f center, float radius ) -{ - double dx = pt.x - center.x; - double dy = pt.y - center.y; - return (double)radius*radius - dx*dx - dy*dy; -} - - -static int -icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float *_radius ) -{ - int shuffles[4][4] = { {0, 1, 2, 3}, {0, 1, 3, 2}, {2, 3, 0, 1}, {2, 3, 1, 0} }; - - int idxs[4] = { 0, 1, 2, 3 }; - int i, j, k = 1, mi = 0; - float max_dist = 0; - CvPoint2D32f center; - CvPoint2D32f min_center; - float radius, min_radius = FLT_MAX; - CvPoint2D32f res_pts[4]; - - center = min_center = pts[0]; - radius = 1.f; - - for( i = 0; i < 4; i++ ) - for( j = i + 1; j < 4; j++ ) - { - float dist = icvDistanceL2_32f( pts[i], pts[j] ); - - if( max_dist < dist ) - { - max_dist = dist; - idxs[0] = i; - idxs[1] = j; - } - } - - if( max_dist == 0 ) - goto function_exit; - - k = 2; - for( i = 0; i < 4; i++ ) - { - for( j = 0; j < k; j++ ) - if( i == idxs[j] ) - break; - if( j == k ) - idxs[k++] = i; - } - - center = cvPoint2D32f( (pts[idxs[0]].x + pts[idxs[1]].x)*0.5f, - (pts[idxs[0]].y + pts[idxs[1]].y)*0.5f ); - radius = (float)(icvDistanceL2_32f( pts[idxs[0]], center )*1.03); - if( radius < 1.f ) - radius = 1.f; - - if( icvIsPtInCircle( pts[idxs[2]], center, radius ) >= 0 && - icvIsPtInCircle( pts[idxs[3]], center, radius ) >= 0 ) - { - k = 2; //rand()%2+2; - } - else - { - mi = -1; - for( i = 0; i < 4; i++ ) - { - if( icvFindCircle( pts[shuffles[i][0]], pts[shuffles[i][1]], - pts[shuffles[i][2]], ¢er, &radius ) >= 0 ) - { - radius *= 1.03f; - if( radius < 2.f ) - radius = 2.f; - - if( icvIsPtInCircle( pts[shuffles[i][3]], center, radius ) >= 0 && - min_radius > radius ) - { - min_radius = radius; - min_center = center; - mi = i; - } - } - } - assert( mi >= 0 ); - if( mi < 0 ) - mi = 0; - k = 3; - center = min_center; - radius = min_radius; - for( i = 0; i < 4; i++ ) - idxs[i] = shuffles[mi][i]; - } - - function_exit: - - *_center = center; - *_radius = radius; - - /* reorder output points */ - for( i = 0; i < 4; i++ ) - res_pts[i] = pts[idxs[i]]; - - for( i = 0; i < 4; i++ ) - { - pts[i] = res_pts[i]; - assert( icvIsPtInCircle( pts[i], center, radius ) >= 0 ); - } - - return k; -} - - -CV_IMPL int -cvMinEnclosingCircle( const void* array, CvPoint2D32f * _center, float *_radius ) -{ - const int max_iters = 100; - const float eps = FLT_EPSILON*2; - CvPoint2D32f center = { 0, 0 }; - float radius = 0; - int result = 0; - - if( _center ) - _center->x = _center->y = 0.f; - if( _radius ) - *_radius = 0; - - CvSeqReader reader; - int k, count; - CvPoint2D32f pts[8]; - CvContour contour_header; - CvSeqBlock block; - CvSeq* sequence = 0; - int is_float; - - if( !_center || !_radius ) - CV_Error( CV_StsNullPtr, "Null center or radius pointers" ); - - if( CV_IS_SEQ(array) ) - { - sequence = (CvSeq*)array; - if( !CV_IS_SEQ_POINT_SET( sequence )) - CV_Error( CV_StsBadArg, "The passed sequence is not a valid contour" ); - } - else - { - sequence = cvPointSeqFromMat( - CV_SEQ_KIND_GENERIC, array, &contour_header, &block ); - } - - if( sequence->total <= 0 ) - CV_Error( CV_StsBadSize, "" ); - - cvStartReadSeq( sequence, &reader, 0 ); - - count = sequence->total; - is_float = CV_SEQ_ELTYPE(sequence) == CV_32FC2; - - if( !is_float ) - { - CvPoint *pt_left, *pt_right, *pt_top, *pt_bottom; - CvPoint pt; - pt_left = pt_right = pt_top = pt_bottom = (CvPoint *)(reader.ptr); - CV_READ_SEQ_ELEM( pt, reader ); - - for(int i = 1; i < count; i++ ) - { - CvPoint* pt_ptr = (CvPoint*)reader.ptr; - CV_READ_SEQ_ELEM( pt, reader ); - - if( pt.x < pt_left->x ) - pt_left = pt_ptr; - if( pt.x > pt_right->x ) - pt_right = pt_ptr; - if( pt.y < pt_top->y ) - pt_top = pt_ptr; - if( pt.y > pt_bottom->y ) - pt_bottom = pt_ptr; - } - - pts[0] = cvPointTo32f( *pt_left ); - pts[1] = cvPointTo32f( *pt_right ); - pts[2] = cvPointTo32f( *pt_top ); - pts[3] = cvPointTo32f( *pt_bottom ); - } - else - { - CvPoint2D32f *pt_left, *pt_right, *pt_top, *pt_bottom; - CvPoint2D32f pt; - pt_left = pt_right = pt_top = pt_bottom = (CvPoint2D32f *) (reader.ptr); - CV_READ_SEQ_ELEM( pt, reader ); - - for(int i = 1; i < count; i++ ) - { - CvPoint2D32f* pt_ptr = (CvPoint2D32f*)reader.ptr; - CV_READ_SEQ_ELEM( pt, reader ); - - if( pt.x < pt_left->x ) - pt_left = pt_ptr; - if( pt.x > pt_right->x ) - pt_right = pt_ptr; - if( pt.y < pt_top->y ) - pt_top = pt_ptr; - if( pt.y > pt_bottom->y ) - pt_bottom = pt_ptr; - } - - pts[0] = *pt_left; - pts[1] = *pt_right; - pts[2] = *pt_top; - pts[3] = *pt_bottom; - } - - for( k = 0; k < max_iters; k++ ) - { - double min_delta = 0, delta; - CvPoint2D32f ptfl, farAway = { 0, 0}; - /*only for first iteration because the alg is repared at the loop's foot*/ - if(k==0) - icvFindEnslosingCicle4pts_32f( pts, ¢er, &radius ); - - cvStartReadSeq( sequence, &reader, 0 ); - - for(int i = 0; i < count; i++ ) - { - if( !is_float ) - { - ptfl.x = (float)((CvPoint*)reader.ptr)->x; - ptfl.y = (float)((CvPoint*)reader.ptr)->y; - } - else - { - ptfl = *(CvPoint2D32f*)reader.ptr; - } - CV_NEXT_SEQ_ELEM( sequence->elem_size, reader ); - - delta = icvIsPtInCircle( ptfl, center, radius ); - if( delta < min_delta ) - { - min_delta = delta; - farAway = ptfl; - } - } - result = min_delta >= 0; - if( result ) - break; - - CvPoint2D32f ptsCopy[4]; - /* find good replacement partner for the point which is at most far away, - starting with the one that lays in the actual circle (i=3) */ - for(int i = 3; i >=0; i-- ) - { - for(int j = 0; j < 4; j++ ) - { - ptsCopy[j]=(i != j)? pts[j]: farAway; - } - - icvFindEnslosingCicle4pts_32f(ptsCopy, ¢er, &radius ); - if( icvIsPtInCircle( pts[i], center, radius )>=0){ // replaced one again in the new circle? - pts[i] = farAway; - break; - } - } - } - - if( !result ) - { - cvStartReadSeq( sequence, &reader, 0 ); - radius = 0.f; - - for(int i = 0; i < count; i++ ) - { - CvPoint2D32f ptfl; - float t, dx, dy; - - if( !is_float ) - { - ptfl.x = (float)((CvPoint*)reader.ptr)->x; - ptfl.y = (float)((CvPoint*)reader.ptr)->y; - } - else - { - ptfl = *(CvPoint2D32f*)reader.ptr; - } - - CV_NEXT_SEQ_ELEM( sequence->elem_size, reader ); - dx = center.x - ptfl.x; - dy = center.y - ptfl.y; - t = dx*dx + dy*dy; - radius = MAX(radius,t); - } - - radius = (float)(sqrt(radius)*(1 + eps)); - result = 1; - } - - *_center = center; - *_radius = radius; - - return result; -} - - -/* area of a whole sequence */ -static CvStatus -icvContourArea( const CvSeq* contour, double *area ) -{ - if( contour->total ) - { - CvSeqReader reader; - int lpt = contour->total; - double a00 = 0, xi_1, yi_1; - int is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2; - - cvStartReadSeq( contour, &reader, 0 ); - - if( !is_float ) - { - xi_1 = ((CvPoint*)(reader.ptr))->x; - yi_1 = ((CvPoint*)(reader.ptr))->y; - } - else - { - xi_1 = ((CvPoint2D32f*)(reader.ptr))->x; - yi_1 = ((CvPoint2D32f*)(reader.ptr))->y; - } - CV_NEXT_SEQ_ELEM( contour->elem_size, reader ); - - while( lpt-- > 0 ) - { - double dxy, xi, yi; - - if( !is_float ) - { - xi = ((CvPoint*)(reader.ptr))->x; - yi = ((CvPoint*)(reader.ptr))->y; - } - else - { - xi = ((CvPoint2D32f*)(reader.ptr))->x; - yi = ((CvPoint2D32f*)(reader.ptr))->y; - } - CV_NEXT_SEQ_ELEM( contour->elem_size, reader ); - - dxy = xi_1 * yi - xi * yi_1; - a00 += dxy; - xi_1 = xi; - yi_1 = yi; - } - - *area = a00 * 0.5; - } - else - *area = 0; - - return CV_OK; -} - - -/****************************************************************************************\ - - copy data from one buffer to other buffer - -\****************************************************************************************/ - -static CvStatus -icvMemCopy( double **buf1, double **buf2, double **buf3, int *b_max ) -{ - int bb; - - if( (*buf1 == NULL && *buf2 == NULL) || *buf3 == NULL ) - return CV_NULLPTR_ERR; - - bb = *b_max; - if( *buf2 == NULL ) - { - *b_max = 2 * (*b_max); - *buf2 = (double *)cvAlloc( (*b_max) * sizeof( double )); - - if( *buf2 == NULL ) - return CV_OUTOFMEM_ERR; - - memcpy( *buf2, *buf3, bb * sizeof( double )); - - *buf3 = *buf2; - cvFree( buf1 ); - *buf1 = NULL; - } - else - { - *b_max = 2 * (*b_max); - *buf1 = (double *) cvAlloc( (*b_max) * sizeof( double )); - - if( *buf1 == NULL ) - return CV_OUTOFMEM_ERR; - - memcpy( *buf1, *buf3, bb * sizeof( double )); - - *buf3 = *buf1; - cvFree( buf2 ); - *buf2 = NULL; - } - return CV_OK; -} - - -/* area of a contour sector */ -static CvStatus icvContourSecArea( CvSeq * contour, CvSlice slice, double *area ) -{ - CvPoint pt; /* pointer to points */ - CvPoint pt_s, pt_e; /* first and last points */ - CvSeqReader reader; /* points reader of contour */ - - int p_max = 2, p_ind; - int lpt, flag, i; - double a00; /* unnormalized moments m00 */ - double xi, yi, xi_1, yi_1, x0, y0, dxy, sk, sk1, t; - double x_s, y_s, nx, ny, dx, dy, du, dv; - double eps = 1.e-5; - double *p_are1, *p_are2, *p_are; - - assert( contour != NULL ); - - if( contour == NULL ) - return CV_NULLPTR_ERR; - - if( !CV_IS_SEQ_POINT_SET( contour )) - return CV_BADFLAG_ERR; - - lpt = cvSliceLength( slice, contour ); - /*if( n2 >= n1 ) - lpt = n2 - n1 + 1; - else - lpt = contour->total - n1 + n2 + 1;*/ - - if( contour->total && lpt > 2 ) - { - a00 = x0 = y0 = xi_1 = yi_1 = 0; - sk1 = 0; - flag = 0; - dxy = 0; - p_are1 = (double *) cvAlloc( p_max * sizeof( double )); - - if( p_are1 == NULL ) - return CV_OUTOFMEM_ERR; - - p_are = p_are1; - p_are2 = NULL; - - cvStartReadSeq( contour, &reader, 0 ); - cvSetSeqReaderPos( &reader, slice.start_index ); - CV_READ_SEQ_ELEM( pt_s, reader ); - p_ind = 0; - cvSetSeqReaderPos( &reader, slice.end_index ); - CV_READ_SEQ_ELEM( pt_e, reader ); - -/* normal coefficients */ - nx = pt_s.y - pt_e.y; - ny = pt_e.x - pt_s.x; - cvSetSeqReaderPos( &reader, slice.start_index ); - - while( lpt-- > 0 ) - { - CV_READ_SEQ_ELEM( pt, reader ); - - if( flag == 0 ) - { - xi_1 = (double) pt.x; - yi_1 = (double) pt.y; - x0 = xi_1; - y0 = yi_1; - sk1 = 0; - flag = 1; - } - else - { - xi = (double) pt.x; - yi = (double) pt.y; - -/**************** edges intersection examination **************************/ - sk = nx * (xi - pt_s.x) + ny * (yi - pt_s.y); - if( (fabs( sk ) < eps && lpt > 0) || sk * sk1 < -eps ) - { - if( fabs( sk ) < eps ) - { - dxy = xi_1 * yi - xi * yi_1; - a00 = a00 + dxy; - dxy = xi * y0 - x0 * yi; - a00 = a00 + dxy; - - if( p_ind >= p_max ) - icvMemCopy( &p_are1, &p_are2, &p_are, &p_max ); - - p_are[p_ind] = a00 / 2.; - p_ind++; - a00 = 0; - sk1 = 0; - x0 = xi; - y0 = yi; - dxy = 0; - } - else - { -/* define intersection point */ - dv = yi - yi_1; - du = xi - xi_1; - dx = ny; - dy = -nx; - if( fabs( du ) > eps ) - t = ((yi_1 - pt_s.y) * du + dv * (pt_s.x - xi_1)) / - (du * dy - dx * dv); - else - t = (xi_1 - pt_s.x) / dx; - if( t > eps && t < 1 - eps ) - { - x_s = pt_s.x + t * dx; - y_s = pt_s.y + t * dy; - dxy = xi_1 * y_s - x_s * yi_1; - a00 += dxy; - dxy = x_s * y0 - x0 * y_s; - a00 += dxy; - if( p_ind >= p_max ) - icvMemCopy( &p_are1, &p_are2, &p_are, &p_max ); - - p_are[p_ind] = a00 / 2.; - p_ind++; - - a00 = 0; - sk1 = 0; - x0 = x_s; - y0 = y_s; - dxy = x_s * yi - xi * y_s; - } - } - } - else - dxy = xi_1 * yi - xi * yi_1; - - a00 += dxy; - xi_1 = xi; - yi_1 = yi; - sk1 = sk; - - } - } - - xi = x0; - yi = y0; - dxy = xi_1 * yi - xi * yi_1; - - a00 += dxy; - - if( p_ind >= p_max ) - icvMemCopy( &p_are1, &p_are2, &p_are, &p_max ); - - p_are[p_ind] = a00 / 2.; - p_ind++; - -/* common area calculation */ - *area = 0; - for( i = 0; i < p_ind; i++ ) - (*area) += fabs( p_are[i] ); - - if( p_are1 != NULL ) - cvFree( &p_are1 ); - else if( p_are2 != NULL ) - cvFree( &p_are2 ); - - return CV_OK; - } - else - return CV_BADSIZE_ERR; -} - - -/* external contour area function */ -CV_IMPL double -cvContourArea( const void *array, CvSlice slice, int oriented ) -{ - double area = 0; - - CvContour contour_header; - CvSeq* contour = 0; - CvSeqBlock block; - - if( CV_IS_SEQ( array )) - { - contour = (CvSeq*)array; - if( !CV_IS_SEQ_POLYLINE( contour )) - CV_Error( CV_StsBadArg, "Unsupported sequence type" ); - } - else - { - contour = cvPointSeqFromMat( CV_SEQ_KIND_CURVE, array, &contour_header, &block ); - } - - if( cvSliceLength( slice, contour ) == contour->total ) - { - IPPI_CALL( icvContourArea( contour, &area )); - } - else - { - if( CV_SEQ_ELTYPE( contour ) != CV_32SC2 ) - CV_Error( CV_StsUnsupportedFormat, - "Only curves with integer coordinates are supported in case of contour slice" ); - IPPI_CALL( icvContourSecArea( contour, slice, &area )); - } - - return oriented ? area : fabs(area); -} - - CV_IMPL CvBox2D cvFitEllipse2( const CvArr* array ) { - CvBox2D box; - cv::AutoBuffer Ad, bd; - memset( &box, 0, sizeof(box)); - - CvContour contour_header; - CvSeq* ptseq = 0; - CvSeqBlock block; - int n; - - if( CV_IS_SEQ( array )) - { - ptseq = (CvSeq*)array; - if( !CV_IS_SEQ_POINT_SET( ptseq )) - CV_Error( CV_StsBadArg, "Unsupported sequence type" ); - } - else - { - ptseq = cvPointSeqFromMat(CV_SEQ_KIND_GENERIC, array, &contour_header, &block); - } - - n = ptseq->total; - if( n < 5 ) - CV_Error( CV_StsBadSize, "Number of points should be >= 5" ); - - /* - * New fitellipse algorithm, contributed by Dr. Daniel Weiss - */ - CvPoint2D32f c = {0,0}; - double gfp[5], rp[5], t; - CvMat A, b, x; - const double min_eps = 1e-6; - int i, is_float; - CvSeqReader reader; - - Ad.allocate(n*5); - bd.allocate(n); - - // first fit for parameters A - E - A = cvMat( n, 5, CV_64F, Ad ); - b = cvMat( n, 1, CV_64F, bd ); - x = cvMat( 5, 1, CV_64F, gfp ); - - cvStartReadSeq( ptseq, &reader ); - is_float = CV_SEQ_ELTYPE(ptseq) == CV_32FC2; - - for( i = 0; i < n; i++ ) - { - CvPoint2D32f p; - if( is_float ) - p = *(CvPoint2D32f*)(reader.ptr); - else - { - p.x = (float)((int*)reader.ptr)[0]; - p.y = (float)((int*)reader.ptr)[1]; - } - CV_NEXT_SEQ_ELEM( sizeof(p), reader ); - c.x += p.x; - c.y += p.y; - } - c.x /= n; - c.y /= n; - - for( i = 0; i < n; i++ ) - { - CvPoint2D32f p; - if( is_float ) - p = *(CvPoint2D32f*)(reader.ptr); - else - { - p.x = (float)((int*)reader.ptr)[0]; - p.y = (float)((int*)reader.ptr)[1]; - } - CV_NEXT_SEQ_ELEM( sizeof(p), reader ); - p.x -= c.x; - p.y -= c.y; - - bd[i] = 10000.0; // 1.0? - Ad[i*5] = -(double)p.x * p.x; // A - C signs inverted as proposed by APP - Ad[i*5 + 1] = -(double)p.y * p.y; - Ad[i*5 + 2] = -(double)p.x * p.y; - Ad[i*5 + 3] = p.x; - Ad[i*5 + 4] = p.y; - } - - cvSolve( &A, &b, &x, CV_SVD ); - - // now use general-form parameters A - E to find the ellipse center: - // differentiate general form wrt x/y to get two equations for cx and cy - A = cvMat( 2, 2, CV_64F, Ad ); - b = cvMat( 2, 1, CV_64F, bd ); - x = cvMat( 2, 1, CV_64F, rp ); - Ad[0] = 2 * gfp[0]; - Ad[1] = Ad[2] = gfp[2]; - Ad[3] = 2 * gfp[1]; - bd[0] = gfp[3]; - bd[1] = gfp[4]; - cvSolve( &A, &b, &x, CV_SVD ); - - // re-fit for parameters A - C with those center coordinates - A = cvMat( n, 3, CV_64F, Ad ); - b = cvMat( n, 1, CV_64F, bd ); - x = cvMat( 3, 1, CV_64F, gfp ); - for( i = 0; i < n; i++ ) - { - CvPoint2D32f p; - if( is_float ) - p = *(CvPoint2D32f*)(reader.ptr); - else - { - p.x = (float)((int*)reader.ptr)[0]; - p.y = (float)((int*)reader.ptr)[1]; - } - CV_NEXT_SEQ_ELEM( sizeof(p), reader ); - p.x -= c.x; - p.y -= c.y; - bd[i] = 1.0; - Ad[i * 3] = (p.x - rp[0]) * (p.x - rp[0]); - Ad[i * 3 + 1] = (p.y - rp[1]) * (p.y - rp[1]); - Ad[i * 3 + 2] = (p.x - rp[0]) * (p.y - rp[1]); - } - cvSolve(&A, &b, &x, CV_SVD); - - // store angle and radii - rp[4] = -0.5 * atan2(gfp[2], gfp[1] - gfp[0]); // convert from APP angle usage - t = sin(-2.0 * rp[4]); - if( fabs(t) > fabs(gfp[2])*min_eps ) - t = gfp[2]/t; - else - t = gfp[1] - gfp[0]; - rp[2] = fabs(gfp[0] + gfp[1] - t); - if( rp[2] > min_eps ) - rp[2] = sqrt(2.0 / rp[2]); - rp[3] = fabs(gfp[0] + gfp[1] + t); - if( rp[3] > min_eps ) - rp[3] = sqrt(2.0 / rp[3]); - - box.center.x = (float)rp[0] + c.x; - box.center.y = (float)rp[1] + c.y; - box.size.width = (float)(rp[2]*2); - box.size.height = (float)(rp[3]*2); - if( box.size.width > box.size.height ) - { - float tmp; - CV_SWAP( box.size.width, box.size.height, tmp ); - box.angle = (float)(90 + rp[4]*180/CV_PI); - } - if( box.angle < -180 ) - box.angle += 360; - if( box.angle > 360 ) - box.angle -= 360; - - return box; + cv::AutoBuffer abuf; + cv::Mat points = cv::cvarrToMat(array, false, false, 0, &abuf); + return cv::fitEllipse(points); } - /* Calculates bounding rectagnle of a point set or retrieves already calculated */ CV_IMPL CvRect cvBoundingRect( CvArr* array, int update ) @@ -977,210 +1089,17 @@ cvBoundingRect( CvArr* array, int update ) if( mat ) { - CvSize size = cvGetMatSize(mat); - xmin = size.width; - ymin = -1; - - for( i = 0; i < size.height; i++ ) - { - uchar* _ptr = mat->data.ptr + i*mat->step; - uchar* ptr = (uchar*)cvAlignPtr(_ptr, 4); - int have_nz = 0, k_min, offset = (int)(ptr - _ptr); - j = 0; - offset = MIN(offset, size.width); - for( ; j < offset; j++ ) - if( _ptr[j] ) - { - have_nz = 1; - break; - } - if( j < offset ) - { - if( j < xmin ) - xmin = j; - if( j > xmax ) - xmax = j; - } - if( offset < size.width ) - { - xmin -= offset; - xmax -= offset; - size.width -= offset; - j = 0; - for( ; j <= xmin - 4; j += 4 ) - if( *((int*)(ptr+j)) ) - break; - for( ; j < xmin; j++ ) - if( ptr[j] ) - { - xmin = j; - if( j > xmax ) - xmax = j; - have_nz = 1; - break; - } - k_min = MAX(j-1, xmax); - k = size.width - 1; - for( ; k > k_min && (k&3) != 3; k-- ) - if( ptr[k] ) - break; - if( k > k_min && (k&3) == 3 ) - { - for( ; k > k_min+3; k -= 4 ) - if( *((int*)(ptr+k-3)) ) - break; - } - for( ; k > k_min; k-- ) - if( ptr[k] ) - { - xmax = k; - have_nz = 1; - break; - } - if( !have_nz ) - { - j &= ~3; - for( ; j <= k - 3; j += 4 ) - if( *((int*)(ptr+j)) ) - break; - for( ; j <= k; j++ ) - if( ptr[j] ) - { - have_nz = 1; - break; - } - } - xmin += offset; - xmax += offset; - size.width += offset; - } - if( have_nz ) - { - if( ymin < 0 ) - ymin = i; - ymax = i; - } - } - - if( xmin >= size.width ) - xmin = ymin = 0; + rect = cv::maskBoundingRect(cv::cvarrToMat(mat)); } else if( ptseq->total ) { - int is_float = CV_SEQ_ELTYPE(ptseq) == CV_32FC2; - cvStartReadSeq( ptseq, &reader, 0 ); - CvPoint pt; - CV_READ_SEQ_ELEM( pt, reader ); - #if CV_SSE4_2 - if(cv::checkHardwareSupport(CV_CPU_SSE4_2)) - { - if( !is_float ) - { - __m128i minval, maxval; - minval = maxval = _mm_loadl_epi64((const __m128i*)(&pt)); //min[0]=pt.x, min[1]=pt.y - - for( i = 1; i < ptseq->total; i++) - { - __m128i ptXY = _mm_loadl_epi64((const __m128i*)(reader.ptr)); - CV_NEXT_SEQ_ELEM(sizeof(pt), reader); - minval = _mm_min_epi32(ptXY, minval); - maxval = _mm_max_epi32(ptXY, maxval); - } - xmin = _mm_cvtsi128_si32(minval); - ymin = _mm_cvtsi128_si32(_mm_srli_si128(minval, 4)); - xmax = _mm_cvtsi128_si32(maxval); - ymax = _mm_cvtsi128_si32(_mm_srli_si128(maxval, 4)); - } - else - { - __m128 minvalf, maxvalf, z = _mm_setzero_ps(), ptXY = _mm_setzero_ps(); - minvalf = maxvalf = _mm_loadl_pi(z, (const __m64*)(&pt)); - - for( i = 1; i < ptseq->total; i++ ) - { - ptXY = _mm_loadl_pi(ptXY, (const __m64*)reader.ptr); - CV_NEXT_SEQ_ELEM(sizeof(pt), reader); - - minvalf = _mm_min_ps(minvalf, ptXY); - maxvalf = _mm_max_ps(maxvalf, ptXY); - } - - float xyminf[2], xymaxf[2]; - _mm_storel_pi((__m64*)xyminf, minvalf); - _mm_storel_pi((__m64*)xymaxf, maxvalf); - xmin = cvFloor(xyminf[0]); - ymin = cvFloor(xyminf[1]); - xmax = cvFloor(xymaxf[0]); - ymax = cvFloor(xymaxf[1]); - } - } - else - #endif - { - if( !is_float ) - { - xmin = xmax = pt.x; - ymin = ymax = pt.y; - - for( i = 1; i < ptseq->total; i++ ) - { - CV_READ_SEQ_ELEM( pt, reader ); - - if( xmin > pt.x ) - xmin = pt.x; - - if( xmax < pt.x ) - xmax = pt.x; - - if( ymin > pt.y ) - ymin = pt.y; - - if( ymax < pt.y ) - ymax = pt.y; - } - } - else - { - Cv32suf v; - // init values - xmin = xmax = CV_TOGGLE_FLT(pt.x); - ymin = ymax = CV_TOGGLE_FLT(pt.y); - - for( i = 1; i < ptseq->total; i++ ) - { - CV_READ_SEQ_ELEM( pt, reader ); - pt.x = CV_TOGGLE_FLT(pt.x); - pt.y = CV_TOGGLE_FLT(pt.y); - - if( xmin > pt.x ) - xmin = pt.x; - - if( xmax < pt.x ) - xmax = pt.x; - - if( ymin > pt.y ) - ymin = pt.y; - - if( ymax < pt.y ) - ymax = pt.y; - } - - v.i = CV_TOGGLE_FLT(xmin); xmin = cvFloor(v.f); - v.i = CV_TOGGLE_FLT(ymin); ymin = cvFloor(v.f); - // because right and bottom sides of the bounding rectangle are not inclusive - // (note +1 in width and height calculation below), cvFloor is used here instead of cvCeil - v.i = CV_TOGGLE_FLT(xmax); xmax = cvFloor(v.f); - v.i = CV_TOGGLE_FLT(ymax); ymax = cvFloor(v.f); - } - } - rect.x = xmin; - rect.y = ymin; - rect.width = xmax - xmin + 1; - rect.height = ymax - ymin + 1; + cv::AutoBuffer abuf; + rect = cv::pointSetBoundingRect(cv::cvarrToMat(ptseq, false, false, 0, &abuf)); } if( update ) ((CvContour*)ptseq)->rect = rect; return rect; } + /* End of file. */ diff --git a/samples/cpp/minarea.cpp b/samples/cpp/minarea.cpp index 6056c39c45..eca5dc1d36 100644 --- a/samples/cpp/minarea.cpp +++ b/samples/cpp/minarea.cpp @@ -13,7 +13,7 @@ static void help() "Random points are generated and then enclosed.\n" "Call:\n" "./minarea\n" - "Using OpenCV version %s\n" << CV_VERSION << "\n" << endl; + "Using OpenCV v" << CV_VERSION << "\n" << endl; } int main( int /*argc*/, char** /*argv*/ )