您的位置:首页 > 编程语言 > C语言/C++

OpenCV教程 之 寻找物体的轮廓与凸包:findContours、convexHull函数(C++)

2017-11-18 23:12 573 查看
凸包(Convex Hull)是一个计算几何中常见的概念,简单来说,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它能包含点集中所有点,理解物体形状轮廓的一种比较有用的方法便是计算一个物体的凸包,然后计算其凸缺陷。很多复杂物体的性能能被这种缺陷表示出来

一、寻找轮廓:findContours()函数

一个轮廓一般对应着一系列的点,也就是图像中的一条曲线,在OpenCV中,可以用findContours()函数从二值图像中查找轮廓,我们先来看一下这个函数的函数原型

void findContours(InputOutArray image,OutputArrayOfArrays contours,outputArray hierarchy,int method,Point offset = Point())

@第一个参数,InputArray类型的image,输入图像,即源图像,填Mat类对象即可,且需为8位单通道图像
@第二个参数,OutputArrayOfArrays类型的contours,检测到的轮廓、函数调用后的运算结果存在这里。每一个轮廓存储为一个点向量,即用point类型的vector表示
@第三个参数,outputArray类型的hierarchy,可选的输出量,包含图像的拓扑信息
@第四个参数,int类型的mode,轮廓检索模式,取值有RETR_EXTERNAL、RETR_LIST、RETR_CCOMP、RETR_TREE
@第五个参数,int类型的method,为轮廓的近似办法,取值有CHAIN_APPROX_NONE、CHAIN_APPROX_SIMPLE、CHAIN_APPROX_TC89_L1、CHAIN_APPROX_TC89_KCOS
@第六个参数,Point类型的offset,每个轮廓点的可选偏移量,有默认值Point()


举个栗子

vector<vector<Point>> contours;
findContours(image,countours,CV_RETR_EXTERNAL,CV_CHAIN_APROX_NONE)


二、绘制轮廓:drawContours()函数

findContours经常与drawContours配合使用,在使用findContours()函数检测到图像的轮廓以后,便可以用drawContours()函数将检测到的轮廓绘制出来,该函数的函数原型如下:

void 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())

@第一个参数,InputArray类型的image,输入图像,即源图像,填Mat类对象即可
@第二个参数,OutputArrayOfArrays类型的contours,所有的输入轮廓。每一个轮廓存储为一个点向量,即用point类型的vector表示
@第三个参数,int类型的contourIdx,轮廓绘制的指示变量。如果其为负值,则绘制所有轮廓
@第四个参数,constScalar&类型的color,轮廓的颜色
@第五个参数,int thickness,轮廓线条的粗细,有默认值1
@第六个参数,int类型的lineType,线条的类型,有默认值8
@第七个参数,InputArray类型的hierarchy,可选的层次结构信息,有默认值noArray()
@第八个参数,int类型的maxLevel,表示用于绘制轮廓的最大等级,有默认值INT_MAX
@第九个参数,Point类型的offset,可选的轮廓偏移参数,默认为Point()


举个栗子:

使用下图作为原图像



//在白色图像上绘制黑色轮廓
Mat result(image.size(),CV_8U,CV::Scalar(255));
drawContours(result,contours,-1,Scalar(0),3);


二、convexHull函数

首先来介绍一下OpenCV中的这个凸包检测函数

void convexHull(InputArray points,OutputArray hull,bool clockwise = false,bool returnPoints = true)

@第一个参数,InputArray类型的Points,输入的二维点集,可以填Mat类型或者std::vector
@第二个参数,OutputArray类型的Hull,输出参数,函数调用后找到的凸包
@第三个参数,bool类型的clockwise,操作方向标识符。当此标志符为真时,输出的凸包为顺时针方向,否则就为逆时针方向。并且是假定坐标系的x轴指向右,y轴指向上方
@第四个参数,bool类型的returnPoints,操作符标识,默认为true。当标识符为真时,函数返回各个凸包的各个点。否则,它返回凸包各点的指数。当输出数组是std::vector时,此标志被忽略


三、应用举例

结合上面介绍的三个函数,我们来尝试一个完整的使用案例

//-
4000
------------------------------------【head file\namesapce declaration】------------------------------
//                         statement:  declare head file and namespace
//-----------------------------------------------------------------------------------------------------
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
typedef vector<Point> vec;

//-------------------------------------【public Variables】---------------------------------------------
//                         statement:  declare global variables
//-----------------------------------------------------------------------------------------------------
Mat g_srcImage,g_grayImage;
int g_nThresh = 50;
int g_maxThresh = 255;
RNG g_rng(12345);
Mat srcImage_copy;
Mat g_thresholdImage_ouput;
vector<vec> g_vContours;
vector<Vec4i> g_vHierarchy;

//-------------------------------------【public function】---------------------------------------------
//                         statement:  declare global function
//-----------------------------------------------------------------------------------------------------
static void on_ThreshChange(int,void*);

//--------------------------------------【main()function】----------------------------------------------
//                          statement:    our code run from here
//-----------------------------------------------------------------------------------------------------
int main(int argc,char *argv[]){
g_srcImage = imread("/Users/zhuxiaoxiansheng/Desktop/xiaoxin.jpg",1 );
cvtColor(g_srcImage,g_grayImage,COLOR_BGR2GRAY);
blur(g_grayImage,g_grayImage,Size(3,3));

namedWindow("srcIamge");
imshow("srcImage",g_srcImage);
waitKey();

namedWindow("show");
createTrackbar("ThresholdValue:","show",&g_nThresh,g_maxThresh,on_ThreshChange);
on_ThreshChange(0,0);

waitKey();
return(0);

}

//----------------------------------【thresh_callback() function】--------------------------------------
//                          statement:    Thresh's help function
//-----------------------------------------------------------------------------------------------------
static void on_ThreshChange(int,void*){
threshold(g_grayImage,g_thresholdImage_ouput,g_nThresh,255,THRESH_BINARY);
findContours(g_thresholdImage_ouput,g_vContours,g_vHierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point(0,0));

vector<vec> hull(g_vContours.size());
for(unsigned int i =0;i < g_vContours.size();i++)
convexHull(Mat(g_vContours[i]),hull[i],false);

Mat drawing = Mat::zeros(g_thresholdImage_ouput.size(),CV_8UC3);
for(unsigned int i = 0;i<g_vContours.size();i++){
Scalar color = Scalar(g_rng.uniform(0,255),g_rng.uniform(0,255),g_rng.uniform(0,255));
drawContours(drawing,g_vContours,i,color,1,8,vector<Vec4i>(),0,Point());
drawContours(drawing,hull,i,color,1,8,vector<Vec4i>(),0,Point());
}
imshow("show",drawing);

}


效果如下:



这里有更完整的代码介绍:

https://github.com/LiangjunFeng/Implement-OpenCV
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息