1. 程式人生 > >OpenCV函式cvConvexHull2由點集序列或陣列建立凸邊形

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 + 1int 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);


顯然,第一處的呼叫方式和後面兩處是不同的。但這裡pt0pt的型別都是CvPoint,ptseqhull都是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,執行。一切正常啦!注:這裡後面兩處對巨集的呼叫已經在前面改了,所以就不必在修改

了。以上所有的分析和理解都只是我個人的看法,不一定就是對的。希望大家能夠一起交流下這個問題,也希

望各位大神能夠不吝賜教!!!