花老湿学习OpenCV:轮廓周围绘制矩形框和圆形框

引言

在实际应用中,常常会有将检测到的轮廓用多边形表示出来的需求。这里为大家讲解如何用多边形表示出轮廓,或者说如何根据轮廓提取出多边形。

API:

approxPolyDP ()主要功能是把一个连续光滑曲线折线化,对图像轮廓点进行多边形拟合。

原理图:对比之前黑点连线,之后蓝色连线:

 

boundingRect()函数计算并返回指定点集最外面的矩形边界。

 

minEnclosingCircle()函数利用一种迭代算法,对给定的2D点集,去寻找面积最小的可包围它们的圆形。

 

minAreaRect()函数对于给定的2D点集,寻找可旋转的最小面积的包围矩形。

 

fitEllipse()函数用椭圆拟合二维点集。

 

代码示例: 

1.通过移动滑动块控制生成随机点的数量,对于生成的随机点的点集,寻找最外面的矩阵边界、面积最小的可包围它们的圆形、

可旋转的最小面积的包围矩形,用椭圆拟合二维点集。

#include "pch.h"
#include <iostream>
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

int pointNum = 50;
int pointMax = 100;
void PolyBound_demo(int pos, void* userdata);
RNG rng(getTickCount());
int mode = 0;
int main()
{
	namedWindow("PolyBound", WINDOW_AUTOSIZE);
	createTrackbar("pointNum", "PolyBound", &pointNum, pointMax, PolyBound_demo);
	createTrackbar("mode", "PolyBound", &mode,1, PolyBound_demo);
	setTrackbarMin("pointNum", "PolyBound", 5);
	PolyBound_demo(pointNum, 0);
	waitKey(0);

}

void PolyBound_demo(int pos, void* userdata)
{
	Mat img = Mat::zeros(Size(500, 500), CV_8UC3);
	//产生随机点并绘制
	vector<Point> points;
	for (int i = 0; i < pointNum; i++)
	{
		Point point;
		point.x = rng.uniform(img.cols / 4, img.cols * 3 / 4);
		point.y = rng.uniform(img.rows / 4, img.rows * 3 / 4);
		points.push_back(point);
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		circle(img, point, 2, color , FILLED, LINE_AA);
	}


	if (mode == 0)  
	{
		//对于以上生成的点集,寻找最外面的矩形边界
		Rect poly_rect = boundingRect(points);
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		rectangle(img, poly_rect, color, 2, LINE_AA);
		//对给定的2D点集,去寻找面积最小的可包围它们的圆形
		Point2f center;
		float radius;
		minEnclosingCircle(points, center, radius);
		color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		circle(img, center, radius, color, 2, LINE_AA);
	}
	else
	{
		//对于给定的2D点集,寻找可旋转的最小面积的包围矩形
		RotatedRect poly_rotateRect  =minAreaRect(points);
		Point2f pts[4];
		poly_rotateRect.points(pts);
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		for (int i = 0; i < 4; i++)
		{		
			line(img, pts[i], pts[(i + 1) % 4], color, 2, LINE_AA);
		}
		//用椭圆拟合二维点集
		RotatedRect poly_ellipse = fitEllipse(points);
		color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		ellipse(img, poly_ellipse, color, 2, LINE_AA);
	}
	imshow("PolyBound", img);
}

代码中出现void cv::RotatedRect::points(Point2f pts[]) const介绍如下:

效果如下:

2.创建包含轮廓的边界:

代码示例:

#include "pch.h"
#include <iostream>
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

int thresholdVal = 86;
int thresholdMax = 255;
void PolyBound_demo(int pos, void* userdata);
RNG rng(getTickCount());
int contourmode = 0;
int ploymode = 0;
Mat src;
Mat blursrc;
int main()
{
	src = imread("F:\\visual studio\\Image\\hand4.jpg");
	if (src.empty())
	{
		cout << "Can't load the image " << endl;
	}
	resize(src, src, Size(), 0.5, 0.5);
	
	//扩大图像的边界易于边框显示
	copyMakeBorder(src, src, 0, 50, 0, 0, BORDER_WRAP);
	imshow("src", src);
	Mat graysrc;
	cvtColor(src, graysrc, COLOR_BGR2GRAY);
	GaussianBlur(graysrc, blursrc, Size(5, 5),3,3);

	namedWindow("PolyBound", WINDOW_AUTOSIZE);
	createTrackbar("threshold", "PolyBound", &thresholdVal , thresholdMax, PolyBound_demo);
	createTrackbar("ploymode", "PolyBound", &ploymode, 1, PolyBound_demo);
	createTrackbar("contourmode", "PolyBound", &contourmode, 3, PolyBound_demo);
	
	PolyBound_demo(thresholdVal, 0);
	waitKey(0);

}

void PolyBound_demo(int pos, void* userdata)
{
	//阈值化
	Mat bin;
	threshold(~blursrc, bin, thresholdVal, thresholdMax, CV_THRESH_BINARY);
	imshow("bin", bin);

	//轮廓检测
	vector<vector<Point>> contours;
	vector<Vec4i> hiearchy;
	findContours(bin, contours, hiearchy, contourmode, CV_CHAIN_APPROX_SIMPLE, Point());

	//对图像轮廓点进行多边形拟合
	vector<vector<Point>> contours_ploy(contours.size());
	for (int i = 0; i < contours.size(); i++)
	{
		approxPolyDP(contours[i], contours_ploy[i], 3, true);
	}

	Mat dst;
	src.copyTo(dst);

	if (ploymode == 0)
	{
		for (int i = 0; i < contours_ploy.size(); i++)
		{
			//对于以上生成的点集,寻找最外面的矩形边界
			Rect poly_rect = boundingRect(contours_ploy[i]);
			Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
			rectangle(dst, poly_rect, color, 2, LINE_AA);
			//对给定的2D点集,去寻找面积最小的可包围它们的圆形
			Point2f center;
			float radius;
			minEnclosingCircle(contours_ploy[i], center, radius);
			color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
			circle(dst, center, radius, color, 2, LINE_AA);
		}	
	}
	else
	{
		for (int i = 0; i < contours_ploy.size(); i++)
		{
			//对于给定的2D点集,寻找可旋转的最小面积的包围矩形
			RotatedRect poly_rotateRect = minAreaRect(contours_ploy[i]);
			Point2f pts[4];
			poly_rotateRect.points(pts);
			Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
			for (int i = 0; i < 4; i++)
			{
				line(dst, pts[i], pts[(i + 1) % 4], color, 2, LINE_AA);
			}
			//用椭圆拟合二维点集 至少需要有5个点
			if (contours_ploy[i].size() >= 5)
			{
				RotatedRect poly_ellipse = fitEllipse(contours_ploy[i]);
				color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
				ellipse(dst, poly_ellipse, color, 2, LINE_AA);
			}
		}
		
	}
	imshow("PolyBound", dst);
}

效果如下:

ploymode=0时,显示轮廓最外面的矩阵边界、面积最小的可包围轮廓的圆形:

contourmode=0时,只查找最外层的轮廓:

ploymode=1时,显示可旋转的最小面积的包围矩形,用椭圆拟合轮廓,注意:用椭圆拟合至少需要5个点。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值