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

来源:互联网 发布:珠海金山软件招聘 编辑:程序博客网 时间:2024/05/16 18:49

凸包(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_EXTERNALRETR_LISTRETR_CCOMPRETR_TREE@第五个参数,int类型的method,为轮廓的近似办法,取值有CHAIN_APPROX_NONECHAIN_APPROX_SIMPLECHAIN_APPROX_TC89_L1CHAIN_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时,此标志被忽略

三、应用举例

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

//-------------------------------------【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

阅读全文
0 0
原创粉丝点击