第29课 轮廓发现(find contour)

1. 轮廓发现(find contour)

  • 轮廓发现是基于图像边缘提取的基础寻找对象轮廓的方法。所以边缘提取的阈值选定会影响最终轮廓发现结果。
    在这里插入图片描述

2. 步骤

  1. 输入图像转为灰度图像cvtColor
  2. 使用Canny进行边缘提取,得到二值图像
  3. 使用findContours寻找轮廓
  4. 使用drawContours绘制轮廓

3.相关API

3.1寻找轮廓findCon tours()

二值图像上发现轮廓。

cv::findContours(

InputOutputArray  binImg, // 输入图像,非0的像素被看成1,0的像素值保持不变,8-bit

 OutputArrayOfArrays  contours,//  全部发现的轮廓对象,每个轮廓都是以点向量的形式进行存储即使用point类型的vector表示
 
OutputArray,  hierachy// 作为轮廓数量的表示hierarchy包含了很多元素,每个轮廓contours[i]对应hierarchy中hierarchy[i][0]~hierarchy[i][3],分别表示后一个轮廓,前一个轮廓,父轮廓,内嵌轮廓的索引,如果没有对应项,则相应的hierarchy[i]设置为负数。

int mode, //  轮廓返回的模式

int method,// 发现方法

Point offset=Point()//  轮廓像素的位移,默认(0, 0)没有位移
)

其中,

  • mode包括:
  1. RETR_EXTERNAL:表示只检测最外层轮廓,对所有轮廓设置hierarchy[i][2]=hierarchy[i][3]=-1
  2. RETR_LIST:提取所有轮廓,并放置在list中,检测的轮廓不建立等级关系
  3. RETR_CCOMP:提取所有轮廓,并将轮廓组织成双层结构(two-level hierarchy),顶层为连通域的外围边界,次层位内层边界
  4. RETR_TREE:提取所有轮廓并重新建立网状轮廓结构
  5. RETR_FLOODFILL:官网没有介绍,应该是洪水填充法
  • method包括:
  1. CHAIN_APPROX_NONE:获取每个轮廓的每个像素,相邻的两个点的像素位置差不超过1
  2. CHAIN_APPROX_SIMPLE:压缩水平方向,垂直方向,对角线方向的元素,值保留该方向的重点坐标,如果一个矩形轮廓只需4个点来保存轮廓信息
  3. CHAIN_APPROX_TC89_L1和CHAIN_APPROX_TC89_KCOS使用Teh-Chinl链逼近算法中的一种

3.2 绘制轮廓drawContours()

在二值图像上发现轮廓使用API cv::findContours之后对发现的轮廓数据进行绘制显示。

drawContours(
InputOutputArray  binImg, // 输出图像

 OutputArrayOfArrays  contours,//  全部发现的轮廓对象
 
Int contourIdx// 轮廓索引号,表示绘制第几个轮廓,如果为负值则绘制所有输入轮廓

const Scalar & color,// 绘制时候颜色

int  thickness,// 绘制线宽

int  lineType ,// 线的类型LINE_8

InputArray hierarchy,// 拓扑结构图

int maxlevel,// 最大层数, 0只绘制当前的,1表示绘制绘制当前及其内嵌的轮廓

Point offset=Point()// 轮廓位移,可选

4. 例程

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

using namespace cv;
using namespace std;
void CallBack(int, void*);
Mat src, dst;
int Threshold = 10;

int main() {
	
	//输入图像并转化为灰度
	src = imread("D:/resource/images/轮廓图.jpg");
	if (src.empty()) printf("src  couldn't be loaded...");
	imshow("input", src);
	cvtColor(src, src, COLOR_BGR2GRAY);

	//设置阈值后执行CallBack()
	namedWindow("output");
	createTrackbar("Threshold", "output", &Threshold, 255, CallBack);
	CallBack(0, 0);

	waitKey(0);
	return 0;
}

void CallBack(int, void*) {

	//边缘检测
	
	Mat CannyOutput;
	Canny(src, CannyOutput, Threshold, Threshold * 2, 3, false);

	//寻找边缘
	vector<vector<Point>> contours;
	vector<Vec4i> hierachy;
	findContours(CannyOutput, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

	//画出所有边缘
	dst = Mat::zeros(src.size(), CV_8UC3);
	RNG rng(12345);
	for (size_t i = 0; i < contours.size(); i++)
		drawContours(dst, contours, i, Scalar(rng.uniform(0,255), rng.uniform(0, 255), rng.uniform(0, 255)), 1, LINE_8, Mat());
	imshow("output", dst);
	cout << contours.size()<<endl;
		

}

在这里插入图片描述

发布了31 篇原创文章 · 获赞 12 · 访问量 2754

猜你喜欢

转载自blog.csdn.net/weixin_42877426/article/details/104378448
今日推荐