2011-11-15 240 views
4

是否有一些更好的方法可以在opencv中找到輪廓質心,而無需使用內置函數?c中opencv輪廓/對象的質心?

+0

如果你有一堆點(2D向量),你應該能夠通過平均這些點來獲得重心:創建點到所有其他點位置添加到,然後除以該點的組成部分累積了總點數的位置。我剛剛寫了一個基本插圖[這裏](http://hascanvas.com/contourCentroid)。不完全確定它與凸包的效果如何。 –

回答

2

你在你的當前片段的代碼得到什麼當然是你的邊界框的質心。

「如果你有一堆點(2D矢量),你應該能夠通過對這些點進行平均來得到質心:創建一個點,將所有其他點的位置添加到點中,然後劃分該點的組件累積的位置由總點數。「 - 喬治Profenza提到

這的確是對於任何給定對象在兩dimentionalspace確切的重心是正確的做法。

在維基百科上,我們有尋找對象的質心的一般形式。 http://en.wikipedia.org/wiki/Centroid

就個人而言,我會問自己,我從這項計劃中所需要的。我是否想要一個徹底但性能很強的操作,還是我想做一些近似值?我甚至可以找到一個OpenCV函數來處理這個問題,並且效率很高。

還沒有工作的例子,所以我用僞上一個簡單的5像素例如在徹底的方法寫的。

x_centroid = (pixel1_x + pixel2_x + pixel3_x + pixel4_x +pixel5_x)/5 
y_centroid = (pixel1_y + pixel2_y + pixel3_y + pixel4_y +pixel5_y)/5 

centroidPoint(x_centroid, y_centroid) 

毛圈絨對於x像素

Loop j times *sample (for (int i=0, i < j, i++))* 
{ 
    x_centroid = pixel[j]_x + x_centroid 
    y_centroid = pixel[j]_x + x_centroid 
} 
x_centroid = x_centroid/j 
y_centroid = y_centroid/j 

centroidPoint(x_centroid, y_centroid) 

本質上,你有類型

vector<vector<point>> 

的矢量輪廓在OpenCV中2.3。我相信你在早期版本中有類似的東西,你應該能夠通過這個「雙向量」的第一個索引遍歷圖片上的每個斑點,並遍歷內向量中的每個像素。

這裏是一個文檔的鏈接上輪廓功能 http://opencv.itseez.com/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=contours#cv.DrawContours

注意:如果您標記爲C++可視化你的問題。我建議你在OpenCV 2.3中使用C++語法而不是c。使用2.3的第一個也是很好的理由是它更基於類,在這種情況下意味着類Mat(而不是IplImage)會泄漏內存。人們不必寫命令銷燬所有活一天:)

我希望這闡明你的問題的一些情況。請享用。

+0

謝謝,這對我幫助很大。 – Gondy

6

雖然Sonaten的答案是完全正確的,有一個簡單的方法來做到這一點:使用專用的OpenCV的功能是:時刻()

http://opencv.itseez.com/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=moments#moments

它不僅返回質心,但有些關於你的形狀的更多統計。你可以發送一個輪廓或光柵形狀(二進制圖像),無論最適合你的需要。

編輯

例(修改)從 「學習OpenCV的」,由Gary bradsky

CvMoments moments; 
double M00, M01, M10; 

cvMoments(contour,&moments); 
M00 = cvGetSpatialMoment(&moments,0,0); 
M10 = cvGetSpatialMoment(&moments,1,0); 
M01 = cvGetSpatialMoment(&moments,0,1); 
centers[i].x = (int)(M10/M00); 
centers[i].y = (int)(M01/M00); 
+0

謝謝,我試圖做到這一點,使用下面的代碼, for(; contourours = 0; contour = contours-> h_next)\t {CvMoments * moments; cvMoments(cc_color,moments,1); \t \t double M01 = cvGetSpatialMoment(moments,0,1); double M00 = cvGetSpatialMoment(moments,0,0); \t \t double yc = M01/M00; } 但它仍然給出了錯誤.. –

+0

它是不是應該首先爲*時刻分配一些空間?或者更好地使用C++語法,它將管理你的內存。我不記得cvMoments – Sam

+0

的構造函數,我甚至把 CvMoments * moments =(CvMoments *)malloc(sizeof(CvMoments)); 但它仍然崩潰。 –

1

我用約瑟夫·奧羅克優秀的多邊形質心算法取得了巨大成功。

參見http://maven.smith.edu/~orourke/Code/centroid.c

本質:

  1. 對於輪廓的每個點,找到從當前索引多邊形的xy的三角形區域到下一個2個多邊形XY點例如:Math.Abs​​((( X1 - X0)*(Y2 - Y0) - (X2 - X0)*(Y1 - Y0))/ 2)
  2. 這個三角形區域添加到列表TriAreas
  3. 薩姆三角形區域,和存儲在SUMT
  4. F表示來自該當前三角形的質心CTx和CTy:CTx =(X0 + X1 + X2)/ 3和CTy =(Y0 + Y1 + Y2)/ 3;
  5. 將這2個質心值存儲在2個其他列表CTxs CTys中。
  6. 最後,對輪廓中的所有點執行此操作後,使用5中的2個三角形x和y列表查找輪廓質心x和y,這是有符號三角形區域的加權和,由每個三角形的質心加權:

    for (Int32 Index = 0; Index < CTxs.Count; Index++) 
        { 
         CentroidPointRet.X += CTxs[Index] * (TriAreas[Index]/SumT); 
        } 
        // now find centroid Y value 
        for (Int32 Index = 0; Index < CTys.Count; Index++) 
        { 
         CentroidPointRet.Y += CTys[Index] * (TriAreas[Index]/SumT); 
        }