轮廓周围绘制矩形和圆形框

1、API介绍;
2、代码演示;

相关API

1、轮廓线拟合API: approxPolyDP():
curve : 输入多边形;curve : 曲线
approxCurve : 输出拟合后的多边形(轮廓点数减少)
epsion : 两点之间的最小距离;
closed : 形成的多边形是否封闭;
基于RDP算法原理实现;


2、最小矩形API : cv::boundingRect() : 得到轮廓周围的最小矩形左上交点和右下交点坐标(坐标位置注意),绘制一个矩形;通过函数返回值返回;
3、旋转矩形API : cv::minAreaRect() : 得到包含轮廓的旋转矩形;

4、轮廓最小区域圆形绘制API : cv::minEnclosingCircle(); enclosing : 封闭的,包卷的
5、轮廓最小区域椭圆绘制API : cv::fitEllipse();

使用方法

1、将图像转换为二值图像;
2、发现轮廓,找到轮廓图像;
3、通过相关API在轮廓点上找到最小包含矩形和圆,旋转矩形和椭圆;
4、绘制;

Code

说明:1、 关键是approxPolyDP()的使用,可以有效减少轮廓中的点,更便于进行图像轮廓的绘制;2、注意旋转椭圆和旋转矩形在拟合后的轮廓点少于5个是无法绘制,必须排除这种情况;

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

Mat src, gray_src, drawImg;
int threshold_v = 124;
int threshold_max = 255;

RNG rng(12345);

const char* OUTPUT_WIN = "rectangle demo";
const char* INPUT_WIN = "input image";

void Contours_CallBack(int, void *);

int main(int argc, char** argv)
{
   
	src = imread("C:\\Users\\hello\\Desktop\\38.jpg");
	if (!src.data)
	{
   
		cout << "could not load the image..." << endl;
		return -1;
	}
	cvtColor(src, gray_src, CV_BGR2GRAY);
	blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);  //均值模糊

	namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
	namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
	imshow(INPUT_WIN, gray_src);

	createTrackbar("Threshold value :", INPUT_WIN, &threshold_v, threshold_max, Contours_CallBack, 0);
	Contours_CallBack(threshold_v, 0);


	waitKey(0);
	return 0;
}

void Contours_CallBack(int, void *)
{
   
	//回调函数实现 自适应阈值API可以将灰度图像直接转换为二值图像
	Mat binary_output;
	//图像阈值处理
	threshold(gray_src, binary_output, threshold_v, threshold_max, THRESH_BINARY);

	vector<vector<Point>> contours;
	vector<Vec4i> hierarchy;
	//寻找二值图像上的轮廓
	findContours(binary_output, contours, RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(-1, -1));
	imshow("binary image", binary_output);

	//注意: 必须初始化,否则会报数组越界错误
	vector<vector<Point>> contour_ploy(contours.size());  //外接多边形
	vector<Rect> ploy_rect(contours.size());
	vector<Point2f> ccs(contours.size());  //圆心
	vector<float> radius(contours.size());

	vector<RotatedRect> minRects(contours.size());
	vector<RotatedRect> mEllipse(contours.size());
	for (size_t i = 0; i < contours.size(); i++)
	{
   
		approxPolyDP(contours[i], contour_ploy[i], 3, true);  //多边形轮廓拟合
		ploy_rect[i] = boundingRect(contour_ploy[i]);  //计算结果通过返回值返回
		minEnclosingCircle(contour_ploy[i], ccs[i], radius[i]);  //计算轮廓拟合圆
		//注意: 多变形轮廓拟合后的点可能少于5个,此时不能拟合椭圆,旋转矩形,需要单独判断
		if (contour_ploy[i].size() > 5)
		{
   
			mEllipse[i] = fitEllipse(contour_ploy[i]);   //计算轮廓拟合椭圆 
			minRects[i] = minAreaRect(contour_ploy[i]);  //计算轮廓拟合旋转矩形
		}
	}
	//绘制包含轮廓的矩形和圆
	//src.copyTo(drawImg);
	drawImg = Mat::zeros(src.size(), src.type()); //可以选择拷贝原图,还是创建黑色背景图形
	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_rect[t], color, 2, LINE_8);
		//circle(drawImg, ccs[t], radius[t], color, 2, LINE_8);
		if (contour_ploy[t].size() > 5)
		{
   
			ellipse(drawImg, mEllipse[t], color, 2, LINE_8);
			minRects[t].points(pts);   //将旋转矩形的四个坐标提取到pts中
			//旋转矩形只能通过画直线的方式来完成绘制 , 取模的操作保证画线闭合!!!
			for (int r = 0; r < 4; r++)
			{
   
				line(drawImg, pts[r], pts[(r + 1) % 4], color, 2, LINE_8);
			}
		}

	}
	imshow(OUTPUT_WIN, drawImg);

	return;
}

效果

1、原图:(阈值发现124最合适)

2、二值图像:

3、绘制图像: