要先变为二值图像:cvThreshold

提取轮廓:cvFindContours

参数描述:

hiararchy:参数和轮廓个数相同。

每个轮廓contours[ i ] 对应4个hierarchy元素的索引编号,即:

    • hierarchy[ i ][ 0 ] 后一个轮廓
    • hierarchy[ i ][ 1 ] 前一个轮廓
    • hierarchy[ i ][ 2 ] 父轮廓
    • hierarchy[ i ][ 3 ] 内嵌轮廓

如果没有对应项,该值设置为负数。

mode:表示轮廓的检索模式

CV_RETR_EXTERNAL      表示只检测外轮廓

CV_RETR_LIST              检测的轮廓不建立等级关系

CV_RETR_CCOMP          建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。

CV_RETR_TREE             建立一个等级树结构的轮廓。

method:为轮廓的近似办法

CV_CHAIN_APPROX_NONE         存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1

CV_CHAIN_APPROX_SIMPLE       压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息

CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS       使用teh-Chinl chain 近似算法

offset:表示代表轮廓点的偏移量,可以设置为任意值。对ROI图像中找出的轮廓,并要在整个图像中进行分析时,这个参数还是很有用的。

findContours 后会对输入的二值图像改变,最好需创建新MAT来存放;

findContours 后的轮廓信息contours可能过于复杂不平滑,可以用 approxPolyDP() 对该多边形曲线做适当近似。

contourArea() 函数可以得到当前轮廓包含区域的大小,方便轮廓的筛选。

findContours经常与 drawContours() 配合使用,用来将轮廓绘制出来。

  • 第一个参数,image表示目标图像
  • 第二个参数,contours表示输入的轮廓组,每一组轮廓由点vector构成
  • 第三个参数,contourIdx指明画第几个轮廓,如果该参数为负值,则画全部轮廓
  • 第四个参数,color为轮廓的颜色
  • 第五个参数,thickness为轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部
  • 第六个参数,lineType为线型
  • 第七个参数,为轮廓结构信息
  • 第八个参数,为maxLevel

得到了复杂轮廓往往不适合特征的检测,这里再介绍一个点集凸包络的提取函数convexHull()

  • 输入参数,是contours组中的一个轮廓
  • 返回,外凸包络的点集。

还可以得到轮廓的外包络矩形,使用函数 boundingRect()

如果想得到旋转的外包络矩形,使用函数 minAreaRect(),返回值为RotatedRect;

也可以得到轮廓的外包络,对应的函数为 minEnclosingCircle()

想得到轮廓的外包络椭圆,对应的函数为 fitEllipse(),返回值也是RotatedRect,可以用ellipse函数画出对应的椭圆。

如果想根据多边形的轮廓信息 => 多边形的多阶矩,可以使用 类moments,这个类可以得到多边形光栅形状的3阶以内的所有矩,

类内有变量m00,m10,m01,m20,m11,m02,m30,m21,m12,m03,

比如多边形的质心为 x = m10 / m00,y = m01 / m00。

如果想获得一点与多边形封闭轮廓的信息,可以调用 pointPolygonTest(),这个函数返回值为该点距离轮廓最近边界的距离,为正值为在轮廓内部,负值为在轮廓外部,0表示在边界上。

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <math.h>
#include <iostream> using namespace cv;
using namespace std; static void help()
{
cout
<< "\nThis program illustrates the use of findContours and drawContours\n"
<< "The original image is put up along with the image of drawn contours\n"
<< "Usage:\n"
<< "./contours2\n"
<< "\nA trackbar is put up which controls the contour level from -3 to 3\n"
<< endl;
} const int w = 500;
int levels = 3; vector<vector<Point> > contours;
vector<Vec4i> hierarchy; static void on_trackbar(int, void*)
{
Mat cnt_img = Mat::zeros(w, w, CV_8UC3);
int _levels = levels - 3;
drawContours( cnt_img, contours, _levels <= 0 ? 3 : -1, Scalar(128,255,255),
3, LINE_AA, hierarchy, std::abs(_levels) ); imshow("contours", cnt_img);
} int main( int argc, char** argv)
{
cv::CommandLineParser parser(argc, argv, "{help h||}");
if (parser.has("help"))
{
help();
return 0;
}
// Mat img = Mat::zeros(w, w, CV_8UC1); //Jeff --> we don't need to draw this by ourselves.
//Draw 6 faces
// for( int i = 0; i < 6; i++ )
// {
// int dx = (i%2)*250 - 30;
// int dy = (i/2)*150;
// const Scalar white = Scalar(255);
// const Scalar black = Scalar(0); // if( i == 0 )
// {
// for( int j = 0; j <= 10; j++ )
// {
// double angle = (j+5)*CV_PI/21;
// line(img, Point(cvRound(dx+100+j*10-80*cos(angle)),
// cvRound(dy+100-90*sin(angle))),
// Point(cvRound(dx+100+j*10-30*cos(angle)),
// cvRound(dy+100-30*sin(angle))), white, 1, 8, 0);
// }
// } // ellipse( img, Point(dx+150, dy+100), Size(100,70), 0, 0, 360, white, -1, 8, 0 );
// ellipse( img, Point(dx+115, dy+70), Size(30,20), 0, 0, 360, black, -1, 8, 0 );
// ellipse( img, Point(dx+185, dy+70), Size(30,20), 0, 0, 360, black, -1, 8, 0 );
// ellipse( img, Point(dx+115, dy+70), Size(15,15), 0, 0, 360, white, -1, 8, 0 );
// ellipse( img, Point(dx+185, dy+70), Size(15,15), 0, 0, 360, white, -1, 8, 0 );
// ellipse( img, Point(dx+115, dy+70), Size(5,5), 0, 0, 360, black, -1, 8, 0 );
// ellipse( img, Point(dx+185, dy+70), Size(5,5), 0, 0, 360, black, -1, 8, 0 );
// ellipse( img, Point(dx+150, dy+100), Size(10,5), 0, 0, 360, black, -1, 8, 0 );
// ellipse( img, Point(dx+150, dy+150), Size(40,10), 0, 0, 360, black, -1, 8, 0 );
// ellipse( img, Point(dx+27, dy+100), Size(20,35), 0, 0, 360, white, -1, 8, 0 );
// ellipse( img, Point(dx+273, dy+100), Size(20,35), 0, 0, 360, white, -1, 8, 0 );
// } Mat img = imread("/home/unsw/lolo.jpg");
Mat gray;
cvtColor(img, gray, COLOR_RGB2GRAY );
Mat binary;
threshold(gray, binary, 200,255,THRESH_BINARY); // (1) Pic One Show: show the faces
namedWindow( "image", 1 );
imshow( "image", binary ); // (2) Pic Two Show
//Extract the contours so that
vector<vector<Point> > contours0;
findContours( binary, contours0, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE); contours.resize(contours0.size());
for( size_t k = 0; k < contours0.size(); k++ )
approxPolyDP(Mat(contours0[k]), contours[k], 3, true); // Jeff --> the same name to bind window and trackbar together.
// qt qml to draw would be much better.
// callback: on_trackbar()
namedWindow( "contours", 1 );
createTrackbar( "levels+3", "contours", &levels, 7, on_trackbar );
on_trackbar(0,0); waitKey();
return 0;
}

  


Reference: http://blog.csdn.net/felix86/article/details/38121959

采用cvFindContours提取轮廓,并过滤掉小面积轮廓,最后将轮廓保存。

 static int getContoursByCplus(char* Imgname, double minarea, double whRatio)
{
cv::Mat src, dst, canny_output;
/// Load source image and convert it to gray
src = imread(Imgname, ); if (!src.data)
{
std::cout << "read data error!" << std::endl;
return -;
}
blur(src, src, Size(, )); //the pram. for findContours,
vector<vector<Point> > contours;
vector<Vec4i> hierarchy; /// Detect edges using canny
Canny(src, canny_output, , , );
/// Find contours
findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(, ));
//CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE double maxarea = ;
int maxAreaIdx = ; for (int i = ; i<contours.size(); i++)
{ double tmparea = fabs(contourArea(contours[i]));
if (tmparea>maxarea)
{
maxarea = tmparea;
maxAreaIdx = i;
continue;
} if (tmparea < minarea)
{
// *** 删除面积小于设定值的轮廓
contours.erase(contours.begin() + i);
std::wcout << "delete a small area" << std::endl;
continue;
}
//计算轮廓的直径宽高
Rect aRect =boundingRect(contours[i]);
if ((aRect.width / aRect.height)<whRatio)
{
// *** 删除宽高比例小于设定值的轮廓
contours.erase(contours.begin() + i);
std::wcout << "delete a unnomalRatio area" << std::endl;
continue;
}
}
/// Draw contours,彩色轮廓
dst= Mat::zeros(canny_output.size(), CV_8UC3);
for (int i = ; i< contours.size(); i++)
{
//随机颜色
Scalar color = Scalar(rng.uniform(, ), rng.uniform(, ), rng.uniform(, ));
drawContours(dst, contours, i, color, , , hierarchy, , Point());
}
// Create Window
char* source_window = "countors";
namedWindow(source_window, CV_WINDOW_NORMAL);
imshow(source_window, dst);
cv:; waitKey(); return ;
}

[OpenCV] Samples 04: contours2的更多相关文章

  1. [OpenCV] Samples 16: Decompose and Analyse RGB channels

    物体的颜色特征决定了灰度处理不是万能,对RGB分别处理具有相当的意义. #include <iostream> #include <stdio.h> #include &quo ...

  2. [OpenCV] Samples 10: imagelist_creator

    yaml写法的简单例子.将 $ ./ 1 2 3 4 5 命令的参数(代表图片地址)写入yaml中. 写yaml文件. 参考:[OpenCV] Samples 06: [ML] logistic re ...

  3. [OpenCV] Samples 06: [ML] logistic regression

    logistic regression,这个算法只能解决简单的线性二分类,在众多的机器学习分类算法中并不出众,但它能被改进为多分类,并换了另外一个名字softmax, 这可是深度学习中响当当的分类算法 ...

  4. [OpenCV] Samples 06: logistic regression

    logistic regression,这个算法只能解决简单的线性二分类,在众多的机器学习分类算法中并不出众,但它能被改进为多分类,并换了另外一个名字softmax, 这可是深度学习中响当当的分类算法 ...

  5. [OpenCV] Samples 13: opencv_version

    cv::CommandLineParser的使用. I suppose CommandLineParser::has("something") should be true whe ...

  6. [OpenCV] Samples 12: laplace

    先模糊再laplace,也可以替换为sobel等. 变换效果后录成视频,挺好玩. #include "opencv2/videoio/videoio.hpp" #include & ...

  7. [OpenCV] Samples 05: convexhull

    得到了复杂轮廓往往不适合特征的检测,这里再介绍一个点集凸包络的提取函数convexHull,输入参数就可以是contours组中的一个轮廓,返回外凸包络的点集 ---- 如此就能去掉凹进去的边. 对于 ...

  8. [OpenCV] Samples 03: cout_mat

    操作Mat元素时:I.at<double>(1,1) = CV_PI; /* * * cvout_sample just demonstrates the serial out capab ...

  9. [OpenCV] Samples 02: [ML] kmeans

    注意Mat作为kmeans的参数的含义. 扩展:高维向量的聚类. #include "opencv2/highgui.hpp" #include "opencv2/cor ...

随机推荐

  1. CA Loves GCD (BC#78 1002) (hdu 5656)

    CA Loves GCD  Accepts: 135  Submissions: 586  Time Limit: 6000/3000 MS (Java/Others)  Memory Limit: ...

  2. 关于HashTable的遍历方法解析

    要遍历一个Hashtable,api中提供了如下几个方法可供我们遍历: keys() - returns an Enumeration of the keys of this Hashtable ke ...

  3. hdu 4193 - Non-negative Partial Sums(滚动数列)

    题意: 给定一个由n个整数组成的整数序列,可以滚动,滚动的意思就是前面k个数放到序列末尾去.问有几种滚动方法使得前面任意个数的和>=0. 思路: 先根据原来的数列求sum数组,找到最低点,然后再 ...

  4. VS2012 编译带有c/c++代码的python模块失败解决方案

    python2.7默认编译带有/c++代码的模块/包是使用VS2008环境变量,所以为了可用,我们要在编译前设置环境变量 SET VS90COMNTOOLS=%VS110COMNTOOLS% 但有时只 ...

  5. 深入理解openstack网络架构(4)-----连接到public network

    原文地址: https://blogs.oracle.com/ronen/entry/diving_into_openstack_network_architecture3 译文转自:http://b ...

  6. linux 2.6 驱动笔记(二)

    字符设备驱动 linux 2.6的字符驱动由cdev结构体描述,具体参考globalmem例子,代码主要分以下几部分: 1. 定义一个字符类型设备驱动的结构体 struct globalmem_dev ...

  7. 区分各浏览器的CSS hack(包括360、搜狗、opera)

    虽然说使用css hack来解决页面兼容性bug并不是个好办法,但是有时候这些hack还是用的着的,比如你接受了一个二手或是三手的遗留界面,杂乱无章的css代码,只在某个浏览器下有兼容bug,而且需要 ...

  8. Sublime Text 2—解决中文乱码

    Sublime Text 2是一个非常棒的代码及文本编辑器,绿色小巧.速度飞快,跨平台支持Win/Mac/Linux,支持32与64位,支持各种流行编程语言的语法高亮.代码补全等,有着许多其他编辑器没 ...

  9. 手把手教你用python打造网易公开课视频下载软件3-对抓取的数据进行处理

    上篇讲到抓取的数据保存到rawhtml变量中,然后通过编码最终保存到html变量当中,那么html变量还会有什么问题吗?当然会有了,例如可能html变量中的保存的抓取的页面源代码可能有些标签没有关闭标 ...

  10. [Unity3D入门]入门级游戏项目"坦克狙击手"更新

    [Unity3D入门]入门级游戏项目"坦克狙击手"更新 在上一篇中我分享了一个尚未完全写好的入门级unity3d项目"坦克狙击手". 本文介绍最新版的" ...