文章目录
1. 步骤
- 首先将图像变为二值图像threshold()
- 发现轮廓,找到图像轮廓canny()
- 通过相关API在轮廓点上找到最小包含矩形和 圆,旋转矩形与椭圆。
- 绘制它们。rectangle()或circle()
2. 相关API
2.1 approxPolyDP()
- 基于RDP算法实现,目的是减少多边形轮廓点数
2.2 cv::boundingRect()
- 得到轮廓周围最小矩形左上交点坐标和右下角点坐标,用以绘制一个矩形
2.3 cv::minAreaRect()
得到一个旋转的矩形,返回旋转矩形。
2.4 cv::minEnclosingCircle()
- 得到最小区域圆形
2.5 cv::fitEllipse()
- 得到最小椭圆
3. 例程
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
using namespace cv;
using namespace std;
void CallBack(int, void*);
Mat src, dst, binout, src_gray;
int Threshold = 40;
int main() {
//输入图像并转化为灰度
src = imread("D:/resource/images/硬币.jpg");
if (src.empty()) {
printf("src couldn't be loaded...");
return -1;
}
imshow("input", src);
cvtColor(src, src_gray, COLOR_BGR2GRAY);
medianBlur(src_gray, src_gray, 21);
blur(src_gray, src_gray, Size(21, 21));
//设置阈值后执行CallBack()
namedWindow("output");
createTrackbar("Threshold", "output", &Threshold, 255, CallBack);
CallBack(0, 0);
waitKey(0);
return 0;
}
void CallBack(int, void*) {
//二值化
threshold(src_gray, binout, Threshold, 255, THRESH_BINARY);
//Canny(src_gray, binout, Threshold, Threshold * 2);
imshow("binary", ~binout);
//寻找边缘
vector<vector<Point>> contours;
vector<Vec4i> hierachy;
findContours(binout, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
//得到矩形框和圆形框和椭圆框的的相关参数
vector<vector<Point>> polies(contours.size());//减少后的多边形边缘上的点
vector<Rect> rects(contours.size());//矩形框
vector<Point2f> ccs(contours.size());//圆心
vector<float> radius(contours.size());//圆的半径
vector<RotatedRect> rotatedRects(contours.size());//旋转矩形框
vector<RotatedRect> rotatedEllipces(contours.size());//旋转椭圆框
for (size_t i = 0; i < contours.size(); i++) {
approxPolyDP(Mat(contours[i]), polies[i], 3, true);//减少多边形边缘点
rects[i] = boundingRect(polies[i]);
minEnclosingCircle(polies[i], ccs[i], radius[i]);
if (polies[i].size() > 5) {//旋转矩形和椭圆检测点至少需要5个
rotatedEllipces[i] = fitEllipse(polies[i]);
rotatedRects[i] = minAreaRect(polies[i]);
}
}
//绘制他们
Point2f pts[4];
for (size_t i = 0; i < contours.size(); i++) {
rectangle(src, rects[i], Scalar(255, 0, 0), 2);//画矩形框
circle(src, ccs[i], radius[i], Scalar(0, 255, 255), 2, 8);//画圆
if (polies.size() > 5) {
ellipse(src, rotatedEllipces[i], Scalar(0, 0, 255), 2, 8);//画旋转椭圆
rotatedRects[i].points(pts);//画旋转矩形
for (int k = 0; k < 4; k++)
line(src, pts[k], pts[(k + 1) % 4], Scalar(255, 255, 0), 2, 8);
}
}
imshow("output", src);
return;
}