2013-04-01 163 views
7

我有一個OpenCV應用程序從辦公室內部的網絡攝像頭流(很多的細節)餵食,我必須找到一個人造標記。該標記是白色背景上的黑色正方形。我使用Canny來查找邊緣和cvFindContours輪廓,然後使用approxPolyDP和co。爲過濾和尋找候選人,然後使用本地直方圖進一步過濾,bla bla bla ...OpenCV轉換Canny邊緣到輪廓

這或多或少,但不完全如我所願。即使Canny創建一個非閉合線,FindContours總是返回一個閉環。我在輪廓線兩側形成一個輪廓,形成一個循環。對於Canny圖像(我的標記)的封閉邊緣,我得到2個輪廓,一個在內側,另一個在外側。 我不得不與該操作問題:

  • 我得到2周的輪廓的每個標記(沒那麼嚴重)

  • 最瑣碎過濾不可用(拒絕非閉合輪廓)

所以我的問題:是否有可能獲得非閉合Canny邊緣的非閉合輪廓? 或者解決上述兩個問題的標準方法是什麼?

Canny是一個非常好的工具,但我需要一種方式將2D b/w圖像轉換爲易於處理的東西。像連接組件一樣按組件的行進順序列出所有像素。所以我可以過濾循環,並將其饋入approxPolyDP。

更新:我錯過了一些重要的細節:標記可以在任何方向(它不是面向相機,沒有直角),實際上我正在做的是3D方向估計,基於2D投影標記。

回答

10

我發現了一個乾淨而簡單的問題解決方案。技巧是啓用2級層次結構生成(在findCountours中)並查找具有父級的輪廓。這將返回封閉的Canny邊緣的內部輪廓,僅此而已。 非封閉邊緣會自動丟棄,每個標記都會有一個輪廓。

vector<vector<Point> > contours; 
vector<Vec4i> hierarchy; 
findContours(CannyImage, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE, Point(0,0)); 
for (unsigned int i=0; i<contours.size(); i++) 
    if (hierarchy[i][3] >= 0) //has parent, inner (hole) contour of a closed edge (looks good) 
     drawContours(contourImage, contours, i, Scalar(255, 0, 0), 1, 8); 

它也可以倒過來,即:尋找具有一個孩子的輪廓(層次[I] [2]> = 0),但在我的情況下,父親檢查產生更好的效果。

+2

我並不真正同意編輯,因爲findContours()和drawContours()不一定在相同的圖像上操作,除非您要立即垃圾輪廓圖像通過透視。該編輯還刪除了來自Canny()的findContours()的輸入信息。 –

1

這我該怎麼做 1. Canny邊緣檢測 2.使用houghtransform檢測邊緣。 3.檢測角度爲90°的兩條邊。

+0

謝謝,這是一個好的主意,面向前方的矩形,但不幸的是我必須在任何方向檢測它們。實際上,我正在做的任務是估計3D空間中的標記方向(使用已知的固有凸輪參數)。 –

+0

您可以使用OpenSURF任何方向來檢測與匹配模板的標記 –

2

我有同樣的問題重複的輪廓,甚至擴張和蠶食沒能解決它:

Mat src=imread("E:\\test.bmp"),gry,bin,nor,dil,erd; 
GaussianBlur(src, nor, Size(5,5),0); 
cvtColor(nor,gry,CV_BGR2GRAY); 
Canny(gry,bin,100,150,5,true); 
dilate(bin,dil,Mat()); 
erode(dil,erd,Mat()); 
Mat tmp=bin.clone(); 
vector<vector<Point>> conts; 
vector<Vec4i> hier; 
findContours(tmp,conts,hier,CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE); 

此圖像(TEST.BMP)包含3個輪廓,但findContours共有6款! 我用閾值和問題解決:

Mat src=imread("E:\\test.bmp"),gry,bin,nor,dil,erd; 
GaussianBlur(src, nor, Size(5,5),0); 
cvtColor(nor,gry,CV_BGR2GRAY); 
threshold(gry,bin,0,255,THRESH_BINARY+THRESH_OTSU);  
vector<vector<Point>> conts; 
vector<Vec4i> hier; 
findContours(bin,conts,hier,CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE); 

現在返回4周的輪廓,其中第一之一是圖像邊界(輪廓具有索引0),並且可以容易地跳過。