c++opencv Chapter 7 - Shapes or Contour Detection

结果图:

在介绍形状特征提取之前,先了解几个特征提取的重要函数。

/* 寻找特征函数
findContours( InputOutputArray image, OutputArrayOfArrays contours,
							  OutputArray hierarchy, int mode,
							  int method, Point offset=Point());

*/
/*
image:图像必须是8位单通道图像,可以是灰度图像,但更常用的是二值图像,一般是经过Canny,拉普拉斯等边缘检测算子处理过的二值图像;(函数运行时,这个图像会被直接涂改,因此如果是将来还有用的图像,应该复制之后再传给该函数)
contours:定义为vector<vector<Point>> contours;向量,向量内每个元素保存了一组由连续的Point点构成的点的集合的向量,每一组Point点集就是一个轮廓,有多少轮廓,向量contours就有多少元素;
hierarchy:定义为vector<Vec4i> hierarchy;,表示向量内每一个元素包含了4个int型变量——hierarchy[i][0] —hierarchy[i][3],分别表示第i个轮廓的后一个轮廓、前一个轮廓、第一条子轮廓、父轮廓的索引编号,如果当前轮廓没有对应的后一个轮廓,前一个轮廓、第一条子轮廓或父嵌轮廓的话,则hierarchy[i][0] —hierarchy[i][3]的相应位被设置为默认值-1;
mode:轮廓提取方式
○ cv::RETR_EXTERNAL:只检测最外围轮廓;
○ cv::RETR_LIST:检测所有的轮廓,但是不建立等级关系;
○ cv::RETR_CCOMP:检测所有的轮廓,但所有轮廓只建立两种等级关系,外围为顶层
○ cv::RETR_TREE:检测所有的轮廓,所有轮廓建立一个等级树结构
method:轮廓的近似方法
○ CV_CHAIN_APPROX_NONE:保存物体边界上所有连续的轮廓点到contours向量中
○ CV_CHAIN_APPROX_SIMPLE:仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存到contours向量中
Point:偏移量,默认为(0,0)没有偏移							
*/
/*绘制轮廓函数
drawContours(InputOutputArray image, InputArrayOfArrays contours,
int contourIdx, const Scalar& color, int thickness=1, int lineType=8,
InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )
image:待绘制轮廓的图像;
contours:要绘制的轮廓组,与findContours中输出的contours相同;
contourIdx:指明画第几个轮廓,如果该参数为负值(通常设为-1),则画全部轮廓,
color:指定绘制的颜色或亮度(灰度图像),如scalar(255,0,255)
thickness:指定线段的宽度
lineType:边框线型,可以是4或8,4代表绘制的线是四连通线(不美观),8代表绘制的线是八连通线(较美观)
hierarchy:对应findContours中输出的hierarchy
maxLevel:限制将在图上绘制的轮廓层次深度,为0表示只绘制“第0层”,以此类推
offset:偏移量,默认为(0,0)没有偏移
*/
/*
approxPolyDP函数
函数的作用:
对图像轮廓点进行多边形拟合

2、函数的调用形式
C++: void approxPolyDP (InputArray curve, OutputArray approxCurve, double epsilon, bool closed)

参数详解;

InputArray curve:一般是由图像的轮廓点组成的点集

OutputArray approxCurve:表示输出的多边形点集

double epsilon:主要表示输出的精度,就是另个轮廓点之间最大距离数,5,6,7,,8,,,,

bool closed:表示输出的多边形是否封闭

*/
/*1.cv2.boundingRect()
能够返回包围轮廓的矩形的边界信息。

函数样式:retval = cv2.boundingRect(array)

参数介绍:

retval 表示返回矩形边界左上角顶点的坐标值及矩形边界的宽和高 , 也可以是4个返回值形式

x, y, w, h = cv2.boundingRect(array)

array 是灰度图像或轮廓

然后使用函数cv2.drawContours()来绘制矩形包围框。*/

具体实现:

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace std;
using namespace cv;


void getContours(Mat imgDil, Mat img) {
	vector<vector<Point>> contours;
	vector<Vec4i> hierarchy;

	findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	//drawContours(img, contours, -1, Scalar(255, 0, 255),2);

	vector<vector<Point>>conPoly(contours.size());
	vector<Rect>boundRect(contours.size());


	//排除干扰
	for (int i = 0;i < contours.size();i++) {
		//计算轮廓面积 
		int area = contourArea(contours[i]);
		string objectType;
		cout << area << endl;
		if (area > 1000) {
			//arcLength(contours[i], true);计算轮廓周长  
			//InputArray类型的curve,输入的向量,二维点(轮廓顶点),可以为std::vector或Mat类型。
			//bool类型的closed,用于指示曲线是否封闭的标识符,一般设置为true。
			float peri = arcLength(contours[i], true);
			//对图像轮廓点进行多边形拟合
			approxPolyDP(contours[i], conPoly[i], 0.02 * peri, true);
			cout << conPoly[i].size() << endl;
			// 表示返回矩形边界左上角顶点的坐标值及矩形边界的宽和高
			boundRect[i] = boundingRect(conPoly[i]);
			//得到特征点
			int objCor = (int)conPoly[i].size();
			//判断图像
			if (objCor == 3) {
				objectType = "Tri";
			}
			if (objCor == 4) {
				float aspRatio = (float)boundRect[i].width / (float)boundRect[i].height;
				cout << aspRatio << endl;
				if (aspRatio > 0.95 && aspRatio < 1.05) {
					objectType = "Square";
				}
				else objectType = "Rect";
			}
			if (objCor > 4) {
				objectType = "Circle";
			}
			//绘制轮廓
			drawContours(img, contours, i, Scalar(255, 0, 255), 2);
			//绘制矩形框
			rectangle(img, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 5);
			//输出判断文本图像
			putText(img, objectType, { boundRect[i].x,boundRect[i].y - 5 },FONT_HERSHEY_PLAIN,1,Scalar(0, 69, 255), 2);

		}
	}
}

int main() {
	string path = "Learn-OpenCV-cpp-in-4-Hours-main\\Resources\\shapes.png";
	Mat img = imread(path),imgGray,imgBlur,imgCanny,imgDil;
	if (img.empty()) {
		printf("could not load image...\n");
		return 0;
	}

	//Preprocessing 预处理
	cvtColor(img, imgGray, COLOR_BGR2GRAY);
	GaussianBlur(imgGray, imgBlur, Size(3, 3), 3, 0);
	Canny(imgBlur, imgCanny, 25, 75);
	Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
	dilate(imgCanny, imgDil, kernel);
	imshow("Image", img);

	getContours(imgDil, img);
	imshow("Image Cont",img);
	waitKey(0);
	destroyAllWindows();
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值