文章目录
- 一、函数介绍
- approxPolyDP,boundingRect,minEnclosingCircle
- 拟合函数 fitEllipse、minAreaRect
- 二、演示
OpenCV—Python 轮廓检测 绘出矩形框(findContours\ boundingRect\rectangle)
一、函数介绍
approxPolyDP,boundingRect,minEnclosingCircle
多边形逼近:基于RDP算法实现, 以指定的精度逼近多边形曲线,目的是减少多边形轮廓点数。函数签名如下:
InputArray curve, 存储在 std::vector 或Mat中的二维点的输入向量
OutputArray approxCurve, 近似的结果。类型应与输入曲线的类型相匹配。
double epsilon, 指定近似精度的参数。这是原始曲线与其近似值之间的最大距离。
bool closed 如果为真,则近似曲线是闭合的
)
矩形包围框,返回 Rect (左上角,右下角),
Rect boundingRect(
InputArray array
);
minEnclosingCircle:顾名思义,最小包围圆,
InputArray points, 二维点的输入向量,存储在 std::vector<> 或Mat
CV_OUT Point2f& center, 输出圆心
CV_OUT float& radius 输出圆半径
);
拟合函数 fitEllipse、minAreaRect
拟合椭圆,围绕一组 2D 点拟合椭圆。该函数计算最适合(在最小二乘意义上)一组 2D 点的椭圆。它返回椭圆内切的旋转矩形。由于数据点靠近包含Mat元素的边界,因此返回的ellipse/rotatedRect 数据可能包含负索引。
RotatedRect fitEllipse(
InputArray points
);
最小面积矩形 , 查找包含输入 2D 点集的最小区域的旋转矩形。该函数计算并返回指定点集的最小面积边界矩形(可能已旋转)。当数据接近包含的Mat元素边界时,返回的RotatedRect可以包含负索引。
RotatedRect minAreaRect(
InputArray points
);
二、演示
实现流程
- 首先把图像从RGB转为灰度
- 二值图像
- 去除二值化图像的零星点(可选)
- 在通过发现轮廓得到候选点
- 凸包API调用
- 绘制显示。
void QuickDemo::boundbox_Demo(Mat& image) {
Mat gray_img, bin_img, drawImg;
vector<vector<Point>> contours;
cvtColor(image, gray_img, COLOR_BGR2GRAY);
threshold(gray_img, bin_img, 210, 255, THRESH_BINARY_INV);
imshow("bin_img0", bin_img);
// 去除二值化图像的零星点
Mat kernel_ = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));
cv::morphologyEx(bin_img, bin_img, MORPH_CLOSE, kernel_, Point(-1, -1), 2);
imshow("bin_img1", bin_img);
findContours(bin_img, contours, RETR_TREE, CHAIN_APPROX_SIMPLE);
if (contours.size() == 0) { return; }
vector<vector<Point>> contours_ploy(contours.size()); // 逼近多边形点
vector<Rect> ploy_rects(contours.size()); // 多边形框
vector<Point2f> ccs(contours.size()); // 圆中心点
vector<float> radius(contours.size()); // 圆半径
vector<RotatedRect> minRects(contours.size());
vector<RotatedRect> myeliipse(contours.size());
for (size_t i = 0; i < contours.size(); i++) {
approxPolyDP(Mat(contours[i]), contours_ploy[i], 3, true);
ploy_rects[i] = boundingRect(contours_ploy[i]);
minEnclosingCircle(contours_ploy[i], ccs[i], radius[i]);
if (contours_ploy[i].size() > 5) {
myeliipse[i] = fitEllipse(contours_ploy[i]);
minRects[i] = minAreaRect(contours_ploy[i]);
}
}
image.copyTo(drawImg);
RNG rng(1234);
Point2f pts[4];
for (size_t t = 0; t < contours.size(); t++) {
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
rectangle(drawImg, ploy_rects[t], color, 2, 8);
circle(drawImg, ccs[t], radius[t], color, 2, 8);
if (contours_ploy[t].size() > 5) {
ellipse(drawImg, myeliipse[t], color, 1, 8);
minRects[t].points(pts);
for (int r = 0; r < 4; r++) {
line(drawImg, pts[r], pts[(r + 1) % 4], color, 2, 8);
}
}
}
imshow("drawImg", drawImg);
}