首先基于前面的工作,通過調(diào)整已經(jīng)很好的把指甲邊緣顯示出來了,不曾想我卻從那時開始走上了彎路,使用matlab去處理靜態(tài)圖片,以獲得更好的指甲和特征提取效果,結(jié)果就是,效果不理想(光照影響)并且用到攝像頭上來一點都不實用。辛辛苦苦的研究了n多的圖像處理算法,幾乎把邊緣提取的算法全部過了一遍,閱讀了不下100篇論文,還折騰出B樣條曲線擬合進行邊緣連接,現(xiàn)在想想太可笑了,其實OpenCV現(xiàn)有的圖像處理方法已經(jīng)可以滿足我提取指甲的要求了,只不過我需要進行合理的組合搭配,從而實現(xiàn)我想要的效果。
總有那么一句話叫:摸著石頭過河。我今天算是體會到了,不過中間老板還讓寫創(chuàng)業(yè)計劃,總之,該回歸正道了!
接著之前的canny提取的邊緣,我想進一步提取出指甲,把其他背景都省略,這樣就只留下指甲了,從而進一步提取特征。首先我想到的是findContours函數(shù)及其輪廓操作
//! 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,輸出是一個向量數(shù)組,每個向量是Points類型的指針向量數(shù)組。這個數(shù)組會用做后面的輪廓處理。
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.建立兩個等級的輪廓,上面的一層為外邊界,里面的一層為內(nèi)孔的邊界信息。如果內(nèi)孔內(nèi)還有一個連通物體,這個物體的邊界也在頂層。
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代表分層結(jié)構(gòu),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函數(shù)用的不對,但是我是照著OpenCVcookbook做的,網(wǎng)上也搜了很多,都是這樣寫的,感覺不同于他們的是我的實在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,該過來之后就可以了。
現(xiàn)在的問題是,我該怎么取適當?shù)闹担沟弥挥兄讣椎妮喞A粝聛恚溆嗟氖∪ァ_€是一步一步來吧,先把輪廓查找的過程搞清楚。
findContours經(jīng)常與drawContours配合使用,用來將輪廓繪制出來。其中第一個參數(shù)image表示目標圖像,第二個參數(shù)contours表示輸入的輪廓組,每一組輪廓由點vector構(gòu)成,第三個參數(shù)contourIdx指明畫第幾個輪廓,如果該參數(shù)為負值,則畫全部輪廓,第四個參數(shù)color為輪廓的顏色,第五個參數(shù)thickness為輪廓的線寬,如果為負值或CV_FILLED表示填充輪廓內(nèi)部,第六個參數(shù)lineType為線型,第七個參數(shù)為輪廓結(jié)構(gòu)信息,第八個參數(shù)為maxLevel。
但是用在視頻處理中,還是不行,所以我改為拍照處理,拍5張照片后重合為一張,效果如下:
雖然還不是很好,但我也只能勉強的繼續(xù)往下走著先。這過程中涉及到一些Mat圖像基本容器的處理,因為我是存儲了5張圖片,所以不能直接賦值,需要用cvcopyto函數(shù)。
capture.read(frame);
++flag;
switch(flag)
{
case1:
frame.copyTo(image1);
break;
case2:
frame.copyTo(image2);
break;
case3:
frame.copyTo(image3);
break;
case4:
frame.copyTo(image4);
break;
default:
flag=0;
break;
}
后然處理重合吧:
Mat edge1=edged(image1);
Mat edge2=edged(image2);
Mat edge3=edged(image3);
Mat edge4=edged(image4);
Mat edge;
Mat result;
cv::addWeighted(edge1,1,edge2,1,0.,edge);
cv::addWeighted(edge,1,edge3,1,0.,edge);
cv::addWeighted(edge,1,edge4,1,0.,edge);
接下來我準備進行多邊形逼近或者其他手段把,把背景去除,然后特征提取。比較慢哈,不過最近聽說一位美國留學的博士師兄在做視網(wǎng)膜診病,和我這個甲診有點類似之處哈,好歹給了我一點鼓勵吧。
評論
查看更多