本范例主要介绍了如何提取轮廓和用一些形状描述符对轮廓进行表述,轮廓提取函数涉及到的参数很多,没有经常用到它的话,对参数的了解就不会太深刻,这里也按照本人搜索出来的一些资料进行总结,希望对大家有用。
本代码实现了多个功能
创建了三个滑动条:
第一个滑动条表示状态描述符,分别表示为:
0:多边形近似
1:外接矩形
2:外接圆
3:力矩
第二个滑动条表示轮廓检测mode类型,分别表示为:
0:只检测出最外轮廓
1:检测出所有轮廓,并保持在list中,只有一层
2:检测出所有轮廓,并将它们组织成两层结构,顶层是外边界,第二层是孔边界。
3:检测出所有轮廓并且重新建立网状的轮廓结构
第三个滑动条表示层次
0:表示没有层次,输出所指定的轮廓
1:表示第一层,输出第一层的轮廓
2:表示第二层,输出第二层的轮廓
3:
……
#include "stdafx.h" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <stdio.h> #include <stdlib.h> using namespace cv; using namespace std; #define w 500 Mat src; Mat src_gray; int hiararchyvalue ; int choice; int contoursmode; int max_mode=3; int max_hiararchy = 4; int max_choice=3; RNG rng(12345); /// 函数声明 void thresh_callback(int, void* ); void contours_callback(int,void*); /** @主函数 */ int main( int argc, char** argv ) { int i, j; /// 载入原图像, 返回3通道图像 // src = imread( "HappyFish.jpg", 1 ); src.zeros(cvSize(w,w),CV_8UC1); IplImage* img = cvCreateImage( cvSize(w,w), 8, 1 ); cvZero( img ); for( i=0; i < 6; i++ ) { int dx = (i%2)*250 - 30; int dy = (i/2)*150; CvScalar white = cvRealScalar(255); CvScalar black = cvRealScalar(0); if( i == 0 ) { for( j = 0; j <= 10; j++ ) { double angle = (j+5)*CV_PI/21; cvLine(img, cvPoint(cvRound(dx+100+j*10-80*cos(angle)), cvRound(dy+100-90*sin(angle))), cvPoint(cvRound(dx+100+j*10-30*cos(angle)), cvRound(dy+100-30*sin(angle))), white, 1, 8, 0); } } cvEllipse( img, cvPoint(dx+150, dy+100), cvSize(100,70), 0, 0, 360, white, -1, 8, 0 ); cvEllipse( img, cvPoint(dx+115, dy+70), cvSize(30,20), 0, 0, 360, black, -1, 8, 0 ); cvEllipse( img, cvPoint(dx+185, dy+70), cvSize(30,20), 0, 0, 360, black, -1, 8, 0 ); cvEllipse( img, cvPoint(dx+115, dy+70), cvSize(15,15), 0, 0, 360, white, -1, 8, 0 ); cvEllipse( img, cvPoint(dx+185, dy+70), cvSize(15,15), 0, 0, 360, white, -1, 8, 0 ); cvEllipse( img, cvPoint(dx+115, dy+70), cvSize(5,5), 0, 0, 360, black, -1, 8, 0 ); cvEllipse( img, cvPoint(dx+185, dy+70), cvSize(5,5), 0, 0, 360, black, -1, 8, 0 ); cvEllipse( img, cvPoint(dx+150, dy+100), cvSize(10,5), 0, 0, 360, black, -1, 8, 0 ); cvEllipse( img, cvPoint(dx+150, dy+150), cvSize(40,10), 0, 0, 360, black, -1, 8, 0 ); cvEllipse( img, cvPoint(dx+27, dy+100), cvSize(20,35), 0, 0, 360, white, -1, 8, 0 ); cvEllipse( img, cvPoint(dx+273, dy+100), cvSize(20,35), 0, 0, 360, white, -1, 8, 0 ); } Mat src1(img); src=src1; /// 转化成灰度图像并进行平滑 // cvtColor( src, src_gray, CV_BGR2GRAY ); // blur( src_gray, src_gray, Size(3,3) ); /// 创建窗口 char* source_window = "Source"; namedWindow( source_window, CV_WINDOW_AUTOSIZE ); imshow( source_window, src ); createTrackbar( " Choice:", "Source", &choice, max_choice, thresh_callback );//创建形状描述符类型 createTrackbar("contours:","Source",&contoursmode,max_mode,contours_callback);//轮廓检测mode类型 createTrackbar( " hiararchy:", "Source", &hiararchyvalue, max_hiararchy, contours_callback );//轮廓检测层次 thresh_callback( 0, 0 ); contours_callback(0,0); waitKey(0); return(0); } /** @thresh_callback 函数 */ void thresh_callback(int, void* ) { vector<vector<Point> > contours; vector<Vec4i> hierarchy; /// 找到轮廓 findContours( src, contours, hierarchy,CV_RETR_TREE , CV_CHAIN_APPROX_SIMPLE, Point(0, 0) ); /// 多边形逼近轮廓 + 获取矩形和圆形边界框 vector<vector<Point> > contours_poly( contours.size() ); vector<Rect> boundRect( contours.size() ); vector<Point2f>center( contours.size() ); vector<float>radius( contours.size() ); vector<Moments> mu(contours.size() ); vector<Point2f> mc( contours.size() ); for( int i = 0; i < contours.size(); i++ ) { switch (choice) { case 0: approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );break;//多边形近似 case 1: boundRect[i] = boundingRect( Mat(contours[i]) );break;//外接矩形 case 2: minEnclosingCircle( Mat(contours[i]), center[i], radius[i] );break;//外接圆 case 3: mu[i] = moments( contours[i], false );mc[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 );break;//力矩 default: break; } } /// 画多边形轮廓 + 包围的矩形框 + 圆形框+力矩 Mat drawing = Mat::zeros( src.size(), CV_8UC3 ); for( int i = 0; i< contours.size(); i++ ) { Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); switch(choice) { case 0: drawContours( drawing, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point() );break; case 1: rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );break; case 2: circle( drawing, center[i], (int)radius[i], color, 2, 8, 0 );break; case 3: circle( drawing, mc[i], 4, color, -1, 8, 0 ); default: break; } } /// 显示在一个窗口 namedWindow( "Contours", CV_WINDOW_AUTOSIZE ); imshow( "Contours", drawing ); } //轮廓检测 void contours_callback(int,void*) { int i=0; Mat threshold_output; Mat drawing = Mat::zeros( src.size(), CV_8UC3 ); vector<vector<Point> > contours; vector<Vec4i> hierarchy; /// 找到轮廓 switch (contoursmode) { case 0: i=0;hiararchyvalue=0;break;//CV_RETR_EXTERNAL case 1: i=1;hiararchyvalue=0;break;//CV_RETR_LIST case 2: i=2; if (hiararchyvalue>1) { hiararchyvalue=0; } break;//CV_RETR_CCOMP case 3: i=3;break;//CV_RETR_TREE } findContours( src, contours, hierarchy,i , CV_CHAIN_APPROX_SIMPLE, Point(0, 0) ); Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); drawContours(drawing,contours,-1,color,1,8,hierarchy,hiararchyvalue+1,Point()); imshow("Contoursmode",drawing); }
图1、原图
图2、多边形近似 图3、外接矩形
图4、外接圆 图5、力矩
图6、第一层轮廓 图7、所有轮廓
功能:在二值图像中寻找轮廓
结构:
void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())
由图我们可以比较清晰的认识轮廓检索模式
图8、传递给findcontours的测试图(上图),得到的轮廓(下图):得到的轮廓只可能有两种,外部轮廓(虚线)或孔(点线)
图9、四种可能的mode值所得到的结果的拓扑结构
还想再了解Findconcours函数,可以点击下面博客
http://blog.csdn.net/augusdi/article/details/9000893
功能:画轮廓或填充轮廓
结构:
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() )
功能:用指定精度逼近多边形曲线
结构:
void approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed)
功能:计算点集的最外面矩形边界
结构:
Rect boundingRect(InputArray points)
功能:计算完全包围已有轮廓最小圆,外接圆
结构:
void minEnclosingCircle(InputArray points, Point2f& center, float& radius)
功能:计算多边形和光栅形状的最高达三阶的所有矩
结构:
Moments moments(InputArray array, bool binaryImage=false )
注:
其他连通区域的形态描述符
ConvexHull:发现点集的凸外形,计算物体的凸包。例子
minAreaRect:对给定的 2D 点集,寻找最小面积的包围矩形,创建可倾斜的边界框。例子
fitEllipse:对给定的 2D 点集,寻找最小面积的包围圆形。例子
PointPolygonTest:确定测试点是否在多边形中,计算图像中的点到轮廓的距离。例子
contourArea:计算轮廓的面积(包含的像素个数)。例子
arcLength:计算轮廓或曲线长度。例子