计算区域的形状描述子 - sumpig/OpenCV GitHub Wiki
本节将介绍几种OpenCV 的形状描述子,用于描述连续区域的形状。
它的定义是:能完整包含该形状的最小垂直矩形。
// 测试边界框
cv::Rect r0 = cv::boundingRect(contours[0]);
// 画矩形
cv::rectangle(result, r0, 0, 2)
最小覆盖圆通常在只需要区域尺寸和位置的近似值时使用。
// 测试覆盖圆
float radius;
cv::Point2f center;
cv::minEnclosingCircle(contours[1], center, radius);
// 画圆形
cv::circle(result, center, static_cast<int>(radius), cv::Scalar(0),2);
如果要更紧凑地表示区域的形状,可采用多边形逼近。
cv::approxPolyDP 函数的第四个参数,表示形状与对应的简化多边形之间能接受的最大距离。
返回的结果是 cv::Point 类型的向量,表示多边形的顶点个数。
// 测试多边形逼近
std::vector<cv::Point> poly;
cv::approxPolyDP(contours[2], poly, 5, true);
// 画多边形
cv::polylines(result, poly, true, 0, 2);
多边形绘制函数cv::polylines 与其他画图函数很相似。第三个布尔型参数表示该轮廓是否闭合。
形状的凸包(或凸包络)是包含该形状的最小凸多边形。可以把它看作一条绕在区域周围的橡皮筋。
在形状轮廓中凹进去的位置,凸包轮廓会与原始轮廓发生偏离。通常可用凸包缺陷来表示这些位置。
// 测试凸包
std::vector<cv::Point> hull;
cv::convexHull(contours[3], hull);
// 画多边形
cv::polylines(result, hull, true, 0, 2);
OpenCV 中有一个专门用于识别凸包缺陷的函数 cv::convexityDefects:
std::vector<cv::Vec4i> defects;
cv::convexityDefects(contour, hull, defects);
参数 contour 和 hull 分别表示原始轮廓和凸包轮廓。函数输出的是一个向量,它的每个元素由四个整数组成:前两个整数是顶点在轮廓中的索引,用来界定该缺陷;第三个整数表示凹陷内部最远的点;最后的整数表示最远点与凸包之间的距离。
// 测试轮廓矩
// 迭代遍历所有轮廓
itc= contours.begin();
while (itc!=contours.end()) {
// 计算所有轮廓矩
cv::Moments mom= cv::moments(cv::Mat(*itc++));
// 画重心
cv::circle(result,
// 将重心位置转换成整数
cv::Point(mom.m10/mom.m00,mom.m01/mom.m00),
2, cv::Scalar(0), 2); // 画黑点
}
函数 cv::minAreaRect 计算最小覆盖自由矩形
函数 cv::contourArea 估算轮廓的面积(内部的像素数量)
函数 cv::pointPolygonTest 判断一个点在轮廓的内部还是外部
函数 cv::matchShapes 度量两个轮廓之间的相似度
// 创建二值图像
components = components==255;
// 打开图像(包含背景)
cv::morphologyEx(components, components,
cv::MORPH_OPEN, cv::Mat(),
cv::Point(-1,-1), 3);
// 翻转图像(背景必须是黑色的)
cv::Mat componentsInv = 255 - components;
// 得到连续区域的轮廓
cv::findContours(componentsInv,
contours, // 轮廓的向量
cv::RETR_EXTERNAL, // 检索外部轮廓
cv::CHAIN_APPROX_NONE);
// 白色图像
cv::Mat quadri(components.size(), CV_8U, 255);
// 针对全部轮廓
std::vector<std::vector<cv::Point>>::iterator it = contours.begin();
while (it != contours.end()) {
poly.clear();
// 用多边形逼近轮廓
cv::approxPolyDP(*it, poly, 10, true);
// 是否为四边形?
if (poly.size()==4)
cv::polylines(quadri, poly, true, 0, 2);
++it;
}
要检测矩形,只需测量相邻边的夹角,并且排除夹角与90 度相差很大的四边形。