OpenCV3之——使用多边形将轮廓包围
一、用最小旋转矩形将点集轮廓包围
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
Mat image(600, 600, CV_8UC3);
RNG& rng = theRNG();
while (1) {
//参数初始化
int count = rng.uniform(3, 103);//随机生成的点的个数
vector<Point> points;
//随机生成点的坐标
for (int i = 0; i < count; i++) {
Point point;
point.x = rng.uniform(image.cols / 4, image.cols * 3 / 4);
point.y = rng.uniform(image.rows / 4, image.rows * 3 / 4);
points.push_back(point);
}
//对给定的二维点集寻找最小面积包围的矩形
RotatedRect box = minAreaRect(Mat(points));//返回最小旋转矩形
Point2f vertex[4];//用于存储矩形四个顶点
box.points(vertex);
//绘制出随机颜点
image = Scalar::all(0);
for (int i = 0; i < count; i++)
circle(image, points[i], 3, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), FILLED, LINE_AA);
//绘出最小面积包围的矩形
for (int i = 0; i < 4; i++)
line(image, vertex[i], vertex[(i + 1) % 4], Scalar(100, 200, 255), 2, LINE_AA);
//显示窗口
imshow("矩形包围示例", image);
//按下ESC,Q或q键,程序退出
char key = (char)waitKey(0);
if (key == 27 || key == 'Q' || key == 'q') {
break;
}
}
return 0;
}
运行结果:
二、创建包围轮廓的圆形边界
//在上面示例的基础上加以修改
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc,char** argv) {
Mat image(600, 600, CV_8UC3);
RNG& rng = theRNG();
while (1) {
//参数初始化
int count = rng.uniform(3, 103);//随机生成的点的个数
vector<Point> points;
//随机生成点的坐标
for (int i = 0; i < count; i++) {
Point point;
point.x = rng.uniform(image.cols / 4, image.cols * 3 / 4);
point.y = rng.uniform(image.rows / 4, image.rows * 3 / 4);
points.push_back(point);
}
//对给定的二维点集寻找最小面积包围的矩形
//RotatedRect box = minAreaRect(Mat(points));//返回最小旋转矩形
//Point2f vertex[4];//用于存储矩形四个顶点
//box.points(vertex);
//对给定的2D点集,寻找最小面积的包围圆
Point2f center;
float radius = 0;
minEnclosingCircle(Mat(points), center, radius);//得到最小圆的圆心和半径
//绘制出随机颜点
image = Scalar::all(0);
for (int i = 0; i < count; i++)
circle(image, points[i], 3, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), FILLED, LINE_AA);
//绘出最小面积包围的矩形
//for (int i = 0; i < 4; i++)
// line(image, vertex[i], vertex[(i + 1) % 4], Scalar(100, 200, 255), 2, LINE_AA);
//绘出最小面积包围的圆
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
circle(image, center, cvRound(radius), color, 2, LINE_AA);
//显示窗口
imshow("矩形包围示例", image);
//按下ESC,Q或q键,程序退出
char key = (char)waitKey(0);
if (key == 27 || key == 'Q' || key == 'q') {
break;
}
}
return 0;
}
运行结果:
三、综合实例:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
#define WINDOW_NAME1 "原始图窗口"
#define WINDOW_NAME2 "外包矩形效果图窗口"
#define WINDOW_NAME3 "外包圆效果图窗口"
//定义一些全局变量
Mat g_srcImage;
Mat g_grayImage;
int g_nThresh = 50;
int g_nMaxThresh = 255;
RNG g_rng(12345);
void on_ContoursChange(int, void*);
int main() {
system("color 1A");
g_srcImage = imread("1.jpg");
if (!g_srcImage.data) {
std::cout << "图片读入错误" << std::endl;
return false;
}
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
blur(g_grayImage, g_grayImage, Size(3, 3));
//创建原始图窗口并显示
namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
imshow(WINDOW_NAME1, g_srcImage);
//设置滚动条并调用一次回调函数
createTrackbar("阈值:", WINDOW_NAME1, &g_nThresh, g_nMaxThresh, on_ContoursChange);
on_ContoursChange(0, 0);
waitKey(0);
return(0);
}
void on_ContoursChange(int, void*) {
//定义一些参数
Mat threshold_output;
std::vector<std::vector<Point>> contours;
std::vector<Vec4i> hierarchy;
//使用Threshold检测边缘
threshold(g_grayImage, threshold_output, g_nThresh, 255, THRESH_BINARY);
//用二值图像找出轮廓
findContours(threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
//多边形逼近轮廓+获取矩形和圆形边界框
std::vector<std::vector<Point>> contours_poly(contours.size());
std::vector<Rect> boundRect(contours.size());//轮廓数量个外包矩形
std::vector<Point2f> center(contours.size());//轮廓数量个圆心
std::vector<float> radius(contours.size());//轮廓数量个半径
//一个循环,遍历所有部分,进行本程序最核心的操作
for (unsigned int i = 0; i < contours.size(); i++) {
approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);//用指定精度逼近多边形曲线
boundRect[i] = boundingRect(Mat(contours_poly[i]));//计算点集的最外面矩形边界
minEnclosingCircle(contours_poly[i], center[i], radius[i]);//对给定的2D点集,寻找最小面积的包围圆形
}
//绘制多边形轮廓+包围框+圆形框
Mat drawing1 = g_srcImage.clone();
Mat drawing2 = g_srcImage.clone();
for(unsigned int i = 0; i < contours.size(); i++) {
Scalar color = Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255));
drawContours(drawing1, contours_poly, i, color, 1, 8, std::vector<Vec4i>(), 0, Point());
drawContours(drawing2, contours_poly, i, color, 1, 8, std::vector<Vec4i>(), 0, Point());
rectangle(drawing1, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0);//绘制矩形
circle(drawing2, center[i], (int)radius[i], color, 2, 8, 0);//绘制圆
}
//显示效果图
namedWindow(WINDOW_NAME2, WINDOW_AUTOSIZE);
imshow(WINDOW_NAME2, drawing1);
namedWindow(WINDOW_NAME3, WINDOW_AUTOSIZE);
imshow(WINDOW_NAME3, drawing2);
}
效果图: