前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >OpenCV findContours函数边缘近似方法

OpenCV findContours函数边缘近似方法

作者头像
chaibubble
发布2022-05-07 09:30:06
5000
发布2022-05-07 09:30:06
举报
文章被收录于专栏:深度学习与计算机视觉

在使用OpenCV的过程中,findcontours是相对使用比较多的,在之前的博客中,介绍了vector<vector<Point> > contours容器: http://blog.csdn.net/chaipp0607/article/details/52858661 查找轮廓时内轮廓与外轮廓: http://blog.csdn.net/chaipp0607/article/details/53765440

再来看下findCountours的函数原型:

代码语言:javascript
复制
CV_EXPORTS_W void findContours(
InputOutputArray image, 
OutputArrayOfArrays contours,
OutputArray hierarchy, 
int mode,
int method, 
Point offset=Point());

其中第五个参数为轮廓的边缘近似方法,说白了就是放在contours中的一堆点,到底以一个怎样的方式把轮廓表征出来,定义如下

代码语言:javascript
复制
enum
{
    CHAIN_APPROX_NONE=CV_CHAIN_APPROX_NONE,
    CHAIN_APPROX_SIMPLE=CV_CHAIN_APPROX_SIMPLE,
    CHAIN_APPROX_TC89_L1=CV_CHAIN_APPROX_TC89_L1,
    CHAIN_APPROX_TC89_KCOS=CV_CHAIN_APPROX_TC89_KCOS
};

依次为: 1为能够包围轮廓的所有的点; 2为压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分; 3,4为使用the flavors of Teh-Chin chain近似算法的一种。

我们用一个例子试一下:

代码语言:javascript
复制
#include <iostream>  
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/ml/ml.hpp>  
#include <time.h>
#include<ctime>
#include <opencv/cv.h> 
#include <opencv2/opencv.hpp>  
#include <stdio.h> 
#include<math.h>

using namespace cv;  
using namespace std;  

int main()
{	
	Mat SrcImage;
	Mat ResizeImage;
	Mat grayImage;
	Mat thresholdImage;
	Mat  roiimage;
	Mat  SrcroiImage;
	SrcImage = imread("2_000_0.bmp");
	Size dsize = Size(SrcImage.cols*0.2,SrcImage.rows*0.2);
	resize(SrcImage, ResizeImage,dsize);
	SrcroiImage = ResizeImage(Rect(ResizeImage.cols/3,ResizeImage.rows/3,ResizeImage.cols/3,ResizeImage.rows/3));
	cvtColor(SrcroiImage,grayImage,CV_BGR2GRAY);
	threshold(grayImage,thresholdImage, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);
	vector<vector<Point> > contours;
	vector<Vec4i>hierarchy;
	findContours(thresholdImage,contours,hierarchy,CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE);  
	for(int k = 0; k < (int)contours.size(); k++)    //查找轮廓
	{
		if (contours.at(k).size()>30&&contours.at(k).size()<50)
		{
			drawContours(SrcroiImage, contours, k, Scalar(255,0,0), CV_FILLED);
		}
		if (contours.at(k).size()>50)
		{
			drawContours(SrcroiImage, contours, k, Scalar(0,255,0), CV_FILLED);
		}
	}
	imshow("兴趣区域二值化",thresholdImage);
	imshow("兴趣区域原图",SrcroiImage);
	waitKey(0);
	getchar();
	return 0;
}

这是截取出来的待检测的图像,我们对它进行轮廓查找,验证一下:

这里写图片描述
这里写图片描述

首先用CV_CHAIN_APPROX_SIMPLE的方法,在for循环中,我们把包围轮廓的点个数作为判断条件,个数大于30个且小于50个是,把这个轮廓在原图中涂成蓝色,而大于50时,涂成绿色,运行结果如下:

这里写图片描述
这里写图片描述

可以看到,中间的兴趣区域的面积明显是要大于右下角的三角形面积的,但是包围它的轮廓的点的个数确要小于三角形的区域,这是因为中间的区域非常接近于矩形,区域规则时只需要很少的点就可以将它描绘出来。

然后我们将CV_CHAIN_APPROX_SIMPLE方法换成CV_CHAIN_APPROX_NONE方法,在修改下判断条件:

代码语言:javascript
复制
		if (contours.at(k).size()>30&&contours.at(k).size()<100)
		{
			drawContours(SrcroiImage, contours, k, Scalar(255,0,0), CV_FILLED);
		}
		if (contours.at(k).size()>100)
		{
			drawContours(SrcroiImage, contours, k, Scalar(0,255,0), CV_FILLED);
		}
		if (contours.at(k).size()>200)
		{
			drawContours(SrcroiImage, contours, k, Scalar(0,0,255), CV_FILLED);
		}
这里写图片描述
这里写图片描述

可以看到,此时的轮廓大小大概是和视觉看上去的面积大小成正比的。 最后补充一点: findcontours函数将二值化后图像白色区域当作前景,黑色部分当做背景。所以找轮廓找到的是白色区域的轮廓。这个函数有一个特点,如果白色区域延伸到了图像边界,那么图像的边界也是被当作轮廓的一部分,这就造成了可能会出现一个很大的外轮廓。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-03-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档