OpenCV学习(30) 轮廓defects

     上一篇教程中,我们学习了如何计算轮廓的凸包,其实对一个轮廓而言,可能它的凸包和它本身是重合的,也有可能不是重合的。比如下面左边图像的轮廓本身就是凸包,而右边图像的轮廓则不是。我们可以通过函数bool isContourConvex(InputArray contour),来判定一个轮廓是否是凸包,是的话返回true,否则false[注意测试的轮廓必须是简单轮廓,没有自交叉之类的]。

      对一个非凸包的轮廓而言,它包括一系列的凹陷区域,这些区域称作defect,比如下面手轮廓中,包括6个defect区域。在OpenCV中,我们用下面的结构来定义defect。

struct CvConvexityDefect { CvPoint* start; // 轮廓中defect的起点 CvPoint* end; // 轮廓中defect的终点 CvPoint* depth_point; // defect中到凸包最远的点 float depth; // 最远点和凸包之间的距离};

 

 

    在OpenCV中,我们通过函数

void convexityDefects(InputArray contour, InputArray convexhull, OutputArray convexityDefects)

得到轮廓的凸包,其中第一个参数和第二个参数是轮廓以及轮廓对应的凸包,注意凸包应该使用vector<int>这样的索引方式表示。第三个参数为返回的defect点集。

 

下面我们看下检测轮廓defects的代码:

#include "opencv2/highgui/highgui.hpp"#include "opencv2/imgproc/imgproc.hpp"#include <iostream>#include <stdio.h>#include <stdlib.h>

using namespace cv;using namespace std;

Mat src; Mat src_gray;RNG rng(12345);

int main( int argc, char** argv ){//装入图像    src = imread("../hand1.jpg", 1 );

//转化为灰度图像    cvtColor( src, src_gray, CV_BGR2GRAY );//blur( src_gray, src_gray, Size(3,3) );    namedWindow( "image");    imshow( "image", src_gray );

Mat threshold_output;    vector<vector<Point> > contours;    vector<Vec4i> hierarchy;

//得到二值图    threshold( src_gray, threshold_output, 200, 255, THRESH_BINARY );

//查找轮廓    findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );    printf("轮廓数目:%d\n", contours.size());/// Find the convex hull object for each contour    vector<vector<Point> >hull( contours.size() );for( int i = 0; i < contours.size(); i++ )    {  convexHull( Mat(contours[i]), hull[i], false ); }

/// Draw contours + hull results    Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );int area = 0; //轮廓索引int k = 0;int i;for(i = 0; i< contours.size(); i++ )    {        Scalar color1 = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );        drawContours( drawing, contours, i, color1, 1, 8, vector<Vec4i>(), 0, Point() );        Scalar color2 = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );        drawContours( drawing, hull, i, color2, 1, 8, vector<Vec4i>(), 0, Point() );int tt = contourArea(contours[i]);        printf("轮廓面积%d = %d\n", i, tt);if( tt > area)        {            area = contourArea(contours[i]);            k = i;        }

}

vector<Point> hull1;    hull1 = hull[1];for(i = 0; i< hull1.size(); i++ )    {        printf("point %d, %d, %d\n", i, hull1[i].x, hull1[i].y);        circle(drawing, hull1[i], 6, Scalar(255,0,0), 3, CV_AA);      }

int j;for(j=0; j< contours.size(); j++)    {//如果没有defects或者轮廓小于三个点,则continueif( isContourConvex(contours[j])|| contours[j].size()<3) continue;

vector<int> convexHull_IntIdx;        vector<Vec4i> defects;if (contours[j].size() >3 )        {            convexHull(contours[j], convexHull_IntIdx, true);            convexityDefects(contours[j], convexHull_IntIdx, defects);        }    

for(i=0;i < defects.size();++i)          {              Matx<int,4,1> defectVector = defects[i];            vector<Point> contours1 =contours[j];            Point point1 = contours1[defectVector.val[0]];//开始点            Point point2 = contours1[defectVector.val[1]];//结束点            Point point3 = contours1[defectVector.val[2]];//深度点float dist = defectVector.val[3];            printf("dist: %f \n", dist);//if ( defectVector.val[3] <= 1000 ) { continue; } // skip defects that are shorter than 100 pixel            circle(drawing, point1, 3, Scalar(255,255,0), 2, CV_AA);            circle(drawing, point2, 8, Scalar(0,255,0), 2, CV_AA);            circle(drawing, point3, 3, Scalar(0,255,255), 2, CV_AA);

}      }/// Show in a window    namedWindow( "Hull demo");    imshow( "Hull demo", drawing );

waitKey(0);return(0);}

 

 

 

 

 

 

 

 

 

程序执行之后界面如下,注意左下有图中

程序代码:工程FirstOpenCV25

 

时间: 2024-09-29 12:29:04

OpenCV学习(30) 轮廓defects的相关文章

OpenCV学习(28) 轮廓

      OpenCV中可以方便的在一副图像中检测到轮廓,并把这些轮廓画出来.主要用到两个函数:一个是findContours( img, contours0, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);另一个是drawContours( cnt_img, contours, idx, color, 1, 8, hierarchy ); int main( int argc, char**) { Mat img = Mat::zeros(w, w,

OpenCV学习(33) 轮廓的特征矩Moment

      在OpenCV中,可以很方便的计算多边形区域的3阶特征矩,opencv中的矩主要包括以下几种:空间矩,中心矩和中心归一化矩. class Moments { public: ...... // 空间矩 double m00, m10, m01, m20, m11, m02, m30, m21, m12, m03; // 中心矩 double mu20, mu11, mu02, mu30, mu21, mu12, mu03; // 中心归一化矩 double nu20, nu11, n

OpenCV学习(31) 基于defects的简单手势

      前几年在做毕业设计时候曾用opencv1.0中defects做过简单的手势识别,这几天看OpenCV2.46中的轮廓函数,发现和以前差别挺大,函数调用完全不一样,重新实现了简单手势的代码.   1.首先用简单的肤色检测算法,得到手的区域.     Mat img = cv::imread("../hand2.jpg");     namedWindow("image");     imshow("image", img);     M

OpenCV 查找图像轮廓

OpenCV 查找图像轮廓 目的 我们将学习: 学会使用 OpenCV 函数 findContours 学会使用 OpenCV 函数 drawContours 原理 代码 下面是本示例的代码,可以从这里 下载 #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <stdio.h> #

指针-opencv学习灰度图锐化的两个函数的差别不理解

问题描述 opencv学习灰度图锐化的两个函数的差别不理解 下面是一个灰度图锐化的函数,我有两种方式实现,方式1,和方式2,居然得到的结果不一样,图片数据也不一样,请高手看一下,可能是C语言的知识掌握的不好. void my_sharpen(const cv::Mat &image, cv::Mat &result) { result.create (image.size(), image.type ()); for(int j=1; j<image.rows-1; j++) { u

库函数-opencv中图像轮廓矢量化算法

问题描述 opencv中图像轮廓矢量化算法 opencv中图像轮廓矢量化算法,有直接矢量化的库函数么?急求答案! 解决方案 说的有点含糊,如果你是要opencv中的代码,你可以直接抠出来用.

(转) OpenCV学习笔记大集锦 与 图像视觉博客资源2之MIT斯坦福CMU

      首页 视界智尚 算法技术 每日技术 来打我呀 注册     OpenCV学习笔记大集锦 整理了我所了解的有关OpenCV的学习笔记.原理分析.使用例程等相关的博文.排序不分先后,随机整理的.如果有好的资源,也欢迎介绍和分享. 1:OpenCV学习笔记 作者:CSDN数量:55篇博文网址:http://blog.csdn.net/column/details/opencv-manual.html 2:部分OpenCV的函数解读和原理解读 作者:梦想腾飞数量:20篇博文网址:http:/

OpenCV学习(32) 求轮廓的包围盒

      在OpenCV中,能够很方便的求轮廓包围盒.包括矩形,圆形,椭圆形以及倾斜的矩形(包围面积最小)集中包围盒.用到的四个函数是: Rect boundingRect(InputArray points) void minEnclosingCircle(InputArray points, Point2f& center, float& radius) RotatedRect minAreaRect(InputArray points) RotatedRect fitEllipse

OpenCV学习(34) 点到轮廓的距离

      在OpenCV中,可以很方便的计算一个像素点到轮廓的距离,计算距离的函数为: double pointPolygonTest(InputArray contour, Point2f pt, bool measureDist) Parameters: contour – 输入参数轮廓. pt – 测试的点. measureDist – 如果为false的话,则函数计算符号,在轮廓外部在为-1,在轮廓内为1,在轮廓上,则为0.如果为ture,则计算实际的像素符号距离,在轮廓外的点像素距离