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,97 +92,38 @@ cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] ) ...@@ -92,97 +92,38 @@ 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) ||
(v0.x < ip.x && v.x < ip.x) ) (v0.x < ip.x && v.x < ip.x) )
{ {
if( ip.y == v.y && (ip.x == v.x || (ip.y == v0.y && 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)))) ) ((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 ) ...@@ -202,38 +143,32 @@ 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) ||
(v0.x < pt.x && v.x < pt.x) ) (v0.x < pt.x && v.x < pt.x) )
{ {
if( pt.y == v.y && (pt.x == v.x || (pt.y == v0.y && 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)))) ) ((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 ) ...@@ -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;
...@@ -292,8 +222,8 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist ) ...@@ -292,8 +222,8 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist )
} }
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) ||
(v0.x < pt.x && v.x < pt.x) ) (v0.x < pt.x && v.x < pt.x) )
continue; continue;
dist_num = dy1*dx - dx1*dy; dist_num = dy1*dx - dx1*dy;
...@@ -301,17 +231,25 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist ) ...@@ -301,17 +231,25 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist )
dist_num = -dist_num; dist_num = -dist_num;
counter += dist_num > 0; counter += dist_num > 0;
} }
result = sqrt(min_dist_num/min_dist_denom); result = sqrt(min_dist_num/min_dist_denom);
if( counter % 2 == 0 ) if( counter % 2 == 0 )
result = -result; result = -result;
} }
} }
return result; return result;
} }
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,159 +40,122 @@ ...@@ -40,159 +40,122 @@
//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 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] ); ama = 1. / (sma * log10( ama ));
double amb = fabs( mb[i] ); amb = 1. / (smb * log10( amb ));
result += fabs( -ama + amb );
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 );
}
} }
break;
} }
break;
case 2: 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] ); ama = sma * log10( ama );
double amb = fabs( mb[i] ); amb = smb * log10( amb );
result += fabs( -ama + amb );
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 );
}
} }
break;
} }
break;
case 3: 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] ); ama = sma * log10( ama );
double amb = fabs( mb[i] ); amb = smb * log10( amb );
mmm = fabs( (ama - amb) / ama );
if( ma[i] > 0 ) if( result < mmm )
sma = 1; result = mmm;
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;
}
} }
break;
} }
break;
default: default:
CV_Error( CV_StsBadArg, "Unknown comparison method" ); CV_Error( CV_StsBadArg, "Unknown comparison method" );
} }
return result; return result;
} }
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
{ {
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++ )
{
double dx, dy;
if( pt0.x < left_x ) struct MinAreaState
left_x = pt0.x, left = i; {
int bottom;
int left;
float height;
float width;
float base_a;
float base_b;
};
enum { CALIPERS_MAXHEIGHT=0, CALIPERS_MINAREARECT=1, CALIPERS_MAXDIST=2 };
/*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*/
/* we will use usual cartesian coordinates */
static void rotatingCalipers( const Point2f* points, int n, int mode, float* out )
{
float minarea = FLT_MAX;
float max_dist = 0;
char buffer[32] = {};
int i, k;
AutoBuffer<float> 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;
if( pt0.x > right_x ) for( i = 0; i < n; i++ )
right_x = pt0.x, right = i; {
double dx, dy;
if( pt0.y > top_y ) if( pt0.x < left_x )
top_y = pt0.y, top = i; left_x = pt0.x, left = i;
if( pt0.y < bottom_y ) if( pt0.x > right_x )
bottom_y = pt0.y, bottom = i; right_x = pt0.x, right = i;
CvPoint2D32f pt = points[(i+1) & (i+1 < n ? -1 : 0)]; if( pt0.y > top_y )
top_y = pt0.y, top = i;
dx = pt.x - pt0.x; if( pt0.y < bottom_y )
dy = pt.y - pt0.y; bottom_y = pt0.y, bottom = i;
vect[i].x = (float)dx; Point2f pt = points[(i+1) & (i+1 < n ? -1 : 0)];
vect[i].y = (float)dy;
inv_vect_length[i] = (float)(1./sqrt(dx*dx + dy*dy));
pt0 = pt; dx = pt.x - pt0.x;
} dy = pt.y - pt0.y;
//cvbInvSqrt( inv_vect_length, inv_vect_length, n ); vect[i].x = (float)dx;
vect[i].y = (float)dy;
inv_vect_length[i] = (float)(1./sqrt(dx*dx + dy*dy));
/* find convex hull orientation */ pt0 = pt;
{ }
double ax = vect[n-1].x;
double ay = vect[n-1].y;
for( i = 0; i < n; i++ ) // find convex hull orientation
{ {
double bx = vect[i].x; double ax = vect[n-1].x;
double by = vect[i].y; double ay = vect[n-1].y;
double convexity = ax * by - ay * bx;
if( convexity != 0 ) for( i = 0; i < n; i++ )
{ {
orientation = (convexity > 0) ? 1.f : (-1.f); double bx = vect[i].x;
break; 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;
} }
ax = bx; CV_Assert( orientation != 0 );
ay = by;
} }
assert( orientation != 0 ); base_a = orientation;
}
base_a = orientation; /*****************************************************************************************/
/* init calipers position */
/*****************************************************************************************/ seq[0] = bottom;
/* init calipers position */ seq[1] = right;
seq[0] = bottom; seq[2] = top;
seq[1] = right; seq[3] = left;
seq[2] = top; /*****************************************************************************************/
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 */
for( k = 0; k < n; k++ )
/* 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 /* sinus of minimal angle */
int pindex = seq[main_element]; /*float sinus;*/
float lead_x = vect[pindex].x*inv_vect_length[pindex];
float lead_y = vect[pindex].y*inv_vect_length[pindex]; /* compute cosine of angle between calipers side and polygon edge */
switch( main_element ) /* 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*/
{ {
case 0: //get next base
base_a = lead_x; int pindex = seq[main_element];
base_b = lead_y; float lead_x = vect[pindex].x*inv_vect_length[pindex];
break; float lead_y = vect[pindex].y*inv_vect_length[pindex];
case 1: switch( main_element )
base_a = lead_y; {
base_b = -lead_x; case 0:
break; base_a = lead_x;
case 2: base_b = lead_y;
base_a = -lead_x; break;
base_b = -lead_y; case 1:
break; base_a = lead_y;
case 3: base_b = -lead_x;
base_a = -lead_y; break;
base_b = lead_x; case 2:
break; base_a = -lead_x;
default: assert(0); 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 */
/* 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)
{
case CV_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 ) switch (mode)
max_dist = dist;
break;
}
case CV_CALIPERS_MINAREARECT:
/* find area of rectangle */
{ {
float height; case CALIPERS_MAXHEIGHT:
float area; {
/* now main element lies on edge alligned to calipers side */
/* find vector left-right */ /* find opposite element i.e. transform */
float dx = points[seq[1]].x - points[seq[3]].x; /* 0->2, 1->3, 2->0, 3->1 */
float dy = points[seq[1]].y - points[seq[3]].y; int opposite_el = main_element ^ 2;
/* dotproduct */ float dx = points[seq[opposite_el]].x - points[seq[main_element]].x;
float width = dx * base_a + dy * base_b; float dy = points[seq[opposite_el]].y - points[seq[main_element]].y;
float dist;
/* find vector left-right */ if( main_element & 1 )
dx = points[seq[2]].x - points[seq[0]].x; dist = (float)fabs(dx * base_a + dy * base_b);
dy = points[seq[2]].y - points[seq[0]].y; else
dist = (float)fabs(dx * (-base_b) + dy * base_a);
/* dotproduct */ if( dist > max_dist )
height = -dx * base_b + dy * base_a; max_dist = dist;
area = width * height; break;
if( area <= minarea ) }
case CALIPERS_MINAREARECT:
/* find area of rectangle */
{ {
float *buf = (float *) buffer; float height;
float area;
minarea = area;
/* leftist point */ /* find vector left-right */
((int *) buf)[0] = seq[3]; float dx = points[seq[1]].x - points[seq[3]].x;
buf[1] = base_a; float dy = points[seq[1]].y - points[seq[3]].y;
buf[2] = width;
buf[3] = base_b; /* dotproduct */
buf[4] = height; float width = dx * base_a + dy * base_b;
/* bottom point */
((int *) buf)[5] = seq[0]; /* find vector left-right */
buf[6] = area; 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;
} }
break; } /*switch */
} } /* for */
} /*switch */
} /* for */
switch (mode) switch (mode)
{
case CV_CALIPERS_MINAREARECT:
{ {
float *buf = (float *) buffer; case CALIPERS_MINAREARECT:
{
float A1 = buf[1]; float *buf = (float *) buffer;
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 A1 = buf[1];
float C2 = A2 * points[((int *) buf)[5]].x + points[((int *) buf)[5]].y * B2; float B1 = buf[3];
float idet = 1.f / (A1 * B2 - A2 * B1); float A2 = -buf[3];
float B2 = buf[1];
float px = (C1 * B2 - C2 * B1) * idet; float C1 = A1 * points[((int *) buf)[0]].x + points[((int *) buf)[0]].y * B1;
float py = (A1 * C2 - A2 * C1) * idet; float C2 = A2 * points[((int *) buf)[5]].x + points[((int *) buf)[5]].y * B2;
out[0] = px; float idet = 1.f / (A1 * B2 - A2 * B1);
out[1] = py;
out[2] = A1 * buf[2]; float px = (C1 * B2 - C2 * B1) * idet;
out[3] = B1 * buf[2]; float py = (A1 * C2 - A2 * C1) * idet;
out[4] = A2 * buf[4]; out[0] = px;
out[5] = B2 * buf[4]; out[1] = py;
}
break; out[2] = A1 * buf[2];
case CV_CALIPERS_MAXHEIGHT: out[3] = B1 * buf[2];
{
out[0] = max_dist; out[4] = A2 * buf[4];
out[5] = B2 * buf[4];
}
break;
case CALIPERS_MAXHEIGHT:
{
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;
convexHull(_points, hull, true, true);
memset(&box, 0, sizeof(box));
if( hull.depth() != CV_32F )
int i, n;
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; static int intersectLines( double x1, double dx1, double y1, double dy1,
const int N = 16; double x2, double dx2, double y2, double dy2, double *t2 )
float buf[N]; {
CvMat buffer = cvMat( 1, N, CV_32F, buf ); double d = dx1 * dy2 - dx2 * dy1;
CvSeqReader reader; int result = -1;
CvContour contour_header;
CvSeq* contour = 0;
CvSeqBlock block;
if( CV_IS_SEQ( array )) if( d != 0 )
{
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; *t2 = ((x2 - x1) * dy1 - (y2 - y1) * dx1) / d;
contour = cvPointSeqFromMat( result = 0;
CV_SEQ_KIND_CURVE | (is_closed ? CV_SEQ_FLAG_CLOSED : 0),
array, &contour_header, &block );
} }
return result;
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;
CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
// Bugfix by Axel at rubico.com 2010-03-22, affects closed slices only
// wraparound not handled by CV_NEXT_SEQ_ELEM
if( is_closed && i == count - 2 )
cvSetSeqReaderPos( &reader, slice.start_index );
buffer.data.fl[j] = dx * dx + dy * dy;
if( ++j == N || i == count - 1 )
{
buffer.cols = j;
cvPow( &buffer, &buffer, 0.5 );
for( ; j > 0; j-- )
perimeter += buffer.data.fl[j-1];
}
}
}
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;
radius = 0;
result = CV_NOTDEFINED_ERR;
} }
return result; center->x = center->y = 0.f;
radius = 0;
return false;
} }
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,65 +120,62 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float ...@@ -198,65 +120,62 @@ icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float
} }
} }
if( max_dist == 0 ) if( max_dist > 0 )
goto function_exit;
k = 2;
for( i = 0; i < 4; i++ )
{ {
for( j = 0; j < k; j++ ) k = 2;
if( i == idxs[j] ) for( i = 0; i < 4; i++ )
break; {
if( j == k ) for( j = 0; j < k; j++ )
idxs[k++] = i; if( i == idxs[j] )
} break;
if( j == k )
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;
}
else
{
mi = -1;
for( i = 0; i < 4; i++ )
{ {
if( icvFindCircle( pts[shuffles[i][0]], pts[shuffles[i][1]], k = 2; //rand()%2+2;
pts[shuffles[i][2]], &center, &radius ) >= 0 ) }
else
{
mi = -1;
for( i = 0; i < 4; i++ )
{ {
radius *= 1.03f; if( findCircle( pts[shuffles[i][0]], pts[shuffles[i][1]],
if( radius < 2.f ) pts[shuffles[i][2]], &center, &radius ) >= 0 )
radius = 2.f;
if( icvIsPtInCircle( pts[shuffles[i][3]], center, radius ) >= 0 &&
min_radius > radius )
{ {
min_radius = radius; radius *= 1.03f;
min_center = center; if( radius < 2.f )
mi = i; 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];
} }
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;
*_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();
Point2f center;
float radius = 0.f;
CV_Assert(count >= 0 && (depth == CV_32F || depth == CV_32S));
if( _center ) _center.x = _center.y = 0.f;
_center->x = _center->y = 0.f; _radius = 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 ) if( count == 0 )
CV_Error( CV_StsBadSize, "" ); return;
cvStartReadSeq( sequence, &reader, 0 ); bool is_float = depth == CV_32F;
const Point* ptsi = (const Point*)points.data;
const Point2f* ptsf = (const Point2f*)points.data;
count = sequence->total; Point2f pt = is_float ? ptsf[0] : Point2f((float)ptsi[0].x,(float)ptsi[0].y);
is_float = CV_SEQ_ELTYPE(sequence) == CV_32FC2; Point2f pts[4] = {pt, pt, pt, pt};
if( !is_float ) for(int i = 1; i < count; i++ )
{ {
CvPoint *pt_left, *pt_right, *pt_top, *pt_bottom; Point2f pt = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
CvPoint pt;
pt_left = pt_right = pt_top = pt_bottom = (CvPoint *)(reader.ptr); if( pt.x < pts[0].x )
CV_READ_SEQ_ELEM( pt, reader ); pts[0] = pt;
if( pt.x > pts[1].x )
for(int i = 1; i < count; i++ ) pts[1] = pt;
{ if( pt.y < pts[2].y )
CvPoint* pt_ptr = (CvPoint*)reader.ptr; pts[2] = pt;
CV_READ_SEQ_ELEM( pt, reader ); if( pt.y > pts[3].y )
pts[3] = pt;
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++ ) 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 ) ptf = is_float ? ptsf[i] : Point2f((float)ptsi[i].x,(float)ptsi[i].y);
{
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 ); 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,121 +274,462 @@ cvMinEnclosingCircle( const void* array, CvPoint2D32f * _center, float *_radius ...@@ -426,121 +274,462 @@ 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;
radius = MAX(radius, t);
}
if( !is_float ) radius = (float)(sqrt(radius)*(1 + eps));
{ }
ptfl.x = (float)((CvPoint*)reader.ptr)->x;
ptfl.y = (float)((CvPoint*)reader.ptr)->y; _center = center;
} _radius = radius;
else }
{
ptfl = *(CvPoint2D32f*)reader.ptr;
} // 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;
CV_NEXT_SEQ_ELEM( sequence->elem_size, reader ); int i, j = 0;
dx = center.x - ptfl.x; const int N = 16;
dy = center.y - ptfl.y; float buf[N];
t = dx*dx + dy*dy;
radius = MAX(radius,t); 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;
}
radius = (float)(sqrt(radius)*(1 + eps)); return perimeter;
result = 1; }
// 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;
} }
*_center = center; a00 *= 0.5;
*_radius = radius; if( !oriented )
a00 = fabs(a00);
return result; return a00;
} }
/* area of a whole sequence */ cv::RotatedRect cv::fitEllipse( InputArray _points )
static CvStatus
icvContourArea( const CvSeq* contour, double *area )
{ {
if( contour->total ) 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<double> _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++ )
{ {
CvSeqReader reader; Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
int lpt = contour->total; p -= c;
double a00 = 0, xi_1, yi_1;
int is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2;
cvStartReadSeq( contour, &reader, 0 ); 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 ) if( !is_float )
{ {
xi_1 = ((CvPoint*)(reader.ptr))->x; __m128i minval, maxval;
yi_1 = ((CvPoint*)(reader.ptr))->y; 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 else
{ {
xi_1 = ((CvPoint2D32f*)(reader.ptr))->x; __m128 minvalf, maxvalf, z = _mm_setzero_ps(), ptXY = _mm_setzero_ps();
yi_1 = ((CvPoint2D32f*)(reader.ptr))->y; minvalf = maxvalf = _mm_loadl_pi(z, (const __m64*)(&pt));
}
CV_NEXT_SEQ_ELEM( contour->elem_size, reader ); 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);
}
while( lpt-- > 0 ) 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 )
{ {
double dxy, xi, yi; xmin = xmax = pt.x;
ymin = ymax = pt.y;
if( !is_float ) for( i = 1; i < npoints; i++ )
{ {
xi = ((CvPoint*)(reader.ptr))->x; pt = pts[i];
yi = ((CvPoint*)(reader.ptr))->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;
} }
else }
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++ )
{ {
xi = ((CvPoint2D32f*)(reader.ptr))->x; pt = pts[i];
yi = ((CvPoint2D32f*)(reader.ptr))->y; 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;
} }
CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
dxy = xi_1 * yi - xi * yi_1; v.i = CV_TOGGLE_FLT(xmin); xmin = cvFloor(v.f);
a00 += dxy; v.i = CV_TOGGLE_FLT(ymin); ymin = cvFloor(v.f);
xi_1 = xi; // because right and bottom sides of the bounding rectangle are not inclusive
yi_1 = yi; // (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);
} }
*area = a00 * 0.5;
} }
else
*area = 0; return Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
}
return CV_OK; 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);
}
copy data from one buffer to other buffer ////////////////////////////////////////////// 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 CvStatus static void
icvMemCopy( double **buf1, double **buf2, double **buf3, int *b_max ) icvMemCopy( double **buf1, double **buf2, double **buf3, int *b_max )
{ {
int bb; CV_Assert( (*buf1 != NULL || *buf2 != NULL) && *buf3 != NULL );
if( (*buf1 == NULL && *buf2 == NULL) || *buf3 == NULL )
return CV_NULLPTR_ERR;
bb = *b_max; int bb = *b_max;
if( *buf2 == NULL ) if( *buf2 == NULL )
{ {
*b_max = 2 * (*b_max); *b_max = 2 * (*b_max);
*buf2 = (double *)cvAlloc( (*b_max) * sizeof( double )); *buf2 = (double *)cvAlloc( (*b_max) * sizeof( double ));
if( *buf2 == NULL )
return CV_OUTOFMEM_ERR;
memcpy( *buf2, *buf3, bb * sizeof( double )); memcpy( *buf2, *buf3, bb * sizeof( double ));
*buf3 = *buf2; *buf3 = *buf2;
...@@ -552,21 +741,17 @@ icvMemCopy( double **buf1, double **buf2, double **buf3, int *b_max ) ...@@ -552,21 +741,17 @@ icvMemCopy( double **buf1, double **buf2, double **buf3, int *b_max )
*b_max = 2 * (*b_max); *b_max = 2 * (*b_max);
*buf1 = (double *) cvAlloc( (*b_max) * sizeof( double )); *buf1 = (double *) cvAlloc( (*b_max) * sizeof( double ));
if( *buf1 == NULL )
return CV_OUTOFMEM_ERR;
memcpy( *buf1, *buf3, bb * sizeof( double )); memcpy( *buf1, *buf3, bb * sizeof( double ));
*buf3 = *buf1; *buf3 = *buf1;
cvFree( buf2 ); cvFree( buf2 );
*buf2 = NULL; *buf2 = NULL;
} }
return CV_OK;
} }
/* area of a contour sector */ /* area of a contour sector */
static CvStatus icvContourSecArea( CvSeq * contour, CvSlice slice, double *area ) static double icvContourSecArea( CvSeq * contour, CvSlice slice )
{ {
CvPoint pt; /* pointer to points */ CvPoint pt; /* pointer to points */
CvPoint pt_s, pt_e; /* first and last points */ CvPoint pt_s, pt_e; /* first and last points */
...@@ -579,14 +764,9 @@ static CvStatus icvContourSecArea( CvSeq * contour, CvSlice slice, double *area ...@@ -579,14 +764,9 @@ static CvStatus icvContourSecArea( CvSeq * contour, CvSlice slice, double *area
double x_s, y_s, nx, ny, dx, dy, du, dv; double x_s, y_s, nx, ny, dx, dy, du, dv;
double eps = 1.e-5; double eps = 1.e-5;
double *p_are1, *p_are2, *p_are; double *p_are1, *p_are2, *p_are;
double area = 0;
assert( contour != NULL ); CV_Assert( contour != NULL && CV_IS_SEQ_POINT_SET( contour ));
if( contour == NULL )
return CV_NULLPTR_ERR;
if( !CV_IS_SEQ_POINT_SET( contour ))
return CV_BADFLAG_ERR;
lpt = cvSliceLength( slice, contour ); lpt = cvSliceLength( slice, contour );
/*if( n2 >= n1 ) /*if( n2 >= n1 )
...@@ -594,143 +774,138 @@ static CvStatus icvContourSecArea( CvSeq * contour, CvSlice slice, double *area ...@@ -594,143 +774,138 @@ static CvStatus icvContourSecArea( CvSeq * contour, CvSlice slice, double *area
else else
lpt = contour->total - n1 + n2 + 1;*/ lpt = contour->total - n1 + n2 + 1;*/
if( contour->total && lpt > 2 ) 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 ));
if( p_are1 == NULL ) a00 = x0 = y0 = xi_1 = yi_1 = 0;
return CV_OUTOFMEM_ERR; sk1 = 0;
flag = 0;
dxy = 0;
p_are1 = (double *) cvAlloc( p_max * sizeof( double ));
p_are = p_are1; p_are = p_are1;
p_are2 = NULL; p_are2 = NULL;
cvStartReadSeq( contour, &reader, 0 ); cvStartReadSeq( contour, &reader, 0 );
cvSetSeqReaderPos( &reader, slice.start_index ); cvSetSeqReaderPos( &reader, slice.start_index );
CV_READ_SEQ_ELEM( pt_s, reader ); CV_READ_SEQ_ELEM( pt_s, reader );
p_ind = 0; p_ind = 0;
cvSetSeqReaderPos( &reader, slice.end_index ); cvSetSeqReaderPos( &reader, slice.end_index );
CV_READ_SEQ_ELEM( pt_e, reader ); CV_READ_SEQ_ELEM( pt_e, reader );
/* normal coefficients */ /* normal coefficients */
nx = pt_s.y - pt_e.y; nx = pt_s.y - pt_e.y;
ny = pt_e.x - pt_s.x; ny = pt_e.x - pt_s.x;
cvSetSeqReaderPos( &reader, slice.start_index ); cvSetSeqReaderPos( &reader, slice.start_index );
while( lpt-- > 0 ) while( lpt-- > 0 )
{ {
CV_READ_SEQ_ELEM( pt, reader ); CV_READ_SEQ_ELEM( pt, reader );
if( flag == 0 ) if( flag == 0 )
{ {
xi_1 = (double) pt.x; xi_1 = (double) pt.x;
yi_1 = (double) pt.y; yi_1 = (double) pt.y;
x0 = xi_1; x0 = xi_1;
y0 = yi_1; y0 = yi_1;
sk1 = 0; sk1 = 0;
flag = 1; flag = 1;
} }
else else
{ {
xi = (double) pt.x; xi = (double) pt.x;
yi = (double) pt.y; yi = (double) pt.y;
/**************** edges intersection examination **************************/ /**************** edges intersection examination **************************/
sk = nx * (xi - pt_s.x) + ny * (yi - pt_s.y); sk = nx * (xi - pt_s.x) + ny * (yi - pt_s.y);
if( (fabs( sk ) < eps && lpt > 0) || sk * sk1 < -eps ) 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
{ {
if( fabs( sk ) < eps ) /* 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 )
{ {
dxy = xi_1 * yi - xi * yi_1; x_s = pt_s.x + t * dx;
a00 = a00 + dxy; y_s = pt_s.y + t * dy;
dxy = xi * y0 - x0 * yi; dxy = xi_1 * y_s - x_s * yi_1;
a00 = a00 + dxy; a00 += dxy;
dxy = x_s * y0 - x0 * y_s;
a00 += dxy;
if( p_ind >= p_max ) if( p_ind >= p_max )
icvMemCopy( &p_are1, &p_are2, &p_are, &p_max ); icvMemCopy( &p_are1, &p_are2, &p_are, &p_max );
p_are[p_ind] = a00 / 2.; p_are[p_ind] = a00 / 2.;
p_ind++; p_ind++;
a00 = 0; a00 = 0;
sk1 = 0; sk1 = 0;
x0 = xi; x0 = x_s;
y0 = yi; y0 = y_s;
dxy = 0; dxy = x_s * yi - xi * y_s;
}
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; else
dxy = xi_1 * yi - xi * yi_1;
a00 += dxy; a00 += dxy;
xi_1 = xi; xi_1 = xi;
yi_1 = yi; yi_1 = yi;
sk1 = sk; sk1 = sk;
}
} }
}
xi = x0; xi = x0;
yi = y0; yi = y0;
dxy = xi_1 * yi - xi * yi_1; dxy = xi_1 * yi - xi * yi_1;
a00 += dxy; a00 += dxy;
if( p_ind >= p_max ) if( p_ind >= p_max )
icvMemCopy( &p_are1, &p_are2, &p_are, &p_max ); icvMemCopy( &p_are1, &p_are2, &p_are, &p_max );
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);
else 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" );
IPPI_CALL( icvContourSecArea( contour, slice, &area ));
} }
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); 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),
array, &contour_header, &block );
} }
n = ptseq->total; if( contour->total > 1 )
if( n < 5 ) {
CV_Error( CV_StsBadSize, "Number of points should be >= 5" ); int is_float = CV_SEQ_ELTYPE( contour ) == CV_32FC2;
/*
* 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); cvStartReadSeq( contour, &reader, 0 );
bd.allocate(n); cvSetSeqReaderPos( &reader, slice.start_index );
count = cvSliceLength( slice, contour );
// first fit for parameters A - E count -= !is_closed && count == contour->total;
A = cvMat( n, 5, CV_64F, Ad );
b = cvMat( n, 1, CV_64F, bd );
x = cvMat( 5, 1, CV_64F, gfp );
cvStartReadSeq( ptseq, &reader ); // scroll the reader by 1 point
is_float = CV_SEQ_ELTYPE(ptseq) == CV_32FC2; reader.prev_elem = reader.ptr;
CV_NEXT_SEQ_ELEM( sizeof(CvPoint), reader );
for( i = 0; i < n; i++ ) for( i = 0; i < count; i++ )
{
CvPoint2D32f p;
if( is_float )
p = *(CvPoint2D32f*)(reader.ptr);
else
{ {
p.x = (float)((int*)reader.ptr)[0]; float dx, dy;
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( !is_float )
{ {
CvPoint2D32f p; CvPoint* pt = (CvPoint*)reader.ptr;
if( is_float ) CvPoint* prev_pt = (CvPoint*)reader.prev_elem;
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? dx = (float)pt->x - (float)prev_pt->x;
Ad[i*5] = -(double)p.x * p.x; // A - C signs inverted as proposed by APP dy = (float)pt->y - (float)prev_pt->y;
Ad[i*5 + 1] = -(double)p.y * p.y; }
Ad[i*5 + 2] = -(double)p.x * p.y; else
Ad[i*5 + 3] = p.x; {
Ad[i*5 + 4] = p.y; CvPoint2D32f* pt = (CvPoint2D32f*)reader.ptr;
} CvPoint2D32f* prev_pt = (CvPoint2D32f*)reader.prev_elem;
cvSolve( &A, &b, &x, CV_SVD ); dx = pt->x - prev_pt->x;
dy = pt->y - prev_pt->y;
}
// now use general-form parameters A - E to find the ellipse center: reader.prev_elem = reader.ptr;
// differentiate general form wrt x/y to get two equations for cx and cy CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
A = cvMat( 2, 2, CV_64F, Ad ); // Bugfix by Axel at rubico.com 2010-03-22, affects closed slices only
b = cvMat( 2, 1, CV_64F, bd ); // wraparound not handled by CV_NEXT_SEQ_ELEM
x = cvMat( 2, 1, CV_64F, rp ); if( is_closed && i == count - 2 )
Ad[0] = 2 * gfp[0]; cvSetSeqReaderPos( &reader, slice.start_index );
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 buffer.data.fl[j] = dx * dx + dy * dy;
A = cvMat( n, 3, CV_64F, Ad ); if( ++j == N || i == count - 1 )
b = cvMat( n, 1, CV_64F, bd ); {
x = cvMat( 3, 1, CV_64F, gfp ); buffer.cols = j;
for( i = 0; i < n; i++ ) cvPow( &buffer, &buffer, 0.5 );
{ for( ; j > 0; j-- )
CvPoint2D32f p; perimeter += buffer.data.fl[j-1];
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);
return perimeter;
// 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_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