OpenCV findContours函数边缘近似方法

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

再来看下findCountours的函数原型:

CV_EXPORTS_W void findContours(
InputOutputArray image, 
OutputArrayOfArrays contours,
OutputArray hierarchy, 
int mode,
int method, 
Point offset=Point());

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

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近似算法的一种。

我们用一个例子试一下:

#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方法,在修改下判断条件:

		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函数将二值化后图像白色区域当作前景,黑色部分当做背景。所以找轮廓找到的是白色区域的轮廓。这个函数有一个特点,如果白色区域延伸到了图像边界,那么图像的边界也是被当作轮廓的一部分,这就造成了可能会出现一个很大的外轮廓。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值