16.1 引言
在寻找到目标轮廓后,很多轮廓基本是不规则的,为了便于目标定位可以用规则的形状将轮廓框选起来。如矩形、椭圆等。
16.2 相关API
16.2.1 approxPolyDP多边拟合函数
该算子使用 Douglas-Peucker 算法求得一条顶点较少的多折线/多边形,以指定的精度近似输入的曲线或多边形。
Douglas-Peucker(拉默-道格拉斯-普克ROP) 算法原理:
- 在曲线首尾两点间虚连一条直线,求其余点到该直线的距离。
- 设定距离阈值,最大距离大于阈值,则保留该点。否则将其余点都去除。
- 依据保留的点将直线分为两段,重复进行1,2步骤,迭代操作,直至无点可舍。
如下图所示:
·void approxPolyOP( InputArray curve, OutputArray approxCurve, double epsilon, bool closed)
参数 | 含义 | |
作用 | 多边拟合,减少多边形轮廓点集 | |
输入 | curve | 一般由图像的轮廓点组成的点集 |
approxCurve | 输出的多边形点集 | |
epsilon | 输出的精度,表示原始曲线与近似之间的最大距离 | |
closed | 多边形是否封闭,true:封闭,false:不封闭 | |
返回值 | void | 无 |
16.2.2 点集的矩形包围框
·Rect boundingRect( InputArray points)
参数 | 含义 | |
作用 | 得到轮廓周围最小矩形左上交点坐标和右下交点坐标,绘制一个矩形 | |
输入 | points | 单个轮廓的点集 |
返回值 | Rect | 矩形 |
·RotatedRect minAreaRect( InputArray points)
参数 | 含义 | |
作用 | 得到轮廓的最小包围矩形 | |
输入 | points | 单个轮廓的点集 |
返回值 | RotatedRect | 旋转的矩形 |
16.2.3 点集的圆形包围框
·viod minEnclosingCircle( InputArray points,Pointsf& center, float &radius)
参数 | 含义 | |
作用 | 获取最小包围圆形 | |
输入 | points | 单个轮廓的点集 |
center | 输出的圆心位置 | |
| 输出的圆半径 | |
返回值 | void | 无 |
16.2.4 点集的椭圆形包围框
·RotateRect fitEllipse( InputArray points)
参数 | 含义 | |
作用 | 得到轮廓的最小包围椭圆形 | |
输入 | points | 单个轮廓的点集 |
返回值 | RotatedRect | 椭圆形 |
16.3 代码示例
Mat src, cannyImg,dst;
const char* OUTPUTWIN = "outputImg";
int thresholdValue = 100;
int thresholdMax = 255;
RNG rng(12345);
void CannyFindContours(int, void*)
{
Mat brinaryImg;
//canny边缘检测,(此外可以使用阈值分割等)
Canny(cannyImg, brinaryImg, thresholdValue, thresholdValue * 2,3,false);
vector<vector<Point>> contours;
vector<Vec4i> hierachy;
//对边缘检测后的图像进行轮廓寻找
findContours(brinaryImg, contours, hierachy, RETR_TREE, CHAIN_APPROX_NONE,Point(0,0));
//多边拟合
vector<vector<Point>> approxCotours(contours.size());
vector<Rect> RectVec(contours.size());
vector<RotatedRect> RotatedRectVec(contours.size());
vector<Point2f> centerVec(contours.size());
vector<float> radiusVec(contours.size());
vector<RotatedRect> ellipseVec(contours.size());
for (int i = 0; i < contours.size(); i++)
{
approxPolyDP(contours[i], approxCotours[i],5,true);
//矩形
RectVec[i]=boundingRect(approxCotours[i]);
//圆形
minEnclosingCircle(approxCotours[i], centerVec[i], radiusVec[i]);
if (approxCotours[i].size() > 5)
{
//最小旋转矩形
RotatedRectVec[i] = minAreaRect(approxCotours[i]);
//椭圆形
ellipseVec[i] = fitEllipse(approxCotours[i]);
}
}
Point2f ptemp[4];
for (int i = 0; i < contours.size(); i++)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
//绘制矩形
rectangle(src, RectVec[i], color, 2, 8);
//绘制圆形
circle(src,centerVec[i],radiusVec[i],color,2,8);
if (approxCotours[i].size() > 5)
{
//绘制椭圆
ellipse(src, ellipseVec[i], color, 2, 8);
//绘制旋转矩形
RotatedRectVec[i].points(ptemp);
for (int n = 0; n < 4; n++)
{
line(src, ptemp[n], ptemp[(n + 1) % 4], color, 2, 8);
}
}
}
imshow(OUTPUTWIN, src);
}
int main(int argc, char** argv)
{
//源图像
src = imread("D:\\testimg\\CSet12\\yingbi.png");
if (src.empty())
{
printf("Could not load the image...\n");
return -1;
}
else;
namedWindow("inputImg", WINDOW_AUTOSIZE);
imshow("inputImg", src);
namedWindow(OUTPUTWIN, WINDOW_AUTOSIZE);
cvtColor(src, cannyImg,COLOR_BGR2GRAY);
const char* trackbarTitle = "threshold";
createTrackbar(trackbarTitle, OUTPUTWIN, &thresholdValue, thresholdMax, CannyFindContours);
CannyFindContours(0, 0);
waitKey(0);
return 0;
}
16.4 判断点与多边形的关系
多边形测试简单来说,就是测试一个点是否在给定的多边形内部、边缘或外部的方法。
16.4.1 相关API
·double pointPolygonTest( InputArray contour, Point2f pt,bool measureDist)
参数 | 含义 | |
作用 | 计算点和多边形的关系 | |
输入 | contour | 多边形轮廓 |
pt | 测试点 | |
measureDist | 是否返回距离值;false:1表示在内部,0表示在边界上,-1表示在外部;true返回实际距离。 | |
返回值 | double | 跟参数3相关 |