- /************************************************************************/
- /* 提取輪廓兩種方法對(duì)比及繪制輪廓'最大等級(jí)'分析 */
- /************************************************************************/
- #include "stdafx.h"
- #include "cv.h"
- #include "highgui.h"
-
- int main()
- {
- IplImage* img = cvLoadImage("lena.jpg", CV_LOAD_IMAGE_GRAYSCALE);
- IplImage* img_temp = cvCreateImage(cvGetSize(img), 8, 1);
-
- cvThreshold(img, img, 128, 255, CV_THRESH_BINARY);
-
- CvMemStorage* mem_storage = cvCreateMemStorage(0);
- CvSeq *first_contour = NULL, *c = NULL;
-
- //////////////////////////////////////////////////////////////////////////
- // 1、
- cvNamedWindow("contour1");
- cvCopyImage(img, img_temp);
- double t = (double)cvGetTickCount();
- cvFindContours(img_temp, mem_storage, &first_contour);
- cvZero(img_temp);
- cvDrawContours(
- img_temp,
- first_contour,
- cvScalar(100),
- cvScalar(100),
- 1
- );
- t = (double)cvGetTickCount() - t;
- cvShowImage("contour1", img_temp);
-
- printf("run1 = %gms\n", t/(cvGetTickFrequency()*1000.));
-
- cvClearMemStorage(mem_storage);
-
- //////////////////////////////////////////////////////////////////////////
- // 2,、
- cvNamedWindow("contour2");
- cvCopyImage(img, img_temp);
- t = (double)cvGetTickCount();
- CvContourScanner scanner = cvStartFindContours(img_temp, mem_storage);
- while (cvFindNextContour(scanner));
- first_contour = cvEndFindContours(&scanner);
-
- cvZero(img_temp);
- cvDrawContours(
- img_temp,
- first_contour,
- cvScalar(100),
- cvScalar(100),
- 1
- );
- t = (double)cvGetTickCount() - t;
- cvShowImage("contour2", img_temp);
-
- printf("run2 = %gms\n", t/(cvGetTickFrequency()*1000.));
-
- cvClearMemStorage(mem_storage);
- cvReleaseImage(&img);
- cvReleaseImage(&img_temp);
-
- cvWaitKey();
-
- /************************************************************************/
- /* 經(jīng)測(cè)試 run1 = 16.1431ms run2 = 15.8677ms (參考)
- 不過(guò)可以肯定這兩中算法時(shí)間復(fù)雜度是相同的 */
- /************************************************************************/
-
- //////////////////////////////////////////////////////////////////////////
- // 上述兩種方法完成了對(duì)輪廓的提取,如想繪制輪廓都得配合cvDrawContours來(lái)使用
- // 而cvDrawContours 函數(shù)第5個(gè)參數(shù)為 max_level 經(jīng)查ICVL含義如下:
- //
- // 繪制輪廓的最大等級(jí),。如果等級(jí)為0,繪制單獨(dú)的輪廓,。如果為1,,繪制輪廓及在其后的相同的級(jí)別下輪廓。
- // 如果值為2,,所有的輪廓,。如果等級(jí)為2,繪制所有同級(jí)輪廓及所有低一級(jí)輪廓,,諸此種種,。如果值為負(fù)數(shù),
- // 函數(shù)不繪制同級(jí)輪廓,,但會(huì)升序繪制直到級(jí)別為abs(max_level)-1的子輪廓,。
- //
- // 相信好多讀者初次都無(wú)法理解等級(jí)的含義,而且測(cè)試時(shí)候輸入>=1 的整數(shù)效果幾乎一樣
- // 只有提取輪廓時(shí)候的提取模式設(shè)為 CV_RETR_CCOMP CV_RETR_TREE 時(shí)這個(gè)參數(shù)才有意義
- //
- // 經(jīng)查FindContours 函數(shù)里面這樣介紹提取模式(mode)的這兩個(gè)參數(shù):
- // CV_RETR_CCOMP - 提取所有輪廓,,并且將其組織為兩層的 hierarchy: 頂層為連通域的外圍邊界,,次層為洞的內(nèi)層邊界。
- // CV_RETR_TREE - 提取所有輪廓,,并且重構(gòu)嵌套輪廓的全部 hierarchy
- //
- // 下面用第一種方法進(jìn)行測(cè)試
-
- cvNamedWindow("contour_test");
- cvNamedWindow("contour_raw");
- img = cvLoadImage("contour.jpg", CV_LOAD_IMAGE_GRAYSCALE);
- cvShowImage("contour_raw", img);
- cvThreshold(img, img, 128, 255, CV_THRESH_BINARY);
- img_temp = cvCloneImage(img);
- cvFindContours(
- img_temp,
- mem_storage,
- &first_contour,
- sizeof(CvContour),
- CV_RETR_CCOMP //#1 需更改區(qū)域
- );
-
- cvZero(img_temp);
- cvDrawContours(
- img_temp,
- first_contour,
- cvScalar(100),
- cvScalar(100),
- 1 //#2 需更改區(qū)域
- );
- cvShowImage("contour_test", img_temp);
- /************************************************************************/
- /* (1, 2) = (CV_RETR_CCOMP, 1) 如圖1
- (1, 2) = (CV_RETR_CCOMP, 2) 如圖2
- (1, 2) = (CV_RETR_TREE, 1) 如圖3
- (1, 2) = (CV_RETR_TREE, 2) 如圖4
- (1, 2) = (CV_RETR_TREE, 6) 如圖5
- 經(jīng)分析CV_RETR_CCOMP 只把圖像分為兩個(gè)層次,頂層和次層,一等級(jí)輪廓只匹配與其最接近
- 的內(nèi)側(cè)輪廓即2等級(jí)
- CV_RETR_TREE 則從輪廓外到內(nèi)按等級(jí)1 - n 全部分配
- CV_RETR_LIST 全部輪廓均為1級(jí) */
- /************************************************************************/
-
- cvWaitKey();
- cvReleaseImage(&img);
- cvReleaseImage(&img_temp);
- cvReleaseMemStorage(&mem_storage);
- cvDestroyAllWindows();
- return 0;
- }
原圖
圖一
圖二
圖三
圖四
圖五
這是OpenCV的經(jīng)典一個(gè)例子:
- #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,,所有外輪廓及包含的內(nèi)輪廓及里面的內(nèi)輪廓
- 2:所有外輪廓及包含的內(nèi)輪廓
- 1:所有外輪廓
- 0,第一個(gè)外輪廓
- -1:第一個(gè)外輪廓及包含的內(nèi)輪廓
- -2:第一個(gè)外輪廓及包含的內(nèi)輪廓及里面的內(nèi)輪廓
-
-
- _contours->h_next:同級(jí)的下一個(gè)輪廓
- _contours->v_next父級(jí)下的下層區(qū)域,;
- */
- 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));
當(dāng)mode 為CV_RETR_CCOMP 只把圖像分為兩個(gè)層次,頂層和次層,一等級(jí)輪廓只匹配與其最接近 ,;
cvDrawContours 函數(shù)第5個(gè)參數(shù)為 max_level=0時(shí),笑臉圖像會(huì)顯示第一個(gè)找到的輪廓,,左邊的白色耳朵一只,;
max_level=1時(shí),所有白色區(qū)域的輪廓都會(huì)被顯示出來(lái),,因?yàn)樗麄兌紝儆诘燃?jí)1,;
max_level=2時(shí);每個(gè)白色區(qū)域里面的黑色區(qū)域會(huì)被顯示出來(lái),,可能一個(gè)白色區(qū)域下面有多個(gè)黑色區(qū)域,,但他們都是同級(jí)的;
這里你要注意的的是每個(gè)白色區(qū)域下的黑色區(qū)域,如臉下面有4個(gè)黑色區(qū)域,,白色眼珠下有一個(gè)黑色區(qū)域,,這個(gè)黑色區(qū)域與臉下的那三個(gè)區(qū)域時(shí)同級(jí)的,也就是說(shuō)他不屬于臉的內(nèi)區(qū)域,,他是白色眼珠的內(nèi)區(qū)域,;
當(dāng)mode為 CV_RETR_LIST 全部輪廓均為1級(jí)
|