OpenCV函式cvConvexHull2由點集序列或陣列建立凸邊形
以下是點集序列或陣列建立凸多邊形的程式碼:
#include<cv.h>#include<highgui.h>#include<stdlib.h>#pragma comment(lib, "cv.lib")#pragma comment(lib, "cxcore.lib")#pragma comment(lib, "highgui.lib")#define ARRAY 0int main(){ IplImage* img = cvCreateImage (cvSize(500, 500), 8, 3); cvNamedWindow ("hull", 1);#if ! ARRAY CvMemStorage* storage = cvCreateMemStorage (0);#endif int i; int contour = rand() % 100 + 1; int hullcontour; CvPoint pt0;#if ! ARRAY CvSeq* ptseq = cvCreateSeq (CV_SEQ_KIND_GENERIC | CV_32SC2, sizeof(CvContour), sizeof(CvPoint), storage); CvSeq* hull; for (i = 0; i < contour; i++) { pt0.x = rand() % (img->width / 2 ) + img->width / 4; pt0.y = rand() % (img->height / 2) + img->height / 4; cvSeqPush (ptseq, &pt0); } hull = cvConvexHull2 (ptseq, 0, CV_CLOCKWISE, 0); /*hull = cvConvexHull2 (ptseq, 0, CV_CLOCKWISE, 1);*/ hullcontour = hull->total;#else CvPoint* points = (CvPoint*)malloc(contour * sizeof(points[0 ])); int* hull = (int*)malloc(contour * sizeof(hull[0])); CvMat point_mat = cvMat (1, contour, CV_32SC2, points); CvMat hull_mat = cvMat (1, contour, CV_32SC1, hull); for (i = 0; i < contour; i++) { pt0.x = rand() % (img->width / 2) + img->width / 4; pt0.y = rand() % (img->height / 2) + img->height / 4; points[i] = pt0; } cvConvexHull2 (&point_mat, &hull_mat, CV_CLOCKWISE, 0); hullcontour = hull_mat.cols;#endif cvZero (img); for (i = 0; i < contour; i++) {#if ! ARRAY pt0 = * CV_GET_SEQ_ELEM(CvPoint, ptseq, i); /*pt0 = ** CV_GET_SEQ_ELEM(CvPoint*, ptseq, i);*/#else pt0 = points[i];#endif cvCircle (img, pt0, 2, CV_RGB(255, 0, 0), CV_FILLED); }#if ! ARRAY pt0 = ** CV_GET_SEQ_ELEM(CvPoint*, hull, hullcontour - 1); /*pt0 = * CV_GET_SEQ_ELEM(CvPoint, hull, hullcontour - 1);*/#else pt0 = points[hull[hullcontour - 1]];#endif for (i = 0; i < hullcontour; i++) {#if ! ARRAY CvPoint pt = **CV_GET_SEQ_ELEM(CvPoint*, hull, i); /*CvPoint pt = *CV_GET_SEQ_ELEM(CvPoint, hull, i);*/#else CvPoint pt = points[hull[i]];#endif cvLine (img, pt0, pt, CV_RGB(255, 0, 0)); pt0 = pt; } cvShowImage ("hull", img); cvWaitKey (0);#if ! ARRAY cvClearMemStorage (storage);#else free (points); free (hull);#endif return 0;}
程式碼中有3條註釋語句,這是我在學習這個程式時遇到的問題,自己寫的測試程式碼。這個程式碼相對來說還是比較
好理解的,主要就是開始對程式中CV_GET_SEQ_ELEM巨集的使用有些不太理解。這個巨集是用來在序列中提取元
素的,本程式中共有3處用到了。
第一處:
pt0 = * CV_GET_SEQ_ELEM(CvPoint, ptseq, i);
第二處:
pt0 = ** CV_GET_SEQ_ELEM(CvPoint*, hull, hullcontour - 1);
第三處:
CvPoint pt = **CV_GET_SEQ_ELEM(CvPoint*, hull, i);
顯然,第一處的呼叫方式和後面兩處是不同的。但這裡pt0和pt的型別都是CvPoint,ptseq和hull都是CvSeq*類
型的,唯一不同的是巨集裡的第一個引數,這個引數表上巨集返回的型別+*,比如:第一處這個引數是CvPoint,則
返回CvPoint*,以此類推。這樣的話這兩個巨集最後結果都是返回一個CvPoint型別值。這裡對巨集的使用是不是有
點型別於函式過載呢!既然如此,我想幹脆都用相同的方式呼叫這個巨集,於是我把第一處的程式碼改為
pt0 = ** CV_GET_SEQ_ELEM(CvPoint*, ptseq, i);
執行後程序中止了,於是我把這裡又改回來,然後改動後兩處,改為
pt0 = * CV_GET_SEQ_ELEM(CvPoint, hull, hullcontour - 1);CvPoint pt = *CV_GET_SEQ_ELEM(CvPoint, hull, i);
執行後程序依然中止啦。這樣起碼說明了在這裡關於這個巨集的呼叫方式是不可以互換的。但具體為什麼,確實
面有句話對我很有幫助:當return_points=0時,用cvConvexHull2函式得到的是凸外形,包含的是輪廓的定點
的指標或下標,而當return_points非0時,得到的是外形點本身。cvConvexHull2函式呼叫程式碼如下
hull = cvConvexHull2 (ptseq, 0, CV_CLOCKWISE, 0);
這裡的return_points被設定為0了,說明hull並不是直接指向輪廓點的序列,而是指向指向輪廓點序列的指標,
這就有點像hull是個二級指標啦!所以在後兩處對巨集的呼叫第一個引數設定為CvPoint*,這樣的話就返回
CvPoint**型別。到目前為止,這還只是我個人推測,還需要進一步的驗證。於是我把上面程式碼中最後一個引數
return_points改為1,執行。一切正常啦!注:這裡後面兩處對巨集的呼叫已經在前面改了,所以就不必在修改
了。以上所有的分析和理解都只是我個人的看法,不一定就是對的。希望大家能夠一起交流下這個問題,也希
望各位大神能夠不吝賜教!!!