首先基于前面的工作,通過調整已經很好的把指甲邊緣顯示出來了,不曾想我卻從那時開始走上了彎路,使用matlab去處理靜態圖片,以獲得更好的指甲和特征提取效果,結果就是,效果不理想(光照影響)并且用到攝像頭上來一點都不實用。辛辛苦苦的研究了n多的圖像處理算法,幾乎把邊緣提取的算法全部過了一遍,閱讀了不下100篇論文,還折騰出B樣條曲線擬合進行邊緣連接,現在想想太可笑了,其實OpenCV現有的圖像處理方法已經可以滿足我提取指甲的要求了,只不過我需要進行合理的組合搭配,從而實現我想要的效果。
總有那么一句話叫:摸著石頭過河。我今天算是體會到了,不過中間老板還讓寫創業計劃,總之,該回歸正道了!
接著之前的canny提取的邊緣,我想進一步提取出指甲,把其他背景都省略,這樣就只留下指甲了,從而進一步提取特征。首先我想到的是findContours函數及其輪廓操作
//! retrieves contours and the hierarchical information from black-n-white image.
CV_EXPORTS_W void findContours( InputOutputArray image, OutputArrayOfArrays contours,
OutputArray hierarchy, int mode,
int method, Point offset=Point());
//! retrieves contours from black-n-white image.
CV_EXPORTS void findContours( InputOutputArray image, OutputArrayOfArrays contours,
int mode, int method, Point offset=Point());
其中image為輸入的 binary image,輸出是一個向量數組,每個向量是Points類型的指針向量數組。這個數組會用做后面的輪廓處理。
mode代表提取輪廓的類型, 可以是以下幾種類型 //CV_RETR_LIST, // retrieve all contours
//CV_RETR_EXTERNAL, // retrieve the external contours
//CV_RETR_TREE, // retrieve all contours in tree format
//CV_RETR_CCOMP is similar but limits the hierarchy at two levels.建立兩個等級的輪廓,上面的一層為外邊界,里面的一層為內孔的邊界信息。如果內孔內還有一個連通物體,這個物體的邊界也在頂層。
method代表輪廓點的類型,可以有 //CV_CHAIN_APPROX_NONE // all pixels of each contours存儲所有的輪廓點,相鄰的兩個點的像素位置差不超過1,即max(abs(x1-x2),abs(y2-y1))==1
//CV_CHAIN_APPROX_SIMPLE //only the end points would be included for horizontal,vertical, or diagonal contours. 壓縮水平方向,垂直方向,對角線方向的元素,只保留該方向的終點坐標,例如一個矩形輪廓只需4個點來保存輪廓信息
最后一個不用管先,然后就是一個OutputArray hierarchy代表分層結構,hierarchy, // hierarchical representation
接下來用 cv::Mat result(image.size(),CV_8U,cv::Scalar(255));
cv::drawContours(result,contours,
-1, // draw all contours
cv::Scalar(0), // in black
2); // with a thickness of 2
出來的效果還不錯,利用黑背景,能將指甲分離出來,但是接下來的分離過程除了錯誤。就是在我將多余的或者不符合要求的輪廓去除過程中報錯了
// Eliminate too short or too long contours
int cmin= 100; // minimum contour length
int cmax= 1000; // maximum contour length
std::vector >::const_iterator itc = contours.begin();
while (itc!=contours.end())
{
if (itc->size() < cmin || itc->size() > cmax)
itc=contours.erase(itc);
else
++itc;
}
錯誤如下:錯誤:no matching function for call to 'std::vector > >::erase(std::vector > >::const_iterator&)',我理解的意思是這里erase函數用的不對,但是我是照著OpenCVcookbook做的,網上也搜了很多,都是這樣寫的,感覺不同于他們的是我的實在QT中編寫,用OpenCV2.3.1,不知到為什么會報錯,
然后就找他的定義,感覺用得也沒錯:
iterator
erase(iterator __position)
{
if (__position + 1 != end())
std::copy(__position + 1, end(), __position);
--this->_M_impl._M_finish;
return __position;
}
iterator
erase(iterator __first, iterator __last)
{
_M_erase_at_end(std::copy(__last, end(), __first));
return __first;
}
后來仔細看了,iterator和const_iterator不一樣, typedef __gnu_cxx::__normal_iterator iterator; typedef __gnu_cxx::__normal_iterator const_iterator;
而我抄襲的程序里面都是const_iterator,該過來之后就可以了。
現在的問題是,我該怎么取適當的值,使得只有指甲的輪廓保留下來,其余的省去。還是一步一步來吧,先把輪廓查找的過程搞清楚。
findContours經常與drawContours配合使用,用來將輪廓繪制出來。其中第一個參數image表示目標圖像,第二個參數contours表示輸入的輪廓組,每一組輪廓由點vector構成,第三個參數contourIdx指明畫第幾個輪廓,如果該參數為負值,則畫全部輪廓,第四個參數color為輪廓的顏色,第五個參數thickness為輪廓的線寬,如果為負值或CV_FILLED表示填充輪廓內部,第六個參數lineType為線型,第七個參數為輪廓結構信息,第八個參數為maxLevel。
評論