先看这个opencv的经典例子:
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
#include <math.h>
#endif
#pragma comment(lib,"cv.lib")
#pragma comment(lib,"highgui.lib")
#pragma comment(lib,"cxcore.lib")
#define w 500
int levels = 3;
CvSeq* contours = 0;
void on_trackbar(int pos)
{
IplImage* cnt_img = cvCreateImage( cvSize(w,w), 8, 3 );
CvSeq* _contours = contours;
int _levels = levels - 3;
if( _levels <= 0 ) // get to the nearest face to make it look more funny
_contours = _contours->h_next->h_next->h_next->h_next->h_next->h_next->h_next->v_next->h_next->h_next;
//_contours = _contours->v_next;
cvZero( cnt_img );
cvDrawContours( cnt_img, _contours, CV_RGB(255,0,0), CV_RGB(0,255,0), _levels);//, 3, CV_AA, cvPoint(0,0) );
/*_levels:
3,所有外轮廓及包含的内轮廓及里面的内轮廓
2:所有外轮廓及包含的内轮廓
1:所有外轮廓
0,第一个外轮廓
-1:第一个外轮廓及包含的内轮廓
-2:第一个外轮廓及包含的内轮廓及里面的内轮廓
_contours->h_next:同级的下一个轮廓
_contours->v_next父级下的下层区域;
*/
cvShowImage( "contours", cnt_img );
cvReleaseImage( &cnt_img );
}
int main( int argc, char** argv )
{
int i, j;
CvMemStorage* storage = cvCreateMemStorage(0);
IplImage* img = cvCreateImage( cvSize(w,w), 8, 1 );
cvZero( img );
for( i=0; i < 6; i++ )
{
int dx = (i%2)*250 - 30;//0%2=0;
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 );
}
cvNamedWindow( "image", 1 );
cvShowImage( "image", img );
cvFindContours( img, storage, &contours, sizeof(CvContour),
2, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
// comment this out if you do not want approximation
contours = cvApproxPoly( contours, sizeof(CvContour), storage, CV_POLY_APPROX_DP, 3, 1 );
//cvApproxPoly: 逼近方法 精度 逼近曲线是否封闭
cvNamedWindow( "contours", 1 );
cvCreateTrackbar( "levels+3", "contours", &levels, 7, on_trackbar );
on_trackbar(0);
cvWaitKey(0);
cvReleaseMemStorage( &storage );
cvReleaseImage( &img );
return 0;
}
主要还是理解下int mode=CV_RETR_LIST,int method=CV_CHAIN_APPROX_SIMPLE,CvPoint offset=cvPoint(0,0));
当mode 为CV_RETR_CCOMP 只把图像分为两个层次,顶层和次层,一等级轮廓只匹配与其最接近 ;
cvDrawContours 函数第5个参数为 max_level=0时,笑脸图像会显示第一个找到的轮廓,左边的白色耳朵一只;
max_level=1时,所有白色区域的轮廓都会被显示出来,因为他们都属于等级1;
max_level=2时;每个白色区域里面的黑色区域会被显示出来,可能一个白色区域下面有多个黑色区域,但他们都是同级的;
这里你要注意的的是每个白色区域下的黑色区域,如脸下面有4个黑色区域,白色眼珠下有一个黑色区域,这个黑色区域与脸下的那三个区域时同级的,也就是说他不属于脸的内区域,他是白色眼珠的内区域;
当mode 为CV_RETR_TREE 则从轮廓外到内按等级1 - n 全部分配
当mode为 CV_RETR_LIST 全部轮廓均为1级