- 轮廓的特征描述
在对实际图像进行轮廓查找时,得到的轮廓数量很多。获取轮廓后,通常基于轮廓的特征进行筛选、识别和处理。例如,基于轮廓的周长和面积对轮廓进行筛选,然后绘制筛选的目标轮廓或其最小外接矩形。
常用的轮廓特征,包括图像距、轮廓周长、轮廓近似、凸包、边界矩形、拟合图形等特征。
2 轮廓的面积、周长、质心和近似多边形
面积、周长、质心是常用的轮廓特征
2.1轮廓的面积和周长
几何矩实质是面积或质量。函数 cv.moments() 的返回值 Moments[‘m00’] 表示轮廓面积。
轮廓的面积也可以使用函数 cv2.contourArea() 计算。
轮廓的周长可以使用函数 cv2.arcLength() 计算。
//计算轮廓面积
CV_EXPORTS_W double contourArea( InputArray contour, bool oriented = false );
//计算轮廓周长
CV_EXPORTS_W double arcLength( InputArray curve, bool closed );
2.2利用轮廓的面积和周长,对轮廓进行过滤
Mat src = imread("F:/code/images/rice.png");
CV_Assert(!src.empty());
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
//高斯滤波
GaussianBlur(src, src, Size(3, 3), 0);
//得到灰度图
Mat gray, binary;
cvtColor(src, gray, COLOR_RGB2GRAY);
imshow("gray", gray);
//得到二值图
threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
imshow("binary", binary);
//发现轮廓
vector<vector<Point>>contours;//因为每个contour都是一系列点的集合
vector<Vec4i> hierarchy;//层次信息
findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
printf("%llu", contours.size());//25
for (size_t t = 0; t < contours.size(); t++) {
//图像轮廓计算:计算面积和周长
double area = contourArea(contours[t]);
double length = arcLength(contours[t], true);
printf("area:%.2f, contour length:%.2f\n", area, length);
//通过面积和周长来过滤掉一些轮廓
if (area < 1800 || length < 10) continue;
drawContours(src, contours, t, Scalar(0, 0, 255), 1, 8);
}
imshow("find contours demo", src);
3,对轮廓的其他计算
获取轮廓最大外接矩形、旋转矩形、轮廓最小外接矩形
3.1 C++ API
boundingRect()得到包覆此轮廓的最小正矩形,minAreaRect()得到包覆轮廓的最小斜矩形
CV_EXPORTS_W Rect boundingRect( InputArray array );
CV_EXPORTS_W RotatedRect minAreaRect( InputArray points );
轮廓的旋转矩形是通过minAreaRect返回的旋转矩形
轮廓的最小外接矩形利用获取旋转矩形的四个顶点,通过绘制四条直线实现绘制
//获取轮廓最大外接矩形
Rect box = boundingRect(contours[t]);
rectangle(src, box, Scalar(0,0,255), 1, LINE_AA);
//椭圆绘制
RotatedRect rrt = minAreaRect(contours[t]);
ellipse(src, rrt, Scalar(255, 0, 0), 1, 8);
//获取轮廓最小外接矩形
Point2f pts[4];
rrt.points(pts);
for (int i = 0; i < 4; i++) {
line(src, pts[i], pts[(i + 1) % 4], Scalar(0, 255, 0), 1, 8);//编程技巧 % 4
}
4,轮廓逼近
4.1 轮廓逼近的本质是减少编码点
C++ API:approxPolyDP
CV_EXPORTS_W void approxPolyDP( InputArray curve,
OutputArray approxCurve,
double epsilon, bool closed );
curve:以顶点构成的二维向量组表示的曲线(如轮廓列表 contours 中的一个轮廓)
approxCurve:近似多边形顶点坐标 (x,y) 的二维向量组
epsilon:近似精度,浮点数,原始曲线与近似多边形之间的最大距离
closed:曲线闭合标志,True 表示近似曲线是闭合的
4.2 实例
Mat src1 = imread("F:/code/images/contours.png");
CV_Assert(!src1.empty());
imshow("input1", src1);
//获取轮廓
vector<vector<Point>>contours1;
contour_info2(src1, contours1);
//多边形逼近
for (size_t t = 0; t < contours1.size(); t++) {
Moments mm1 = moments(contours1[t]);
//可以获取轮廓的中心位置
double cx = mm1.m10 / mm1.m00;
double cy = mm1.m01 / mm1.m00;
circle(src1, Point(cx, cy), 3, Scalar(255, 0, 0), 2, 8, 0);
double area = contourArea(contours1[t]);
double length = arcLength(contours1[t], true);
Mat result;//放多边形的点对
approxPolyDP(contours1[t], result, 4, true);
printf("contour corners :%d,contour area:%.2f,contour length:%.2f\n", result.rows, area, length);
if (result.rows == 6) {
putText(src1, "poly", Point(cx, cy - 10), FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 0, 255), 1, 8);
}
if (result.rows == 4) {
putText(src1, "rectangle", Point(cx, cy - 10), FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 255, 255), 1, 8);
}
if (result.rows == 3) {
putText(src1, "triangle", Point(cx, cy - 10), FONT_HERSHEY_PLAIN, 1.0, Scalar(255, 0, 255), 1, 8);
}
if (result.rows > 10) {
putText(src1, "circle", Point(cx, cy - 10), FONT_HERSHEY_PLAIN, 1.0, Scalar(255, 255, 0), 1, 8);
}
drawContours(src1, result, -1, Scalar(0,0,255), 8);
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/182005.html