c++opencv Chapter 7 - Shapes or Contour Detection-程序员宅基地

技术标签: c++  c++ opencv  opencv  开发语言  

结果图:

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

/* 寻找特征函数
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();
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_50934329/article/details/138084455

智能推荐

JS(JavaScript)详解-程序员宅基地

文章浏览阅读7k次,点赞7次,收藏37次。JavaScript是由Netscape(网景)公司研发出来的一种在它的Navigator浏览器上执行的程序语言。JavaScript是一种基于对象(object-based)和事件驱动(Event Driven)的简单的并具有安全性能的脚本语言。JavaScript组成ECMAScript:JavaScript的核心,语法格式,使用方法文档对象模型(DOM,document object model):DOM(文档对象模型)是 HTML 和 XML 的应用程序接口(API)。_js

最好用的caffe深度学习简单批处理数据集(windows+linux+Python)_win linux 深度学习 数据集-程序员宅基地

文章浏览阅读395次。简单的批处理方式,包含了windows系统下的bat文件,Linux系统下的sh文件以及最牛逼的Python脚本。在进行AI相关的研究时,不可避免的需要去进行处理数据集。有些数据集是现成的,有些数据集却是需要自己去定制的。以下是自己在学习的过程中总结出来的比较常见的几种方式去处理数据。因为做的是CV,所以设计的处理方式多是处理图片。一、windows下的bat1、统计每个文件夹的名称以及相应文..._win linux 深度学习 数据集

8hutool实战:ChineseDate(农历日期工具类)_hutool chinesedate-程序员宅基地

文章浏览阅读1.3w次,点赞17次,收藏9次。hutool实战:农历日期工具,最大支持到2055年,支持:- 通过公历日期构造获取对应农历- 通过农历日期直接构造关键字:java java JAVA hutool hutool Hutool 工具类 工具类 工具类 DateUtil DateUtil DateUtil_hutool chinesedate

30道python自动化测试面试题-程序员宅基地

文章浏览阅读1.4w次,点赞28次,收藏405次。30道python自动化测试面试题,让你的面试过程比德芙还丝滑~_python自动化测试面试题

vi光标移动_vi移动光标-程序员宅基地

文章浏览阅读3.4k次。hjkl,前后左右,加数字代表重复执行,如3j表示下移3行^:移动光标到行首;$:移动光标到行尾;ctrl-b: 上翻一页ctrl-f:下翻一页_vi移动光标

一文带你通俗理解23种软件设计模式(推荐收藏,适合小白学习,附带C++例程完整源码)-程序员宅基地

文章浏览阅读4.3w次,点赞33次,收藏236次。一文带你通俗理解23种软件设计模式(推荐收藏,适合小白学习,附带C++例程完整源码)_软件设计模式

随便推点

关于生产者消费者模式的C#实现_c#生产者消费者模式-程序员宅基地

文章浏览阅读9.7k次,点赞14次,收藏83次。今天是圣诞节,大家 Merry Chrismas~以前都是在C++项目中写界面,现在接触了C#感觉比MFC和QT好用多了,决定以后除了特殊要求外都用C#开发:)。记录一下用C#实现生产者消费者模式吧。先介绍一下这个模式,简而言之就是生产者(可能有数个)生产东西,消费者(可能有数个)消费前面生产的东西。举个生活中的例子就是苹果有好几个厂家(生产者)生产iphone,线下线上的购买者(消费者)通过..._c#生产者消费者模式

如何在linux搭建airtest+chromeweb测试环境--(用命令行运行.air脚本)-程序员宅基地

文章浏览阅读806次。大前堤:如果你需要airtest提供的可视化测试报告,那你的操作系统,一定要有图形化界面.否则运行你的airtest脚本 会遇到这样的问题Xlib.error.DisplayNameError: Bad display name ""你可能百度之后 遇到了xhost +命令执行这个命令后,再运行测试脚本,又遇到这个问题然后再百度,原来.Xauthority X..._linux +airtest

ros介绍-程序员宅基地

文章浏览阅读1.5k次。ROS是什么?ROS 历史起源ROS 发展背景问题:机器人跨学科特点,系统庞大,工程应用涉及面广,硬件繁多,软件开发困难、低级重复基础:机器人研究相关领域发展迅速:计算机视觉,异构计算加速,室内移动机器人算法的成熟等等需求:机器人研究过程中需要统一开发/测试平台解决方法:机器人软件中间件ROS总体设计一个目标提高机器人开发中的代码复用率五个特点免费且开源BSD许..._ros

Faster R-CNN roi_pooling_layer 浅析_psroi_pooling_layer not implemented yet-程序员宅基地

文章浏览阅读3.3k次。阅读完 R-CNN一系列论文之后,开始看源代码。本文简要记录自己对roi_pooling_layer源码的理解。作者首先在caffe.proto中添加该层参数说明,主要是三个变量 optional ROIPoolingParameter roi_pooling_param = 43; message ROIPoolingParameter {// Pad, kernel size, and str_psroi_pooling_layer not implemented yet

刷题笔记7——输出斐波那契数列的第n项_输出斐波拉契数列第n项r语言-程序员宅基地

文章浏览阅读793次。题目描述大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。n&lt;=391、递归class Solution {public: int Fibonacci(int n) { int num[39]; num[0] = 0; num[1] = 1; int cnt..._输出斐波拉契数列第n项r语言