3.3使用多邊形将輪廓包圍
在實際運用中,常常會有将檢測處的輪廓用多邊形包圍,本節就為讀者講解如何用多邊形包圍輪廓。
3.3.1多邊形包圍輪廓的相關API
3.3.1.1多邊形包圍輪廓的相關API講解
傳回外圍矩形邊界:boundingRect() 函數
C++: Rect boundingRect(InputArray points)
【參數】
唯一的參數就是輸入的二維點集。
尋找最小包圍矩形:minAreaRect()函數
C++: RotatedRect minAreaRect(InputArray points)
【參數】
對于輸入的二維點集,計算包圍點集的最小矩形
尋找最小包圍圓形:minEnclosingCircle()函數
利用疊代算法,對給定的二維點集尋找計算可包圍點集的最小圓形,其定義如下
C++: void minEnclosingCircle(InputArray points,
Point2f& center,
float& radius)
【參數】
第一個參數,points:輸入的二維點集,資料類型為vector<>或Mat類型
第二個參數,center:繪制圓的圓心坐标
第三個參數,radius:圓的半徑
用橢圓拟合二維點集:fitEllipse()函數
C++: RotatedRect fitEllipse(InputArray points)
【參數】
唯一的參數就是二維點集。
逼近多邊形曲線: approxPolyDP()函數
C++: void approxPolyDP(InputArray curve,
OutputArray approxCurve,
double epsilon,
bool closed)
【參數】
第一個參數,curve:輸入的二維點集,可以是vector類型或Mat類型 ;
第二參數,approxCurve:多邊形逼近的結果,其類型與輸入的點集類型一緻;
第三個參數,epsilon:逼近的精度,為原始曲線和逼近曲線間的最大值;
第四個參數,closed:如果為true,逼近的曲線為封閉曲線,如果為false則逼近曲線不封閉。
多邊形測試:pointPolygonTest ()函數
double pointPolygonTest(InputArray contour,
Point2f pt,
bool measureDist);
【參數】
第一個參數,contour:輸入的輪廓;
第二個參數,pt:輪廓中檢測的點;
第四個參數,measureDist:如果是true:估計點到最近輪廓邊緣的距離,否則檢查點是否在輪廓中。
3.3.1.2多邊形包圍輪廓的相關API源代碼
傳回外圍矩形邊界:boundingRect() 函數
/*【boundingRect ( )源代碼】**********************************************************
* @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的對應版本源碼完全一樣,均在對應的安裝目錄下)
* @源碼路徑:…\opencv\sources\modules\imgproc\src\ shapedescr.cpp
* @起始行數:698行
********************************************************************************/
cv::Rect cv::boundingRect(InputArray array)
{
Mat m = array.getMat();
return m.depth() <= CV_8U ? maskBoundingRect(m) : pointSetBoundingRect(m);
}
從源碼可以看出,其實是調用了兩個函數maskBoundingRect()和pointSetBoundingRect(),函數源代碼如下。
/*【pointSetBoundingRect ( )源代碼】***************************************************
* @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的對應版本源碼完全一樣,均在對應的安裝目錄下)
* @源碼路徑:…\opencv\sources\modules\imgproc\src\ shapedescr.cpp
* @起始行數:483行
********************************************************************************/
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 = points.ptr<Point>();
Point pt = pts[0];
#if CV_SSE4_2
if(cv::checkHardwareSupport(CV_CPU_SSE4_2))
{
if( !is_float )
{
__m128i minval, maxval;
minval = maxval = _mm_loadl_epi64((const __m128i*)(&pt)); //min[0]=pt.x, min[1]=pt.y
for( i = 1; i < npoints; i++ )
{
__m128i ptXY = _mm_loadl_epi64((const __m128i*)&pts[i]);
minval = _mm_min_epi32(ptXY, minval);
maxval = _mm_max_epi32(ptXY, maxval);
}
xmin = _mm_cvtsi128_si32(minval);
ymin = _mm_cvtsi128_si32(_mm_srli_si128(minval, 4));
xmax = _mm_cvtsi128_si32(maxval);
ymax = _mm_cvtsi128_si32(_mm_srli_si128(maxval, 4));
}
else
{
__m128 minvalf, maxvalf, z = _mm_setzero_ps(), ptXY = _mm_setzero_ps();
minvalf = maxvalf = _mm_loadl_pi(z, (const __m64*)(&pt));
for( i = 1; i < npoints; i++ )
{
ptXY = _mm_loadl_pi(ptXY, (const __m64*)&pts[i]);
minvalf = _mm_min_ps(minvalf, ptXY);
maxvalf = _mm_max_ps(maxvalf, ptXY);
}
float xyminf[2], xymaxf[2];
_mm_storel_pi((__m64*)xyminf, minvalf);
_mm_storel_pi((__m64*)xymaxf, maxvalf);
xmin = cvFloor(xyminf[0]);
ymin = cvFloor(xyminf[1]);
xmax = cvFloor(xymaxf[0]);
ymax = cvFloor(xymaxf[1]);
}
}
else
#endif
{
if( !is_float )
{
xmin = xmax = pt.x;
ymin = ymax = pt.y;
for( i = 1; i < npoints; i++ )
{
pt = pts[i];
if( xmin > pt.x )
xmin = pt.x;
if( xmax < pt.x )
xmax = pt.x;
if( ymin > pt.y )
ymin = pt.y;
if( ymax < pt.y )
ymax = pt.y;
}
}
else
{
Cv32suf v;
// init values
xmin = xmax = CV_TOGGLE_FLT(pt.x);
ymin = ymax = CV_TOGGLE_FLT(pt.y);
for( i = 1; i < npoints; i++ )
{
pt = pts[i];
pt.x = CV_TOGGLE_FLT(pt.x);
pt.y = CV_TOGGLE_FLT(pt.y);
if( xmin > pt.x )
xmin = pt.x;
if( xmax < pt.x )
xmax = pt.x;
if( ymin > pt.y )
ymin = pt.y;
if( ymax < pt.y )
ymax = pt.y;
}
v.i = CV_TOGGLE_FLT(xmin); xmin = cvFloor(v.f);
v.i = CV_TOGGLE_FLT(ymin); ymin = cvFloor(v.f);
// because right and bottom sides of the bounding rectangle are not inclusive
// (note +1 in width and height calculation below), cvFloor is used here instead of cvCeil
v.i = CV_TOGGLE_FLT(xmax); xmax = cvFloor(v.f);
v.i = CV_TOGGLE_FLT(ymax); ymax = cvFloor(v.f);
}
}
return Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
}
/*【maskBoundingRect ( )源代碼】******************************************************
* @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的對應版本源碼完全一樣,均在對應的安裝目錄下)
* @源碼路徑:…\opencv\sources\modules\imgproc\src\ shapedescr.cpp
* @起始行數:603行
********************************************************************************/
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);
}
尋找最小包圍矩形:minAreaRect()函數
/*【minAreaRect ( )源代碼】***********************************************************
* @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的對應版本源碼完全一樣,均在對應的安裝目錄下)
* @源碼路徑:…\opencv\sources\modules\imgproc\src\ rotcalipers.cpp
* @起始行數:343行
********************************************************************************/
cv::RotatedRect cv::minAreaRect( InputArray _points )
{
Mat hull;
Point2f out[3];
RotatedRect box;
convexHull(_points, hull, true, true);
if( hull.depth() != CV_32F )
{
Mat temp;
hull.convertTo(temp, CV_32F);
hull = temp;
}
int n = hull.checkVector(2);
const Point2f* hpoints = hull.ptr<Point2f>();
if( n > 2 )
{
rotatingCalipers( hpoints, n, CALIPERS_MINAREARECT, (float*)out );
box.center.x = out[0].x + (out[1].x + out[2].x)*0.5f;
box.center.y = out[0].y + (out[1].y + out[2].y)*0.5f;
box.size.width = (float)std::sqrt((double)out[1].x*out[1].x + (double)out[1].y*out[1].y);
box.size.height = (float)std::sqrt((double)out[2].x*out[2].x + (double)out[2].y*out[2].y);
box.angle = (float)atan2( (double)out[1].y, (double)out[1].x );
}
else if( n == 2 )
{
box.center.x = (hpoints[0].x + hpoints[1].x)*0.5f;
box.center.y = (hpoints[0].y + hpoints[1].y)*0.5f;
double dx = hpoints[1].x - hpoints[0].x;
double dy = hpoints[1].y - hpoints[0].y;
box.size.width = (float)std::sqrt(dx*dx + dy*dy);
box.size.height = 0;
box.angle = (float)atan2( dy, dx );
}
else
{
if( n == 1 )
box.center = hpoints[0];
}
box.angle = (float)(box.angle*180/CV_PI);
return box;
}
尋找最小包圍圓形:minEnclosingCircle()函數
/*【minEnclosingCircle ( )源代碼】******************************************************
* @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的對應版本源碼完全一樣,均在對應的安裝目錄下)
* @源碼路徑:…\opencv\sources\modules\imgproc\src\ shapedescr.cpp
* @起始行數:196行
********************************************************************************/
void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radius )
{
int max_iters = 100;
const float eps = FLT_EPSILON*2;
bool result = false;
Mat points = _points.getMat();
int i, j, k, count = points.checkVector(2);
int depth = points.depth();
Point2f center;
float radius = 0.f;
CV_Assert(count >= 0 && (depth == CV_32F || depth == CV_32S));
_center.x = _center.y = 0.f;
_radius = 0.f;
if( count == 0 )
return;
bool is_float = depth == CV_32F;
const Point* ptsi = points.ptr<Point>();
const Point2f* ptsf = points.ptr<Point2f>();
Point2f pt = is_float ? ptsf[0] : Point2f((float)ptsi[0].x,(float)ptsi[0].y);
Point2f pts[4] = {pt, pt, pt, pt};
for( i = 1; i < count; i++ )
{
pt = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
if( pt.x < pts[0].x )
pts[0] = pt;
if( pt.x > pts[1].x )
pts[1] = pt;
if( pt.y < pts[2].y )
pts[2] = pt;
if( pt.y > pts[3].y )
pts[3] = pt;
}
for( k = 0; k < max_iters; k++ )
{
double min_delta = 0, delta;
Point2f farAway(0,0);
/*only for first iteration because the alg is repared at the loop's foot*/
if( k == 0 )
findEnslosingCicle4pts_32f( pts, center, radius );
for( i = 0; i < count; i++ )
{
pt = is_float ? ptsf[i] : Point2f((float)ptsi[i].x,(float)ptsi[i].y);
delta = pointInCircle( pt, center, radius );
if( delta < min_delta )
{
min_delta = delta;
farAway = pt;
}
}
result = min_delta >= 0;
if( result )
break;
Point2f ptsCopy[4];
// find good replacement partner for the point which is at most far away,
// starting with the one that lays in the actual circle (i=3)
for( i = 3; i >= 0; i-- )
{
for( j = 0; j < 4; j++ )
ptsCopy[j] = i != j ? pts[j] : farAway;
findEnslosingCicle4pts_32f( ptsCopy, center, radius );
if( pointInCircle( pts[i], center, radius ) >= 0)
{
// replaced one again in the new circle?
pts[i] = farAway;
break;
}
}
}
if( !result )
{
radius = 0.f;
for( i = 0; i < count; i++ )
{
pt = is_float ? ptsf[i] : Point2f((float)ptsi[i].x,(float)ptsi[i].y);
float dx = center.x - pt.x, dy = center.y - pt.y;
float t = dx*dx + dy*dy;
radius = MAX(radius, t);
}
radius = (float)(std::sqrt(radius)*(1 + eps));
}
_center = center;
_radius = radius;
}
用橢圓拟合二維點集:fitEllipse()函數
/*【fitEllipse ( )源代碼】**************************************************************
* @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的對應版本源碼完全一樣,均在對應的安裝目錄下)
* @源碼路徑:…\opencv\sources\modules\imgproc\src\ shapedescr.cpp
* @起始行數:369行
********************************************************************************/
cv::RotatedRect cv::fitEllipse( InputArray _points )
{
Mat points = _points.getMat();
int i, n = points.checkVector(2);
int depth = points.depth();
CV_Assert( n >= 0 && (depth == CV_32F || depth == CV_32S));
RotatedRect box;
if( n < 5 )
CV_Error( CV_StsBadSize, "There should be at least 5 points to fit the ellipse" );
// New fitellipse algorithm, contributed by Dr. Daniel Weiss
Point2f c(0,0);
double gfp[5], rp[5], t;
const double min_eps = 1e-8;
bool is_float = depth == CV_32F;
const Point* ptsi = points.ptr<Point>();
const Point2f* ptsf = points.ptr<Point2f>();
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++ )
{
Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
p -= c;
bd[i] = 10000.0; // 1.0?
Ad[i*5] = -(double)p.x * p.x; // A - C signs inverted as proposed by APP
Ad[i*5 + 1] = -(double)p.y * p.y;
Ad[i*5 + 2] = -(double)p.x * p.y;
Ad[i*5 + 3] = p.x;
Ad[i*5 + 4] = p.y;
}
solve(A, b, x, DECOMP_SVD);
// now use general-form parameters A - E to find the ellipse center:
// differentiate general form wrt x/y to get two equations for cx and cy
A = Mat( 2, 2, CV_64F, Ad );
b = Mat( 2, 1, CV_64F, bd );
x = Mat( 2, 1, CV_64F, rp );
Ad[0] = 2 * gfp[0];
Ad[1] = Ad[2] = gfp[2];
Ad[3] = 2 * gfp[1];
bd[0] = gfp[3];
bd[1] = gfp[4];
solve( A, b, x, DECOMP_SVD );
// re-fit for parameters A - C with those center coordinates
A = Mat( n, 3, CV_64F, Ad );
b = Mat( n, 1, CV_64F, bd );
x = Mat( 3, 1, CV_64F, gfp );
for( i = 0; i < n; i++ )
{
Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
p -= c;
bd[i] = 1.0;
Ad[i * 3] = (p.x - rp[0]) * (p.x - rp[0]);
Ad[i * 3 + 1] = (p.y - rp[1]) * (p.y - rp[1]);
Ad[i * 3 + 2] = (p.x - rp[0]) * (p.y - rp[1]);
}
solve(A, b, x, DECOMP_SVD);
// store angle and radii
rp[4] = -0.5 * atan2(gfp[2], gfp[1] - gfp[0]); // convert from APP angle usage
if( fabs(gfp[2]) > min_eps )
t = gfp[2]/sin(-2.0 * rp[4]);
else // ellipse is rotated by an integer multiple of pi/2
t = gfp[1] - gfp[0];
rp[2] = fabs(gfp[0] + gfp[1] - t);
if( rp[2] > min_eps )
rp[2] = std::sqrt(2.0 / rp[2]);
rp[3] = fabs(gfp[0] + gfp[1] + t);
if( rp[3] > min_eps )
rp[3] = std::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;
}
逼近多邊形曲線:approxPolyDP()函數
/*【approxPolyDP ( )源代碼】**********************************************************
* @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的對應版本源碼完全一樣,均在對應的安裝目錄下)
* @源碼路徑:…\opencv\sources\modules\imgproc\src\ approx.cpp
* @起始行數:674行
********************************************************************************/
void cv::approxPolyDP( InputArray _curve, OutputArray _approxCurve,
double epsilon, bool closed )
{
Mat curve = _curve.getMat();
int npoints = curve.checkVector(2), depth = curve.depth();
CV_Assert( npoints >= 0 && (depth == CV_32S || depth == CV_32F));
if( npoints == 0 )
{
_approxCurve.release();
return;
}
AutoBuffer<Point> _buf(npoints);
AutoBuffer<Range> _stack(npoints);
Point* buf = _buf;
int nout = 0;
if( depth == CV_32S )
nout = approxPolyDP_(curve.ptr<Point>(), npoints, buf, closed, epsilon, &_stack);
else if( depth == CV_32F )
nout = approxPolyDP_(curve.ptr<Point2f>(), npoints, (Point2f*)buf, closed, epsilon, &_stack);
else
CV_Error( CV_StsUnsupportedFormat, "" );
Mat(nout, 1, CV_MAKETYPE(depth, 2), buf).copyTo(_approxCurve);
}
多邊形測試:pointPolygonTest ()函數
/*【pointPolygonTest ( )源代碼】*******************************************************
* @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的對應版本源碼完全一樣,均在對應的安裝目錄下)
* @源碼路徑:…\opencv\sources\modules\imgproc\src\ geometry.cpp
* @起始行數:95行
********************************************************************************/
double cv::pointPolygonTest( InputArray _contour, Point2f pt, bool measureDist )
{
double result = 0;
Mat contour = _contour.getMat();
int i, total = contour.checkVector(2), counter = 0;
int depth = contour.depth();
CV_Assert( total >= 0 && (depth == CV_32S || depth == CV_32F));
bool is_float = depth == CV_32F;
double min_dist_num = FLT_MAX, min_dist_denom = 1;
Point ip(cvRound(pt.x), cvRound(pt.y));
if( total == 0 )
return measureDist ? -DBL_MAX : -1;
const Point* cnt = contour.ptr<Point>();
const Point2f* cntf = (const Point2f*)cnt;
if( !is_float && !measureDist && ip.x == pt.x && ip.y == pt.y )
{
// the fastest "purely integer" branch
Point v0, v = cnt[total-1];
for( i = 0; i < total; i++ )
{
int dist;
v0 = v;
v = cnt[i];
if( (v0.y <= ip.y && v.y <= ip.y) ||
(v0.y > ip.y && v.y > ip.y) ||
(v0.x < ip.x && v.x < ip.x) )
{
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)))) )
return 0;
continue;
}
dist = (ip.y - v0.y)*(v.x - v0.x) - (ip.x - v0.x)*(v.y - v0.y);
if( dist == 0 )
return 0;
if( v.y < v0.y )
dist = -dist;
counter += dist > 0;
}
result = counter % 2 == 0 ? -1 : 1;
}
else
{
Point2f v0, v;
Point iv;
if( is_float )
{
v = cntf[total-1];
}
else
{
v = cnt[total-1];
}
if( !measureDist )
{
for( i = 0; i < total; i++ )
{
double dist;
v0 = v;
if( is_float )
v = cntf[i];
else
v = cnt[i];
if( (v0.y <= pt.y && v.y <= pt.y) ||
(v0.y > pt.y && v.y > pt.y) ||
(v0.x < pt.x && v.x < pt.x) )
{
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)))) )
return 0;
continue;
}
dist = (double)(pt.y - v0.y)*(v.x - v0.x) - (double)(pt.x - v0.x)*(v.y - v0.y);
if( dist == 0 )
return 0;
if( v.y < v0.y )
dist = -dist;
counter += dist > 0;
}
result = counter % 2 == 0 ? -1 : 1;
}
else
{
for( i = 0; i < total; i++ )
{
double dx, dy, dx1, dy1, dx2, dy2, dist_num, dist_denom = 1;
v0 = v;
if( is_float )
v = cntf[i];
else
v = cnt[i];
dx = v.x - v0.x; dy = v.y - v0.y;
dx1 = pt.x - v0.x; dy1 = pt.y - v0.y;
dx2 = pt.x - v.x; dy2 = pt.y - v.y;
if( dx1*dx + dy1*dy <= 0 )
dist_num = dx1*dx1 + dy1*dy1;
else if( dx2*dx + dy2*dy >= 0 )
dist_num = dx2*dx2 + dy2*dy2;
else
{
dist_num = (dy1*dx - dx1*dy);
dist_num *= dist_num;
dist_denom = dx*dx + dy*dy;
}
if( dist_num*min_dist_denom < min_dist_num*dist_denom )
{
min_dist_num = dist_num;
min_dist_denom = dist_denom;
if( min_dist_num == 0 )
break;
}
if( (v0.y <= pt.y && v.y <= pt.y) ||
(v0.y > pt.y && v.y > pt.y) ||
(v0.x < pt.x && v.x < pt.x) )
continue;
dist_num = dy1*dx - dx1*dy;
if( dy < 0 )
dist_num = -dist_num;
counter += dist_num > 0;
}
result = std::sqrt(min_dist_num/min_dist_denom);
if( counter % 2 == 0 )
result = -result;
}
}
return result;
}
3.3.2多邊形包圍輪廓執行個體
3.3.2.1建立包圍輪廓的矩形邊界執行個體
代碼參看附件【demo1】。
圖1
3.3.2.2建立包圍輪廓的最小矩形邊界執行個體
代碼參看附件【demo2】。
圖2
3.3.2.3建立包圍輪廓的圓形邊界執行個體
代碼參看附件【demo3】。
圖3
3.3.2.4建立包圍輪廓的橢圓邊界執行個體
代碼參看附件【demo4】。
圖4
3.3.2.5使用多邊形包圍輪廓執行個體
代碼參看附件【demo5】。
圖5
3.3.2.6使用多邊形測試執行個體
代碼參看附件【demo6】。
圖6