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;
}

运行结果:

OpenCV3之——使用多边形将轮廓包围

 

OpenCV3之——使用多边形将轮廓包围

 

二、创建包围轮廓的圆形边界

//在上面示例的基础上加以修改

#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;
}


运行结果:

OpenCV3之——使用多边形将轮廓包围

OpenCV3之——使用多边形将轮廓包围

 三、综合实例:

#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);
}

效果图:

OpenCV3之——使用多边形将轮廓包围

OpenCV3之——使用多边形将轮廓包围