converted few more comp. geometry functions to C++

This commit is contained in:
Vadim Pisarevsky 2013-01-22 16:54:31 +04:00
parent c2241dccc5
commit dc4d0398f3
7 changed files with 1381 additions and 1692 deletions

View File

@ -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 );

View File

@ -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. */

View File

@ -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 )
} }
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 )
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 )
} }
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;
@ -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

View File

@ -40,153 +40,105 @@
//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" );
} }
@ -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. */

View File

@ -1,418 +1,367 @@
/*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 struct MinAreaState
#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; int bottom;
int left;
float height;
float width;
float base_a;
float base_b;
};
if( pt0.x < left_x ) enum { CALIPERS_MAXHEIGHT=0, CALIPERS_MINAREARECT=1, CALIPERS_MAXDIST=2 };
left_x = pt0.x, left = i;
if( pt0.x > right_x ) /*F///////////////////////////////////////////////////////////////////////////////////////
right_x = pt0.x, right = i; // Name: rotatingCalipers
// Purpose:
// Rotating calipers algorithm with some applications
//
// Context:
// Parameters:
// points - convex hull vertices ( any orientation )
// n - number of vertices
// mode - concrete application of algorithm
// can be CV_CALIPERS_MAXDIST or
// CV_CALIPERS_MINAREARECT
// left, bottom, right, top - indexes of extremal points
// out - output info.
// In case CV_CALIPERS_MAXDIST it points to float value -
// maximal height of polygon.
// In case CV_CALIPERS_MINAREARECT
// ((CvPoint2D32f*)out)[0] - corner
// ((CvPoint2D32f*)out)[1] - vector1
// ((CvPoint2D32f*)out)[0] - corner2
//
// ^
// |
// vector2 |
// |
// |____________\
// corner /
// vector1
//
// Returns:
// Notes:
//F*/
if( pt0.y > top_y ) /* we will use usual cartesian coordinates */
top_y = pt0.y, top = i; static void rotatingCalipers( const Point2f* points, int n, int mode, float* out )
if( pt0.y < bottom_y )
bottom_y = pt0.y, bottom = i;
CvPoint2D32f pt = points[(i+1) & (i+1 < n ? -1 : 0)];
dx = pt.x - pt0.x;
dy = pt.y - pt0.y;
vect[i].x = (float)dx;
vect[i].y = (float)dy;
inv_vect_length[i] = (float)(1./sqrt(dx*dx + dy*dy));
pt0 = pt;
}
//cvbInvSqrt( inv_vect_length, inv_vect_length, n );
/* find convex hull orientation */
{ {
double ax = vect[n-1].x; float minarea = FLT_MAX;
double ay = vect[n-1].y; 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;
for( i = 0; i < n; i++ ) for( i = 0; i < n; i++ )
{ {
double bx = vect[i].x; double dx, dy;
double by = vect[i].y;
double convexity = ax * by - ay * bx; if( pt0.x < left_x )
left_x = pt0.x, left = i;
if( convexity != 0 ) if( pt0.x > right_x )
{ right_x = pt0.x, right = i;
orientation = (convexity > 0) ? 1.f : (-1.f);
break; if( pt0.y > top_y )
} top_y = pt0.y, top = i;
ax = bx;
ay = by; if( pt0.y < bottom_y )
bottom_y = pt0.y, bottom = i;
Point2f pt = points[(i+1) & (i+1 < n ? -1 : 0)];
dx = pt.x - pt0.x;
dy = pt.y - pt0.y;
vect[i].x = (float)dx;
vect[i].y = (float)dy;
inv_vect_length[i] = (float)(1./sqrt(dx*dx + dy*dy));
pt0 = pt;
} }
assert( orientation != 0 );
}
base_a = orientation;
/*****************************************************************************************/ // find convex hull orientation
/* init calipers position */
seq[0] = bottom;
seq[1] = right;
seq[2] = top;
seq[3] = left;
/*****************************************************************************************/
/* Main loop - evaluate angles and rotate calipers */
/* all of edges will be checked while rotating calipers by 90 degrees */
for( k = 0; k < n; k++ )
{
/* sinus of minimal angle */
/*float sinus;*/
/* compute cosine of angle between calipers side and polygon edge */
/* dp - dot product */
float dp0 = base_a * vect[seq[0]].x + base_b * vect[seq[0]].y;
float dp1 = -base_b * vect[seq[1]].x + base_a * vect[seq[1]].y;
float dp2 = -base_a * vect[seq[2]].x - base_b * vect[seq[2]].y;
float dp3 = base_b * vect[seq[3]].x - base_a * vect[seq[3]].y;
float cosalpha = dp0 * inv_vect_length[seq[0]];
float maxcos = cosalpha;
/* number of calipers edges, that has minimal angle with edge */
int main_element = 0;
/* choose minimal angle */
cosalpha = dp1 * inv_vect_length[seq[1]];
maxcos = (cosalpha > maxcos) ? (main_element = 1, cosalpha) : maxcos;
cosalpha = dp2 * inv_vect_length[seq[2]];
maxcos = (cosalpha > maxcos) ? (main_element = 2, cosalpha) : maxcos;
cosalpha = dp3 * inv_vect_length[seq[3]];
maxcos = (cosalpha > maxcos) ? (main_element = 3, cosalpha) : maxcos;
/*rotate calipers*/
{ {
//get next base double ax = vect[n-1].x;
int pindex = seq[main_element]; double ay = vect[n-1].y;
float lead_x = vect[pindex].x*inv_vect_length[pindex];
float lead_y = vect[pindex].y*inv_vect_length[pindex];
switch( main_element )
{
case 0:
base_a = lead_x;
base_b = lead_y;
break;
case 1:
base_a = lead_y;
base_b = -lead_x;
break;
case 2:
base_a = -lead_x;
base_b = -lead_y;
break;
case 3:
base_a = -lead_y;
base_b = lead_x;
break;
default: assert(0);
}
}
/* change base point of main edge */
seq[main_element] += 1;
seq[main_element] = (seq[main_element] == n) ? 0 : seq[main_element];
for( i = 0; i < n; i++ )
{
double bx = vect[i].x;
double by = vect[i].y;
double convexity = ax * by - ay * bx;
if( convexity != 0 )
{
orientation = (convexity > 0) ? 1.f : (-1.f);
break;
}
ax = bx;
ay = by;
}
CV_Assert( orientation != 0 );
}
base_a = orientation;
/*****************************************************************************************/
/* init calipers position */
seq[0] = bottom;
seq[1] = right;
seq[2] = top;
seq[3] = left;
/*****************************************************************************************/
/* Main loop - evaluate angles and rotate calipers */
/* all of edges will be checked while rotating calipers by 90 degrees */
for( k = 0; k < n; k++ )
{
/* sinus of minimal angle */
/*float sinus;*/
/* compute cosine of angle between calipers side and polygon edge */
/* dp - dot product */
float dp0 = base_a * vect[seq[0]].x + base_b * vect[seq[0]].y;
float dp1 = -base_b * vect[seq[1]].x + base_a * vect[seq[1]].y;
float dp2 = -base_a * vect[seq[2]].x - base_b * vect[seq[2]].y;
float dp3 = base_b * vect[seq[3]].x - base_a * vect[seq[3]].y;
float cosalpha = dp0 * inv_vect_length[seq[0]];
float maxcos = cosalpha;
/* number of calipers edges, that has minimal angle with edge */
int main_element = 0;
/* choose minimal angle */
cosalpha = dp1 * inv_vect_length[seq[1]];
maxcos = (cosalpha > maxcos) ? (main_element = 1, cosalpha) : maxcos;
cosalpha = dp2 * inv_vect_length[seq[2]];
maxcos = (cosalpha > maxcos) ? (main_element = 2, cosalpha) : maxcos;
cosalpha = dp3 * inv_vect_length[seq[3]];
maxcos = (cosalpha > maxcos) ? (main_element = 3, cosalpha) : maxcos;
/*rotate calipers*/
{
//get next base
int pindex = seq[main_element];
float lead_x = vect[pindex].x*inv_vect_length[pindex];
float lead_y = vect[pindex].y*inv_vect_length[pindex];
switch( main_element )
{
case 0:
base_a = lead_x;
base_b = lead_y;
break;
case 1:
base_a = lead_y;
base_b = -lead_x;
break;
case 2:
base_a = -lead_x;
base_b = -lead_y;
break;
case 3:
base_a = -lead_y;
base_b = lead_x;
break;
default:
CV_Error(CV_StsError, "main_element should be 0, 1, 2 or 3");
}
}
/* change base point of main edge */
seq[main_element] += 1;
seq[main_element] = (seq[main_element] == n) ? 0 : seq[main_element];
switch (mode)
{
case CALIPERS_MAXHEIGHT:
{
/* now main element lies on edge alligned to calipers side */
/* find opposite element i.e. transform */
/* 0->2, 1->3, 2->0, 3->1 */
int opposite_el = main_element ^ 2;
float dx = points[seq[opposite_el]].x - points[seq[main_element]].x;
float dy = points[seq[opposite_el]].y - points[seq[main_element]].y;
float dist;
if( main_element & 1 )
dist = (float)fabs(dx * base_a + dy * base_b);
else
dist = (float)fabs(dx * (-base_b) + dy * base_a);
if( dist > max_dist )
max_dist = dist;
break;
}
case CALIPERS_MINAREARECT:
/* find area of rectangle */
{
float height;
float area;
/* find vector left-right */
float dx = points[seq[1]].x - points[seq[3]].x;
float dy = points[seq[1]].y - points[seq[3]].y;
/* dotproduct */
float width = dx * base_a + dy * base_b;
/* find vector left-right */
dx = points[seq[2]].x - points[seq[0]].x;
dy = points[seq[2]].y - points[seq[0]].y;
/* dotproduct */
height = -dx * base_b + dy * base_a;
area = width * height;
if( area <= minarea )
{
float *buf = (float *) buffer;
minarea = area;
/* leftist point */
((int *) buf)[0] = seq[3];
buf[1] = base_a;
buf[2] = width;
buf[3] = base_b;
buf[4] = height;
/* bottom point */
((int *) buf)[5] = seq[0];
buf[6] = area;
}
break;
}
} /*switch */
} /* for */
switch (mode) switch (mode)
{ {
case CV_CALIPERS_MAXHEIGHT: case CALIPERS_MINAREARECT:
{ {
/* now main element lies on edge alligned to calipers side */ float *buf = (float *) buffer;
/* find opposite element i.e. transform */ float A1 = buf[1];
/* 0->2, 1->3, 2->0, 3->1 */ float B1 = buf[3];
int opposite_el = main_element ^ 2;
float dx = points[seq[opposite_el]].x - points[seq[main_element]].x; float A2 = -buf[3];
float dy = points[seq[opposite_el]].y - points[seq[main_element]].y; float B2 = buf[1];
float dist;
if( main_element & 1 ) float C1 = A1 * points[((int *) buf)[0]].x + points[((int *) buf)[0]].y * B1;
dist = (float)fabs(dx * base_a + dy * base_b); float C2 = A2 * points[((int *) buf)[5]].x + points[((int *) buf)[5]].y * B2;
else
dist = (float)fabs(dx * (-base_b) + dy * base_a);
if( dist > max_dist ) float idet = 1.f / (A1 * B2 - A2 * B1);
max_dist = dist;
break; float px = (C1 * B2 - C2 * B1) * idet;
float py = (A1 * C2 - A2 * C1) * idet;
out[0] = px;
out[1] = py;
out[2] = A1 * buf[2];
out[3] = B1 * buf[2];
out[4] = A2 * buf[4];
out[5] = B2 * buf[4];
} }
case CV_CALIPERS_MINAREARECT: break;
/* find area of rectangle */ case CALIPERS_MAXHEIGHT:
{ {
float height; out[0] = max_dist;
float area;
/* find vector left-right */
float dx = points[seq[1]].x - points[seq[3]].x;
float dy = points[seq[1]].y - points[seq[3]].y;
/* dotproduct */
float width = dx * base_a + dy * base_b;
/* find vector left-right */
dx = points[seq[2]].x - points[seq[0]].x;
dy = points[seq[2]].y - points[seq[0]].y;
/* dotproduct */
height = -dx * base_b + dy * base_a;
area = width * height;
if( area <= minarea )
{
float *buf = (float *) buffer;
minarea = area;
/* leftist point */
((int *) buf)[0] = seq[3];
buf[1] = base_a;
buf[2] = width;
buf[3] = base_b;
buf[4] = height;
/* bottom point */
((int *) buf)[5] = seq[0];
buf[6] = area;
}
break;
} }
} /*switch */ break;
} /* for */
switch (mode)
{
case CV_CALIPERS_MINAREARECT:
{
float *buf = (float *) buffer;
float A1 = buf[1];
float B1 = buf[3];
float A2 = -buf[3];
float B2 = buf[1];
float C1 = A1 * points[((int *) buf)[0]].x + points[((int *) buf)[0]].y * B1;
float C2 = A2 * points[((int *) buf)[5]].x + points[((int *) buf)[5]].y * B2;
float idet = 1.f / (A1 * B2 - A2 * B1);
float px = (C1 * B2 - C2 * B1) * idet;
float py = (A1 * C2 - A2 * C1) * idet;
out[0] = px;
out[1] = py;
out[2] = A1 * buf[2];
out[3] = B1 * buf[2];
out[4] = A2 * buf[4];
out[5] = B2 * buf[4];
} }
break;
case CV_CALIPERS_MAXHEIGHT:
{
out[0] = max_dist;
}
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) && Mat temp;
(CV_SEQ_KIND(ptseq) != CV_SEQ_KIND_CURVE || hull.convertTo(temp, CV_32F);
CV_SEQ_ELTYPE(ptseq) != CV_SEQ_ELTYPE_PPOINT )) hull = temp;
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 ) int n = hull.checkVector(2);
{ const Point2f* hpoints = (const Point2f*)hull.data;
temp_storage = cvCreateChildMemStorage( storage );
}
else
{
temp_storage = cvCreateMemStorage(1 << 10);
}
ptseq = cvConvexHull2( ptseq, temp_storage, CV_CLOCKWISE, 1 );
n = ptseq->total;
_points.allocate(n);
points = _points;
cvStartReadSeq( ptseq, &reader );
if( CV_SEQ_ELTYPE( ptseq ) == CV_32SC2 )
{
for( i = 0; i < n; i++ )
{
CvPoint pt;
CV_READ_SEQ_ELEM( pt, reader );
points[i].x = (float)pt.x;
points[i].y = (float)pt.y;
}
}
else
{
for( i = 0; i < n; i++ )
{
CV_READ_SEQ_ELEM( points[i], reader );
}
}
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 )
} }
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 )
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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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*/ )