Commit dc4d0398 authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

converted few more comp. geometry functions to C++

parent c2241dcc
...@@ -52,16 +52,6 @@ CV_INLINE float icvDistanceL2_32f( CvPoint2D32f pt1, CvPoint2D32f pt2 ) ...@@ -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. */ /* curvature: 0 - 1-curvature, 1 - k-cosine curvature. */
CvSeq* icvApproximateChainTC89( CvChain* chain, int header_size, CvMemStorage* storage, int method ); CvSeq* icvApproximateChainTC89( CvChain* chain, int header_size, CvMemStorage* storage, int method );
......
...@@ -1753,85 +1753,4 @@ void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours, ...@@ -1753,85 +1753,4 @@ void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours,
findContours(_image, _contours, noArray(), mode, method, offset); 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*)&center, &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. */ /* End of file. */
...@@ -92,93 +92,34 @@ cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] ) ...@@ -92,93 +92,34 @@ cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] )
} }
int double cv::pointPolygonTest( InputArray _contour, Point2f pt, bool measureDist )
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 result = 0; 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; bool is_float = depth == CV_32F;
CvContour header;
CvSeq* contour = (CvSeq*)_contour;
CvSeqReader reader;
int i, total, counter = 0;
int is_float;
double min_dist_num = FLT_MAX, min_dist_denom = 1; 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) ) if( total == 0 )
{ return measureDist ? -DBL_MAX : -1;
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" );
total = contour->total; const Point* cnt = (const Point*)contour.data;
is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2; const Point2f* cntf = (const Point2f*)cnt;
cvStartReadSeq( contour, &reader, -1 );
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 // the fastest "purely integer" branch
CvPoint v0, v; Point v0, v = cnt[total-1];
CV_READ_SEQ_ELEM( v, reader );
for( i = 0; i < total; i++ ) for( i = 0; i < total; i++ )
{ {
int dist; int dist;
v0 = v; v0 = v;
CV_READ_SEQ_ELEM( v, reader ); v = cnt[i];
if( (v0.y <= ip.y && v.y <= ip.y) || if( (v0.y <= ip.y && v.y <= ip.y) ||
(v0.y > ip.y && v.y > ip.y) || (v0.y > ip.y && v.y > ip.y) ||
...@@ -202,34 +143,28 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist ) ...@@ -202,34 +143,28 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist )
} }
else else
{ {
CvPoint2D32f v0, v; Point2f v0, v;
CvPoint iv; Point iv;
if( is_float ) if( is_float )
{ {
CV_READ_SEQ_ELEM( v, reader ); v = cntf[total-1];
} }
else else
{ {
CV_READ_SEQ_ELEM( iv, reader ); v = cnt[total-1];
v = cvPointTo32f( iv );
} }
if( !measure_dist ) if( !measureDist )
{ {
for( i = 0; i < total; i++ ) for( i = 0; i < total; i++ )
{ {
double dist; double dist;
v0 = v; v0 = v;
if( is_float ) if( is_float )
{ v = cntf[i];
CV_READ_SEQ_ELEM( v, reader );
}
else else
{ v = cnt[i];
CV_READ_SEQ_ELEM( iv, reader );
v = cvPointTo32f( iv );
}
if( (v0.y <= pt.y && v.y <= pt.y) || if( (v0.y <= pt.y && v.y <= pt.y) ||
(v0.y > pt.y && v.y > pt.y) || (v0.y > pt.y && v.y > pt.y) ||
...@@ -259,14 +194,9 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist ) ...@@ -259,14 +194,9 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist )
v0 = v; v0 = v;
if( is_float ) if( is_float )
{ v = cntf[i];
CV_READ_SEQ_ELEM( v, reader );
}
else else
{ v = cnt[i];
CV_READ_SEQ_ELEM( iv, reader );
v = cvPointTo32f( iv );
}
dx = v.x - v0.x; dy = v.y - v0.y; dx = v.x - v0.x; dy = v.y - v0.y;
dx1 = pt.x - v0.x; dy1 = pt.y - v0.y; dx1 = pt.x - v0.x; dy1 = pt.y - v0.y;
...@@ -312,6 +242,14 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist ) ...@@ -312,6 +242,14 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist )
} }
CV_IMPL double
cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist )
{
cv::AutoBuffer<double> 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), This code is described in "Computational Geometry in C" (Second Edition),
Chapter 7. It is not written to be comprehensible without the Chapter 7. It is not written to be comprehensible without the
......
...@@ -40,64 +40,21 @@ ...@@ -40,64 +40,21 @@
//M*/ //M*/
#include "precomp.hpp" #include "precomp.hpp"
/*F///////////////////////////////////////////////////////////////////////////////////////
// Name: cvMatchContours double cv::matchShapes(InputArray contour1, InputArray contour2, int method, double)
// 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*/ )
{ {
CvMoments moments;
CvHuMoments huMoments;
double ma[7], mb[7]; double ma[7], mb[7];
int i, sma, smb; int i, sma, smb;
double eps = 1.e-5; double eps = 1.e-5;
double mmm; double mmm;
double result = 0; double result = 0;
if( !contour1 || !contour2 ) HuMoments( moments(contour1), ma );
CV_Error( CV_StsNullPtr, "" ); HuMoments( moments(contour2), mb );
// 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;
switch (method) switch (method)
{ {
case 1: case 1:
{
for( i = 0; i < 7; i++ ) for( i = 0; i < 7; i++ )
{ {
double ama = fabs( ma[i] ); double ama = fabs( ma[i] );
...@@ -124,10 +81,8 @@ cvMatchShapes( const void* contour1, const void* contour2, ...@@ -124,10 +81,8 @@ cvMatchShapes( const void* contour1, const void* contour2,
} }
} }
break; break;
}
case 2: case 2:
{
for( i = 0; i < 7; i++ ) for( i = 0; i < 7; i++ )
{ {
double ama = fabs( ma[i] ); double ama = fabs( ma[i] );
...@@ -154,10 +109,8 @@ cvMatchShapes( const void* contour1, const void* contour2, ...@@ -154,10 +109,8 @@ cvMatchShapes( const void* contour1, const void* contour2,
} }
} }
break; break;
}
case 3: case 3:
{
for( i = 0; i < 7; i++ ) for( i = 0; i < 7; i++ )
{ {
double ama = fabs( ma[i] ); double ama = fabs( ma[i] );
...@@ -186,7 +139,6 @@ cvMatchShapes( const void* contour1, const void* contour2, ...@@ -186,7 +139,6 @@ cvMatchShapes( const void* contour1, const void* contour2,
} }
} }
break; break;
}
default: default:
CV_Error( CV_StsBadArg, "Unknown comparison method" ); CV_Error( CV_StsBadArg, "Unknown comparison method" );
} }
...@@ -195,4 +147,15 @@ cvMatchShapes( const void* contour1, const void* contour2, ...@@ -195,4 +147,15 @@ cvMatchShapes( const void* contour1, const void* contour2,
} }
CV_IMPL double
cvMatchShapes( const void* _contour1, const void* _contour2,
int method, double parameter )
{
cv::AutoBuffer<double> 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. */ /* End of file. */
/*M/////////////////////////////////////////////////////////////////////////////////////// /*M///////////////////////////////////////////////////////////////////////////////////////
// //
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
// //
// By downloading, copying, installing or using the software you agree to this license. // 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, // If you do not agree to this license, do not download, install,
// copy or use the software. // copy or use the software.
// //
// //
// Intel License Agreement // License Agreement
// For Open Source Computer Vision Library // For Open Source Computer Vision Library
// //
// Copyright (C) 2000, Intel Corporation, all rights reserved. // Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners. // Third party copyrights are property of their respective owners.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// * Redistribution's of source code must retain the above copyright notice, // * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// * Redistribution's in binary form must reproduce the above copyright notice, // * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation // this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution. // and/or other materials provided with the distribution.
// //
// * The name of Intel Corporation may not be used to endorse or promote products // * The name of OpenCV Foundation may not be used to endorse or promote products
// derived from this software without specific prior written permission. // derived from this software without specific prior written permission.
// //
// This software is provided by the copyright holders and contributors "as is" and // 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 // any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed. // 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, // In no event shall the OpenCV Foundation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages // indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services; // (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused // loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability, // and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of // 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. // the use of this software, even if advised of the possibility of such damage.
// //
//M*/ //M*/
#include "precomp.hpp" #include "precomp.hpp"
typedef struct namespace cv
{ {
struct MinAreaState
{
int bottom; int bottom;
int left; int left;
float height; float height;
float width; float width;
float base_a; float base_a;
float base_b; float base_b;
} };
icvMinAreaState;
enum { CALIPERS_MAXHEIGHT=0, CALIPERS_MINAREARECT=1, CALIPERS_MAXDIST=2 };
#define CV_CALIPERS_MAXHEIGHT 0
#define CV_CALIPERS_MINAREARECT 1 /*F///////////////////////////////////////////////////////////////////////////////////////
#define CV_CALIPERS_MAXDIST 2 // Name: rotatingCalipers
// Purpose:
/*F/////////////////////////////////////////////////////////////////////////////////////// // Rotating calipers algorithm with some applications
// Name: icvRotatingCalipers //
// Purpose: // Context:
// Rotating calipers algorithm with some applications // Parameters:
// // points - convex hull vertices ( any orientation )
// Context: // n - number of vertices
// Parameters: // mode - concrete application of algorithm
// points - convex hull vertices ( any orientation ) // can be CV_CALIPERS_MAXDIST or
// n - number of vertices // CV_CALIPERS_MINAREARECT
// mode - concrete application of algorithm // left, bottom, right, top - indexes of extremal points
// can be CV_CALIPERS_MAXDIST or // out - output info.
// CV_CALIPERS_MINAREARECT // In case CV_CALIPERS_MAXDIST it points to float value -
// left, bottom, right, top - indexes of extremal points // maximal height of polygon.
// out - output info. // In case CV_CALIPERS_MINAREARECT
// In case CV_CALIPERS_MAXDIST it points to float value - // ((CvPoint2D32f*)out)[0] - corner
// maximal height of polygon. // ((CvPoint2D32f*)out)[1] - vector1
// In case CV_CALIPERS_MINAREARECT // ((CvPoint2D32f*)out)[0] - corner2
// ((CvPoint2D32f*)out)[0] - corner //
// ((CvPoint2D32f*)out)[1] - vector1 // ^
// ((CvPoint2D32f*)out)[0] - corner2 // |
// // vector2 |
// ^ // |
// | // |____________\
// vector2 | // corner /
// | // vector1
// |____________\ //
// corner / // Returns:
// vector1 // Notes:
// //F*/
// Returns:
// Notes: /* we will use usual cartesian coordinates */
//F*/ static void rotatingCalipers( const Point2f* points, int n, int mode, float* out )
{
/* we will use usual cartesian coordinates */
static void
icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
{
float minarea = FLT_MAX; float minarea = FLT_MAX;
float max_dist = 0; float max_dist = 0;
char buffer[32] = {}; char buffer[32] = {};
int i, k; int i, k;
CvPoint2D32f* vect = (CvPoint2D32f*)cvAlloc( n * sizeof(vect[0]) ); AutoBuffer<float> buf(n*3);
float* inv_vect_length = (float*)cvAlloc( n * sizeof(inv_vect_length[0]) ); float* inv_vect_length = buf;
Point2f* vect = (Point2f*)(inv_vect_length + n);
int left = 0, bottom = 0, right = 0, top = 0; int left = 0, bottom = 0, right = 0, top = 0;
int seq[4] = { -1, -1, -1, -1 }; int seq[4] = { -1, -1, -1, -1 };
...@@ -110,7 +110,7 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out ) ...@@ -110,7 +110,7 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
float base_b = 0; float base_b = 0;
float left_x, right_x, top_y, bottom_y; float left_x, right_x, top_y, bottom_y;
CvPoint2D32f pt0 = points[0]; Point2f pt0 = points[0];
left_x = right_x = pt0.x; left_x = right_x = pt0.x;
top_y = bottom_y = pt0.y; top_y = bottom_y = pt0.y;
...@@ -131,7 +131,7 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out ) ...@@ -131,7 +131,7 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
if( pt0.y < bottom_y ) if( pt0.y < bottom_y )
bottom_y = pt0.y, bottom = i; bottom_y = pt0.y, bottom = i;
CvPoint2D32f pt = points[(i+1) & (i+1 < n ? -1 : 0)]; Point2f pt = points[(i+1) & (i+1 < n ? -1 : 0)];
dx = pt.x - pt0.x; dx = pt.x - pt0.x;
dy = pt.y - pt0.y; dy = pt.y - pt0.y;
...@@ -143,9 +143,7 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out ) ...@@ -143,9 +143,7 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
pt0 = pt; pt0 = pt;
} }
//cvbInvSqrt( inv_vect_length, inv_vect_length, n ); // find convex hull orientation
/* find convex hull orientation */
{ {
double ax = vect[n-1].x; double ax = vect[n-1].x;
double ay = vect[n-1].y; double ay = vect[n-1].y;
...@@ -165,18 +163,18 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out ) ...@@ -165,18 +163,18 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
ax = bx; ax = bx;
ay = by; ay = by;
} }
assert( orientation != 0 ); CV_Assert( orientation != 0 );
} }
base_a = orientation; base_a = orientation;
/*****************************************************************************************/ /*****************************************************************************************/
/* init calipers position */ /* init calipers position */
seq[0] = bottom; seq[0] = bottom;
seq[1] = right; seq[1] = right;
seq[2] = top; seq[2] = top;
seq[3] = left; seq[3] = left;
/*****************************************************************************************/ /*****************************************************************************************/
/* Main loop - evaluate angles and rotate calipers */ /* Main loop - evaluate angles and rotate calipers */
/* all of edges will be checked while rotating calipers by 90 degrees */ /* all of edges will be checked while rotating calipers by 90 degrees */
for( k = 0; k < n; k++ ) for( k = 0; k < n; k++ )
...@@ -229,17 +227,17 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out ) ...@@ -229,17 +227,17 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
base_a = -lead_y; base_a = -lead_y;
base_b = lead_x; base_b = lead_x;
break; break;
default: assert(0); default:
CV_Error(CV_StsError, "main_element should be 0, 1, 2 or 3");
} }
} }
/* change base point of main edge */ /* change base point of main edge */
seq[main_element] += 1; seq[main_element] += 1;
seq[main_element] = (seq[main_element] == n) ? 0 : seq[main_element]; seq[main_element] = (seq[main_element] == n) ? 0 : seq[main_element];
switch (mode) switch (mode)
{ {
case CV_CALIPERS_MAXHEIGHT: case CALIPERS_MAXHEIGHT:
{ {
/* now main element lies on edge alligned to calipers side */ /* now main element lies on edge alligned to calipers side */
...@@ -261,7 +259,7 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out ) ...@@ -261,7 +259,7 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
break; break;
} }
case CV_CALIPERS_MINAREARECT: case CALIPERS_MINAREARECT:
/* find area of rectangle */ /* find area of rectangle */
{ {
float height; float height;
...@@ -304,7 +302,7 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out ) ...@@ -304,7 +302,7 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
switch (mode) switch (mode)
{ {
case CV_CALIPERS_MINAREARECT: case CALIPERS_MINAREARECT:
{ {
float *buf = (float *) buffer; float *buf = (float *) buffer;
...@@ -332,87 +330,38 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out ) ...@@ -332,87 +330,38 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
out[5] = B2 * buf[4]; out[5] = B2 * buf[4];
} }
break; break;
case CV_CALIPERS_MAXHEIGHT: case CALIPERS_MAXHEIGHT:
{ {
out[0] = max_dist; out[0] = max_dist;
} }
break; break;
} }
}
cvFree( &vect );
cvFree( &inv_vect_length );
} }
CV_IMPL CvBox2D cv::RotatedRect cv::minAreaRect( InputArray _points )
cvMinAreaRect2( const CvArr* array, CvMemStorage* storage )
{ {
cv::Ptr<CvMemStorage> temp_storage; Mat hull;
CvBox2D box; Point2f out[3];
cv::AutoBuffer<CvPoint2D32f> _points; RotatedRect box;
CvPoint2D32f* points;
memset(&box, 0, sizeof(box)); convexHull(_points, hull, true, true);
int i, n; if( hull.depth() != CV_32F )
CvSeqReader reader;
CvContour contour_header;
CvSeqBlock block;
CvSeq* ptseq = (CvSeq*)array;
CvPoint2D32f out[3];
if( CV_IS_SEQ(ptseq) )
{
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;
}
else
{
ptseq = cvPointSeqFromMat( CV_SEQ_KIND_GENERIC, array, &contour_header, &block );
}
if( storage )
{
temp_storage = cvCreateChildMemStorage( storage );
}
else
{ {
temp_storage = cvCreateMemStorage(1 << 10); Mat temp;
hull.convertTo(temp, CV_32F);
hull = temp;
} }
ptseq = cvConvexHull2( ptseq, temp_storage, CV_CLOCKWISE, 1 ); int n = hull.checkVector(2);
n = ptseq->total; const Point2f* hpoints = (const Point2f*)hull.data;
_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 );
}
}
if( n > 2 ) 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.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.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); 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 ) ...@@ -421,10 +370,10 @@ cvMinAreaRect2( const CvArr* array, CvMemStorage* storage )
} }
else if( n == 2 ) else if( n == 2 )
{ {
box.center.x = (points[0].x + points[1].x)*0.5f; box.center.x = (hpoints[0].x + hpoints[1].x)*0.5f;
box.center.y = (points[0].y + points[1].y)*0.5f; box.center.y = (hpoints[0].y + hpoints[1].y)*0.5f;
double dx = points[1].x - points[0].x; double dx = hpoints[1].x - hpoints[0].x;
double dy = points[1].y - points[0].y; double dy = hpoints[1].y - hpoints[0].y;
box.size.width = (float)sqrt(dx*dx + dy*dy); box.size.width = (float)sqrt(dx*dx + dy*dy);
box.size.height = 0; box.size.height = 0;
box.angle = (float)atan2( dy, dx ); box.angle = (float)atan2( dy, dx );
...@@ -432,10 +381,21 @@ cvMinAreaRect2( const CvArr* array, CvMemStorage* storage ) ...@@ -432,10 +381,21 @@ cvMinAreaRect2( const CvArr* array, CvMemStorage* storage )
else else
{ {
if( n == 1 ) if( n == 1 )
box.center = points[0]; box.center = hpoints[0];
} }
box.angle = (float)(box.angle*180/CV_PI); box.angle = (float)(box.angle*180/CV_PI);
return box; return box;
} }
CV_IMPL CvBox2D
cvMinAreaRect2( const CvArr* array, CvMemStorage* storage )
{
cv::AutoBuffer<double> abuf;
cv::Mat points = cv::cvarrToMat(array, false, false, 0, &abuf);
cv::RotatedRect rr = cv::minAreaRect(points);
return (CvBox2D)rr;
}
...@@ -40,97 +40,25 @@ ...@@ -40,97 +40,25 @@
//M*/ //M*/
#include "precomp.hpp" #include "precomp.hpp"
/* calculates length of a curve (e.g. contour perimeter) */ namespace cv
CV_IMPL double
cvArcLength( const void *array, CvSlice slice, int is_closed )
{ {
double perimeter = 0;
int i, j = 0, count;
const int N = 16;
float buf[N];
CvMat buffer = cvMat( 1, N, CV_32F, buf );
CvSeqReader reader;
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" );
if( is_closed < 0 )
is_closed = CV_IS_SEQ_CLOSED( contour );
}
else
{
is_closed = is_closed > 0;
contour = cvPointSeqFromMat(
CV_SEQ_KIND_CURVE | (is_closed ? CV_SEQ_FLAG_CLOSED : 0),
array, &contour_header, &block );
}
if( contour->total > 1 )
{
int is_float = CV_SEQ_ELTYPE( contour ) == CV_32FC2;
cvStartReadSeq( contour, &reader, 0 );
cvSetSeqReaderPos( &reader, slice.start_index );
count = cvSliceLength( slice, contour );
count -= !is_closed && count == contour->total;
/* scroll the reader by 1 point */
reader.prev_elem = reader.ptr;
CV_NEXT_SEQ_ELEM( sizeof(CvPoint), reader );
for( i = 0; i < count; i++ )
{
float dx, dy;
if( !is_float )
{
CvPoint* pt = (CvPoint*)reader.ptr;
CvPoint* prev_pt = (CvPoint*)reader.prev_elem;
dx = (float)pt->x - (float)prev_pt->x;
dy = (float)pt->y - (float)prev_pt->y;
}
else
{
CvPoint2D32f* pt = (CvPoint2D32f*)reader.ptr;
CvPoint2D32f* prev_pt = (CvPoint2D32f*)reader.prev_elem;
dx = pt->x - prev_pt->x;
dy = pt->y - prev_pt->y;
}
reader.prev_elem = reader.ptr; static int intersectLines( double x1, double dx1, double y1, double dy1,
CV_NEXT_SEQ_ELEM( contour->elem_size, reader ); double x2, double dx2, double y2, double dy2, double *t2 )
// Bugfix by Axel at rubico.com 2010-03-22, affects closed slices only {
// wraparound not handled by CV_NEXT_SEQ_ELEM double d = dx1 * dy2 - dx2 * dy1;
if( is_closed && i == count - 2 ) int result = -1;
cvSetSeqReaderPos( &reader, slice.start_index );
buffer.data.fl[j] = dx * dx + dy * dy; if( d != 0 )
if( ++j == N || i == count - 1 )
{ {
buffer.cols = j; *t2 = ((x2 - x1) * dy1 - (y2 - y1) * dx1) / d;
cvPow( &buffer, &buffer, 0.5 ); result = 0;
for( ; j > 0; j-- )
perimeter += buffer.data.fl[j-1];
} }
} return result;
}
return perimeter;
} }
static bool findCircle( Point2f pt0, Point2f pt1, Point2f pt2,
static CvStatus Point2f* center, float* radius )
icvFindCircle( CvPoint2D32f pt0, CvPoint2D32f pt1,
CvPoint2D32f pt2, CvPoint2D32f * center, float *radius )
{ {
double x1 = (pt0.x + pt1.x) * 0.5; double x1 = (pt0.x + pt1.x) * 0.5;
double dy1 = pt0.x - pt1.x; double dy1 = pt0.x - pt1.x;
...@@ -142,26 +70,21 @@ icvFindCircle( CvPoint2D32f pt0, CvPoint2D32f pt1, ...@@ -142,26 +70,21 @@ icvFindCircle( CvPoint2D32f pt0, CvPoint2D32f pt1,
double dx2 = pt2.y - pt1.y; double dx2 = pt2.y - pt1.y;
double t = 0; double t = 0;
CvStatus result = CV_OK; if( intersectLines( x1, dx1, y1, dy1, x2, dx2, y2, dy2, &t ) >= 0 )
if( icvIntersectLines( x1, dx1, y1, dy1, x2, dx2, y2, dy2, &t ) >= 0 )
{ {
center->x = (float) (x2 + dx2 * t); center->x = (float) (x2 + dx2 * t);
center->y = (float) (y2 + dy2 * t); center->y = (float) (y2 + dy2 * t);
*radius = (float) icvDistanceL2_32f( *center, pt0 ); *radius = (float)norm(*center - pt0);
return true;
} }
else
{
center->x = center->y = 0.f; center->x = center->y = 0.f;
radius = 0; radius = 0;
result = CV_NOTDEFINED_ERR; return false;
}
return result;
} }
CV_INLINE double icvIsPtInCircle( CvPoint2D32f pt, CvPoint2D32f center, float radius ) static double pointInCircle( Point2f pt, Point2f center, float radius )
{ {
double dx = pt.x - center.x; double dx = pt.x - center.x;
double dy = pt.y - center.y; double dy = pt.y - center.y;
...@@ -169,18 +92,17 @@ CV_INLINE double icvIsPtInCircle( CvPoint2D32f pt, CvPoint2D32f center, float ra ...@@ -169,18 +92,17 @@ CV_INLINE double icvIsPtInCircle( CvPoint2D32f pt, CvPoint2D32f center, float ra
} }
static int static int findEnslosingCicle4pts_32f( Point2f* pts, Point2f& _center, float& _radius )
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 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 idxs[4] = { 0, 1, 2, 3 };
int i, j, k = 1, mi = 0; int i, j, k = 1, mi = 0;
float max_dist = 0; float max_dist = 0;
CvPoint2D32f center; Point2f center;
CvPoint2D32f min_center; Point2f min_center;
float radius, min_radius = FLT_MAX; float radius, min_radius = FLT_MAX;
CvPoint2D32f res_pts[4]; Point2f res_pts[4];
center = min_center = pts[0]; center = min_center = pts[0];
radius = 1.f; radius = 1.f;
...@@ -188,7 +110,7 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float ...@@ -188,7 +110,7 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float
for( i = 0; i < 4; i++ ) for( i = 0; i < 4; i++ )
for( j = i + 1; j < 4; j++ ) for( j = i + 1; j < 4; j++ )
{ {
float dist = icvDistanceL2_32f( pts[i], pts[j] ); float dist = norm(pts[i] - pts[j]);
if( max_dist < dist ) if( max_dist < dist )
{ {
...@@ -198,9 +120,8 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float ...@@ -198,9 +120,8 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float
} }
} }
if( max_dist == 0 ) if( max_dist > 0 )
goto function_exit; {
k = 2; k = 2;
for( i = 0; i < 4; i++ ) for( i = 0; i < 4; i++ )
{ {
...@@ -211,14 +132,13 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float ...@@ -211,14 +132,13 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float
idxs[k++] = i; idxs[k++] = i;
} }
center = cvPoint2D32f( (pts[idxs[0]].x + pts[idxs[1]].x)*0.5f, center = Point2f( (pts[idxs[0]].x + pts[idxs[1]].x)*0.5f, (pts[idxs[0]].y + pts[idxs[1]].y)*0.5f );
(pts[idxs[0]].y + pts[idxs[1]].y)*0.5f ); radius = (float)(norm(pts[idxs[0]] - center)*1.03);
radius = (float)(icvDistanceL2_32f( pts[idxs[0]], center )*1.03);
if( radius < 1.f ) if( radius < 1.f )
radius = 1.f; radius = 1.f;
if( icvIsPtInCircle( pts[idxs[2]], center, radius ) >= 0 && if( pointInCircle( pts[idxs[2]], center, radius ) >= 0 &&
icvIsPtInCircle( pts[idxs[3]], center, radius ) >= 0 ) pointInCircle( pts[idxs[3]], center, radius ) >= 0 )
{ {
k = 2; //rand()%2+2; k = 2; //rand()%2+2;
} }
...@@ -227,14 +147,14 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float ...@@ -227,14 +147,14 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float
mi = -1; mi = -1;
for( i = 0; i < 4; i++ ) for( i = 0; i < 4; i++ )
{ {
if( icvFindCircle( pts[shuffles[i][0]], pts[shuffles[i][1]], if( findCircle( pts[shuffles[i][0]], pts[shuffles[i][1]],
pts[shuffles[i][2]], &center, &radius ) >= 0 ) pts[shuffles[i][2]], &center, &radius ) >= 0 )
{ {
radius *= 1.03f; radius *= 1.03f;
if( radius < 2.f ) if( radius < 2.f )
radius = 2.f; radius = 2.f;
if( icvIsPtInCircle( pts[shuffles[i][3]], center, radius ) >= 0 && if( pointInCircle( pts[shuffles[i][3]], center, radius ) >= 0 &&
min_radius > radius ) min_radius > radius )
{ {
min_radius = radius; min_radius = radius;
...@@ -243,7 +163,7 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float ...@@ -243,7 +163,7 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float
} }
} }
} }
assert( mi >= 0 ); CV_Assert( mi >= 0 );
if( mi < 0 ) if( mi < 0 )
mi = 0; mi = 0;
k = 3; k = 3;
...@@ -252,11 +172,10 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float ...@@ -252,11 +172,10 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float
for( i = 0; i < 4; i++ ) for( i = 0; i < 4; i++ )
idxs[i] = shuffles[mi][i]; idxs[i] = shuffles[mi][i];
} }
}
function_exit: _center = center;
_radius = radius;
*_center = center;
*_radius = radius;
/* reorder output points */ /* reorder output points */
for( i = 0; i < 4; i++ ) for( i = 0; i < 4; i++ )
...@@ -265,159 +184,88 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float ...@@ -265,159 +184,88 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float
for( i = 0; i < 4; i++ ) for( i = 0; i < 4; i++ )
{ {
pts[i] = res_pts[i]; pts[i] = res_pts[i];
assert( icvIsPtInCircle( pts[i], center, radius ) >= 0 ); CV_Assert( pointInCircle( pts[i], center, radius ) >= 0 );
} }
return k; return k;
} }
}
CV_IMPL int void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radius )
cvMinEnclosingCircle( const void* array, CvPoint2D32f * _center, float *_radius )
{ {
const int max_iters = 100; int max_iters = 100;
const float eps = FLT_EPSILON*2; const float eps = FLT_EPSILON*2;
CvPoint2D32f center = { 0, 0 }; bool result = false;
float radius = 0; Mat points = _points.getMat();
int result = 0; int i, j, k, count = points.checkVector(2);
int depth = points.depth();
if( _center ) Point2f center;
_center->x = _center->y = 0.f; float radius = 0.f;
if( _radius ) CV_Assert(count >= 0 && (depth == CV_32F || depth == CV_32S));
*_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; _center.x = _center.y = 0.f;
is_float = CV_SEQ_ELTYPE(sequence) == CV_32FC2; _radius = 0.f;
if( !is_float ) if( count == 0 )
{ return;
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 ) bool is_float = depth == CV_32F;
pt_left = pt_ptr; const Point* ptsi = (const Point*)points.data;
if( pt.x > pt_right->x ) const Point2f* ptsf = (const Point2f*)points.data;
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 ); Point2f pt = is_float ? ptsf[0] : Point2f((float)ptsi[0].x,(float)ptsi[0].y);
pts[1] = cvPointTo32f( *pt_right ); Point2f pts[4] = {pt, pt, pt, pt};
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++ ) for(int i = 1; i < count; i++ )
{ {
CvPoint2D32f* pt_ptr = (CvPoint2D32f*)reader.ptr; Point2f pt = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
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; if( pt.x < pts[0].x )
pts[1] = *pt_right; pts[0] = pt;
pts[2] = *pt_top; if( pt.x > pts[1].x )
pts[3] = *pt_bottom; 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++ ) for( k = 0; k < max_iters; k++ )
{ {
double min_delta = 0, delta; double min_delta = 0, delta;
CvPoint2D32f ptfl, farAway = { 0, 0}; Point2f ptf, farAway(0,0);
/*only for first iteration because the alg is repared at the loop's foot*/ /*only for first iteration because the alg is repared at the loop's foot*/
if(k==0) if( k == 0 )
icvFindEnslosingCicle4pts_32f( pts, &center, &radius ); findEnslosingCicle4pts_32f( pts, center, radius );
cvStartReadSeq( sequence, &reader, 0 );
for(int i = 0; i < count; i++ ) for( 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; ptf = is_float ? ptsf[i] : Point2f((float)ptsi[i].x,(float)ptsi[i].y);
}
CV_NEXT_SEQ_ELEM( sequence->elem_size, reader );
delta = icvIsPtInCircle( ptfl, center, radius ); delta = pointInCircle( ptf, center, radius );
if( delta < min_delta ) if( delta < min_delta )
{ {
min_delta = delta; min_delta = delta;
farAway = ptfl; farAway = ptf;
} }
} }
result = min_delta >= 0; result = min_delta >= 0;
if( result ) if( result )
break; break;
CvPoint2D32f ptsCopy[4]; Point2f ptsCopy[4];
/* find good replacement partner for the point which is at most far away, // 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) */ // starting with the one that lays in the actual circle (i=3)
for(int i = 3; i >=0; i-- ) for( i = 3; i >= 0; i-- )
{ {
for(int j = 0; j < 4; j++ ) for( j = 0; j < 4; j++ )
{ ptsCopy[j] = i != j ? pts[j] : farAway;
ptsCopy[j]=(i != j)? pts[j]: farAway;
}
icvFindEnslosingCicle4pts_32f(ptsCopy, &center, &radius ); findEnslosingCicle4pts_32f( ptsCopy, center, radius );
if( icvIsPtInCircle( pts[i], center, radius )>=0){ // replaced one again in the new circle? if( pointInCircle( pts[i], center, radius ) >= 0)
{
// replaced one again in the new circle?
pts[i] = farAway; pts[i] = farAway;
break; break;
} }
...@@ -426,193 +274,523 @@ cvMinEnclosingCircle( const void* array, CvPoint2D32f * _center, float *_radius ...@@ -426,193 +274,523 @@ cvMinEnclosingCircle( const void* array, CvPoint2D32f * _center, float *_radius
if( !result ) if( !result )
{ {
cvStartReadSeq( sequence, &reader, 0 );
radius = 0.f; radius = 0.f;
for(int i = 0; i < count; i++ ) for(int i = 0; i < count; i++ )
{ {
CvPoint2D32f ptfl; Point2f ptf = is_float ? ptsf[i] : Point2f((float)ptsi[i].x,(float)ptsi[i].y);
float t, dx, dy; float dx = center.x - ptf.x, dy = center.y - ptf.y;
float t = dx*dx + dy*dy;
if( !is_float ) radius = MAX(radius, t);
{
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)); radius = (float)(sqrt(radius)*(1 + eps));
result = 1;
} }
*_center = center; _center = center;
*_radius = radius; _radius = radius;
return result;
} }
/* area of a whole sequence */ // calculates length of a curve (e.g. contour perimeter)
static CvStatus double cv::arcLength( InputArray _curve, bool is_closed )
icvContourArea( const CvSeq* contour, double *area )
{ {
if( contour->total ) Mat curve = _curve.getMat();
{ int count = curve.checkVector(2);
CvSeqReader reader; int depth = curve.depth();
int lpt = contour->total; CV_Assert( count >= 0 && (depth == CV_32F || depth == CV_32S));
double a00 = 0, xi_1, yi_1; double perimeter = 0;
int is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2;
cvStartReadSeq( contour, &reader, 0 ); int i, j = 0;
const int N = 16;
float buf[N];
if( !is_float ) if( count <= 1 )
{ return 0.;
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 ) bool is_float = depth == CV_32F;
{ int last = is_closed ? count-1 : 0;
double dxy, xi, yi; const Point* pti = (const Point*)curve.data;
const Point2f* ptf = (const Point2f*)curve.data;
if( !is_float ) Point2f prev = is_float ? ptf[last] : Point2f((float)pti[last].x,(float)pti[last].y);
{
xi = ((CvPoint*)(reader.ptr))->x; for( i = 0; i < count; i++ )
yi = ((CvPoint*)(reader.ptr))->y;
}
else
{ {
xi = ((CvPoint2D32f*)(reader.ptr))->x; Point2f p = is_float ? ptf[i] : Point2f((float)pti[i].x,(float)pti[i].y);
yi = ((CvPoint2D32f*)(reader.ptr))->y; float dx = p.x - prev.x, dy = p.y - prev.y;
} buf[j] = dx*dx + dy*dy;
CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
dxy = xi_1 * yi - xi * yi_1; if( ++j == N || i == count-1 )
a00 += dxy; {
xi_1 = xi; Mat bufmat(1, j, CV_32F, buf);
yi_1 = yi; sqrt(bufmat, bufmat);
for( ; j > 0; j-- )
perimeter += buf[j-1];
} }
prev = p;
*area = a00 * 0.5;
} }
else
*area = 0;
return CV_OK; return perimeter;
} }
// area of a whole sequence
/****************************************************************************************\ double cv::contourArea( InputArray _contour, bool oriented )
copy data from one buffer to other buffer
\****************************************************************************************/
static CvStatus
icvMemCopy( double **buf1, double **buf2, double **buf3, int *b_max )
{ {
int bb; Mat contour = _contour.getMat();
int npoints = contour.checkVector(2);
if( (*buf1 == NULL && *buf2 == NULL) || *buf3 == NULL ) int depth = contour.depth();
return CV_NULLPTR_ERR; CV_Assert(npoints >= 0 && (depth == CV_32F || depth == CV_32S));
bb = *b_max;
if( *buf2 == NULL )
{
*b_max = 2 * (*b_max);
*buf2 = (double *)cvAlloc( (*b_max) * sizeof( double ));
if( *buf2 == NULL ) if( npoints == 0 )
return CV_OUTOFMEM_ERR; return 0.;
memcpy( *buf2, *buf3, bb * sizeof( double )); 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);
*buf3 = *buf2; for( int i = 0; i < npoints; i++ )
cvFree( buf1 );
*buf1 = NULL;
}
else
{ {
*b_max = 2 * (*b_max); Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
*buf1 = (double *) cvAlloc( (*b_max) * sizeof( double )); a00 += (double)prev.x * p.y - (double)prev.y * p.x;
prev = p;
if( *buf1 == NULL ) }
return CV_OUTOFMEM_ERR;
memcpy( *buf1, *buf3, bb * sizeof( double )); a00 *= 0.5;
if( !oriented )
a00 = fabs(a00);
*buf3 = *buf1; return a00;
cvFree( buf2 );
*buf2 = NULL;
}
return CV_OK;
} }
/* area of a contour sector */ cv::RotatedRect cv::fitEllipse( InputArray _points )
static CvStatus icvContourSecArea( CvSeq * contour, CvSlice slice, double *area )
{ {
CvPoint pt; /* pointer to points */ Mat points = _points.getMat();
CvPoint pt_s, pt_e; /* first and last points */ int i, n = points.checkVector(2);
CvSeqReader reader; /* points reader of contour */ int depth = points.depth();
CV_Assert( n >= 0 && (depth == CV_32F || depth == CV_32S));
int p_max = 2, p_ind; RotatedRect box;
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( n < 5 )
CV_Error( CV_StsBadSize, "There should be at least 5 points to fit the ellipse" );
if( contour == NULL ) // New fitellipse algorithm, contributed by Dr. Daniel Weiss
return CV_NULLPTR_ERR; 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;
if( !CV_IS_SEQ_POINT_SET( contour )) AutoBuffer<double> _Ad(n*5), _bd(n);
return CV_BADFLAG_ERR; double *Ad = _Ad, *bd = _bd;
lpt = cvSliceLength( slice, contour ); // first fit for parameters A - E
/*if( n2 >= n1 ) Mat A( n, 5, CV_64F, Ad );
lpt = n2 - n1 + 1; Mat b( n, 1, CV_64F, bd );
else Mat x( 5, 1, CV_64F, gfp );
lpt = contour->total - n1 + n2 + 1;*/
if( contour->total && lpt > 2 ) for( i = 0; i < n; i++ )
{ {
a00 = x0 = y0 = xi_1 = yi_1 = 0; Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
sk1 = 0; c += p;
flag = 0; }
dxy = 0; c.x /= n;
p_are1 = (double *) cvAlloc( p_max * sizeof( double )); c.y /= n;
if( p_are1 == NULL ) for( i = 0; i < n; i++ )
return CV_OUTOFMEM_ERR; {
Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
p -= c;
p_are = p_are1; bd[i] = 10000.0; // 1.0?
p_are2 = NULL; 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;
}
cvStartReadSeq( contour, &reader, 0 ); solve(A, b, x, DECOMP_SVD);
cvSetSeqReaderPos( &reader, slice.start_index );
CV_READ_SEQ_ELEM( pt_s, reader ); // now use general-form parameters A - E to find the ellipse center:
p_ind = 0; // differentiate general form wrt x/y to get two equations for cx and cy
cvSetSeqReaderPos( &reader, slice.end_index ); 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<double> 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 ); CV_READ_SEQ_ELEM( pt_e, reader );
/* normal coefficients */ /* normal coefficients */
...@@ -717,20 +895,17 @@ static CvStatus icvContourSecArea( CvSeq * contour, CvSlice slice, double *area ...@@ -717,20 +895,17 @@ static CvStatus icvContourSecArea( CvSeq * contour, CvSlice slice, double *area
p_are[p_ind] = a00 / 2.; p_are[p_ind] = a00 / 2.;
p_ind++; p_ind++;
/* common area calculation */ // common area calculation
*area = 0; area = 0;
for( i = 0; i < p_ind; i++ ) for( i = 0; i < p_ind; i++ )
(*area) += fabs( p_are[i] ); area += fabs( p_are[i] );
if( p_are1 != NULL ) if( p_are1 != NULL )
cvFree( &p_are1 ); cvFree( &p_are1 );
else if( p_are2 != NULL ) else if( p_are2 != NULL )
cvFree( &p_are2 ); cvFree( &p_are2 );
return CV_OK; return area;
}
else
return CV_BADSIZE_ERR;
} }
...@@ -757,178 +932,115 @@ cvContourArea( const void *array, CvSlice slice, int oriented ) ...@@ -757,178 +932,115 @@ cvContourArea( const void *array, CvSlice slice, int oriented )
if( cvSliceLength( slice, contour ) == contour->total ) if( cvSliceLength( slice, contour ) == contour->total )
{ {
IPPI_CALL( icvContourArea( contour, &area )); cv::AutoBuffer<double> abuf;
cv::Mat points = cv::cvarrToMat(contour, false, false, 0, &abuf);
return cv::contourArea( points, oriented !=0 );
} }
else
{
if( CV_SEQ_ELTYPE( contour ) != CV_32SC2 ) if( CV_SEQ_ELTYPE( contour ) != CV_32SC2 )
CV_Error( CV_StsUnsupportedFormat, CV_Error( CV_StsUnsupportedFormat,
"Only curves with integer coordinates are supported in case of contour slice" ); "Only curves with integer coordinates are supported in case of contour slice" );
IPPI_CALL( icvContourSecArea( contour, slice, &area )); area = icvContourSecArea( contour, slice );
}
return oriented ? area : fabs(area); return oriented ? area : fabs(area);
} }
CV_IMPL CvBox2D /* calculates length of a curve (e.g. contour perimeter) */
cvFitEllipse2( const CvArr* array ) CV_IMPL double
cvArcLength( const void *array, CvSlice slice, int is_closed )
{ {
CvBox2D box; double perimeter = 0;
cv::AutoBuffer<double> Ad, bd;
memset( &box, 0, sizeof(box));
int i, j = 0, count;
const int N = 16;
float buf[N];
CvMat buffer = cvMat( 1, N, CV_32F, buf );
CvSeqReader reader;
CvContour contour_header; CvContour contour_header;
CvSeq* ptseq = 0; CvSeq* contour = 0;
CvSeqBlock block; CvSeqBlock block;
int n;
if( CV_IS_SEQ( array )) if( CV_IS_SEQ( array ))
{ {
ptseq = (CvSeq*)array; contour = (CvSeq*)array;
if( !CV_IS_SEQ_POINT_SET( ptseq )) if( !CV_IS_SEQ_POLYLINE( contour ))
CV_Error( CV_StsBadArg, "Unsupported sequence type" ); CV_Error( CV_StsBadArg, "Unsupported sequence type" );
if( is_closed < 0 )
is_closed = CV_IS_SEQ_CLOSED( contour );
} }
else else
{ {
ptseq = cvPointSeqFromMat(CV_SEQ_KIND_GENERIC, array, &contour_header, &block); is_closed = is_closed > 0;
} contour = cvPointSeqFromMat(
CV_SEQ_KIND_CURVE | (is_closed ? CV_SEQ_FLAG_CLOSED : 0),
n = ptseq->total; array, &contour_header, &block );
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++ ) if( contour->total > 1 )
{
CvPoint2D32f p;
if( is_float )
p = *(CvPoint2D32f*)(reader.ptr);
else
{ {
p.x = (float)((int*)reader.ptr)[0]; int is_float = CV_SEQ_ELTYPE( contour ) == CV_32FC2;
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? cvStartReadSeq( contour, &reader, 0 );
Ad[i*5] = -(double)p.x * p.x; // A - C signs inverted as proposed by APP cvSetSeqReaderPos( &reader, slice.start_index );
Ad[i*5 + 1] = -(double)p.y * p.y; count = cvSliceLength( slice, contour );
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 ); count -= !is_closed && count == contour->total;
// now use general-form parameters A - E to find the ellipse center: // scroll the reader by 1 point
// differentiate general form wrt x/y to get two equations for cx and cy reader.prev_elem = reader.ptr;
A = cvMat( 2, 2, CV_64F, Ad ); CV_NEXT_SEQ_ELEM( sizeof(CvPoint), reader );
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 for( i = 0; i < count; i++ )
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; float dx, dy;
if( is_float )
p = *(CvPoint2D32f*)(reader.ptr); if( !is_float )
else
{ {
p.x = (float)((int*)reader.ptr)[0]; CvPoint* pt = (CvPoint*)reader.ptr;
p.y = (float)((int*)reader.ptr)[1]; CvPoint* prev_pt = (CvPoint*)reader.prev_elem;
dx = (float)pt->x - (float)prev_pt->x;
dy = (float)pt->y - (float)prev_pt->y;
} }
CV_NEXT_SEQ_ELEM( sizeof(p), reader ); else
p.x -= c.x; {
p.y -= c.y; CvPoint2D32f* pt = (CvPoint2D32f*)reader.ptr;
bd[i] = 1.0; CvPoint2D32f* prev_pt = (CvPoint2D32f*)reader.prev_elem;
Ad[i * 3] = (p.x - rp[0]) * (p.x - rp[0]);
Ad[i * 3 + 1] = (p.y - rp[1]) * (p.y - rp[1]); dx = pt->x - prev_pt->x;
Ad[i * 3 + 2] = (p.x - rp[0]) * (p.y - rp[1]); dy = pt->y - prev_pt->y;
} }
cvSolve(&A, &b, &x, CV_SVD);
// store angle and radii reader.prev_elem = reader.ptr;
rp[4] = -0.5 * atan2(gfp[2], gfp[1] - gfp[0]); // convert from APP angle usage CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
t = sin(-2.0 * rp[4]); // Bugfix by Axel at rubico.com 2010-03-22, affects closed slices only
if( fabs(t) > fabs(gfp[2])*min_eps ) // wraparound not handled by CV_NEXT_SEQ_ELEM
t = gfp[2]/t; if( is_closed && i == count - 2 )
else cvSetSeqReaderPos( &reader, slice.start_index );
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; buffer.data.fl[j] = dx * dx + dy * dy;
box.center.y = (float)rp[1] + c.y; if( ++j == N || i == count - 1 )
box.size.width = (float)(rp[2]*2);
box.size.height = (float)(rp[3]*2);
if( box.size.width > box.size.height )
{ {
float tmp; buffer.cols = j;
CV_SWAP( box.size.width, box.size.height, tmp ); cvPow( &buffer, &buffer, 0.5 );
box.angle = (float)(90 + rp[4]*180/CV_PI); for( ; j > 0; j-- )
perimeter += buffer.data.fl[j-1];
}
}
} }
if( box.angle < -180 )
box.angle += 360;
if( box.angle > 360 )
box.angle -= 360;
return box; return perimeter;
} }
CV_IMPL CvBox2D
cvFitEllipse2( const CvArr* array )
{
cv::AutoBuffer<double> 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 */ /* Calculates bounding rectagnle of a point set or retrieves already calculated */
CV_IMPL CvRect CV_IMPL CvRect
cvBoundingRect( CvArr* array, int update ) cvBoundingRect( CvArr* array, int update )
...@@ -977,210 +1089,17 @@ cvBoundingRect( CvArr* array, int update ) ...@@ -977,210 +1089,17 @@ cvBoundingRect( CvArr* array, int update )
if( mat ) if( mat )
{ {
CvSize size = cvGetMatSize(mat); rect = cv::maskBoundingRect(cv::cvarrToMat(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;
} }
else if( ptseq->total ) else if( ptseq->total )
{ {
int is_float = CV_SEQ_ELTYPE(ptseq) == CV_32FC2; cv::AutoBuffer<double> abuf;
cvStartReadSeq( ptseq, &reader, 0 ); rect = cv::pointSetBoundingRect(cv::cvarrToMat(ptseq, false, false, 0, &abuf));
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;
} }
if( update ) if( update )
((CvContour*)ptseq)->rect = rect; ((CvContour*)ptseq)->rect = rect;
return rect; return rect;
} }
/* End of file. */ /* End of file. */
...@@ -13,7 +13,7 @@ static void help() ...@@ -13,7 +13,7 @@ static void help()
"Random points are generated and then enclosed.\n" "Random points are generated and then enclosed.\n"
"Call:\n" "Call:\n"
"./minarea\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*/ ) int main( int /*argc*/, char** /*argv*/ )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment