整個工程進(jìn)展到這一步也算是不容易吧,但技術(shù)含量也不怎么高,中間亂起八糟的錯誤太煩人了,不管怎么樣,現(xiàn)在面臨了最大的困難吧,圖像處理算法。算法確實不好弄啊,雖然以前整過,但都不是針對圖像的。
現(xiàn)在的圖像算法太多了,好像誰都在研究,沒有一個統(tǒng)一的路線,看論文也是越看越糊涂,無奈之下還是自己好好學(xué)學(xué)吧,幸好隊友以前也搞過,大家也都愿意參與進(jìn)來了,很開心!
首先改變下策略吧,之前一直在linux中直接在QT中利用OpenCV庫進(jìn)行圖像處理的嘗試,但是效率太差了,每次想要結(jié)果,都要用板子,所以,現(xiàn)在改用OpenCV+vs2010現(xiàn)在PC上測試,直到滿意了再復(fù)制到板子上進(jìn)行測試。
換工具,得先配置啊,還好之前搞過,使用的人也多,所以比較順利:參考博客
?
自己寫程序,測試結(jié)果編譯出錯:LINK : fatal error LNK1123: 轉(zhuǎn)換到 COFF 期間失敗: 文件無效或損壞
百度了, ?mod=viewthread&tid=10226 這個帖子不錯,安裝完補(bǔ)丁之后,編譯生成解決方案成功。
測試了小程序,可以使用了。
針對自己的問題吧,現(xiàn)在的問題是月牙提取不出來,所以絞盡腦汁、千方百計要把這月牙給分離出來,找方法一個一個試吧。
話說加入OpenCV后編譯又出現(xiàn)一個錯誤:
?
這個方法解決了。
首先我們已經(jīng)對圖像進(jìn)行了初步的分割,可以將指甲的輪廓提取出來,只是效果不是很理想??梢钥吹绞芄庹沼绊懨黠@,需要采取措施解決光照問題。如下圖:
?
現(xiàn)在想要通過對扣取出來的圖片進(jìn)行進(jìn)一步處理,也就是對第二幅圖進(jìn)行特征提取,從中找到我們所需的月牙,月牙和甲床面積比,月牙顏色,甲床顏色,甲床上是否有斑點、橫紋、縱紋,從而為后面的醫(yī)學(xué)診斷理論作依據(jù)。
既然基于灰度圖像已經(jīng)不能再有任何進(jìn)展了,不如就用彩色圖像分割吧。之前也探索過,發(fā)現(xiàn)還是有一定的效果的。
RGB顏色空間是圖像處理中最基本、最常用、面向硬件的顏色空間。我們采集到的彩色圖像,一般就是被分成R、G、B的成分加以保存的。然而,自然環(huán)境下獲取的果實圖像容易受自然光照、葉片遮擋和陰影等情況的影響,即對亮度比較敏感。而RGB顏色空間的分量與亮度密切相關(guān),即只要亮度改變,3個分量都會隨之相應(yīng)地改變。所以,RGB顏色空間適合于顯示系統(tǒng),卻并不適合于圖像處理。
HSL 和 HSV(也叫HSB)是對RGB 色彩空間中點的兩種有關(guān)系的表示,它們嘗試描述比 RGB 更準(zhǔn)確的感知顏色聯(lián)系,并仍保持在計算上簡單。
H指hue(色相)、S指saturation(飽和度)、L指lightness(亮度)、V指value(色調(diào))、B指brightness(明度)。
色相(H)是色彩的基本屬性,就是平常所說的顏色名稱,如紅色、黃色等。
飽和度(S)是指色彩的純度,越高色彩越純,低則逐漸變灰,取0-100%的數(shù)值。
明度(V),亮度(L),取0-100%。
?
根據(jù)這幅圖就能很好地理解HSV空間了。所以接下來就采用彩色圖像進(jìn)行分析看看效果。,貌似可以先將指甲摳出來。不管怎樣,先試試。
?
首先查論文,看到的好多是聚類方法,kmeans方法首先來,幸好OpenCV也有這函數(shù),先來學(xué)學(xué)。
K-means算法是最為經(jīng)典的基于劃分的聚類方法,是十大經(jīng)典數(shù)據(jù)挖掘算法之一。K-means算法的基本思想是:以空間中k個點為中心進(jìn)行聚類,對最靠近他們的對象歸類。通過迭代的方法,逐次更新各聚類中心的值,直至得到最好的聚類結(jié)果。
我的OpenCV的版本是2.3.1. 其中Kmean的實現(xiàn)在modulescoresrcmatrix.cpp里面,這里要推薦一個博客,講得挺清楚:?p=8
例子可以看:
double cv::kmeans( InputArray _data, int K, InputOutputArray _bestLabels, TermCriteria criteria, int attempts, int flags, OutputArray _centers )
下面就是分析這個函數(shù)了。
_data: 這個就是你要處理的數(shù)據(jù),例如是一個CvMat數(shù)據(jù)
K : 你需要最終生成的cluster的數(shù)量
_bestLabels: 當(dāng)cv::kmeans執(zhí)行完畢以后, _bestLabels里面儲存的就是每一個對應(yīng)的數(shù)據(jù)元素所在的cluster的index,這樣你就可以更新你的數(shù)據(jù),就是標(biāo)記矩陣。
criteria: 這個東西是用來告訴cv::kmeans以一個什么樣的停止條件來運(yùn)行,例如criteria.epsilon = 0.01f;criteria.type = CV_TERMCRIT_EPS; 這個表示centers在兩輪cluster運(yùn)行以后的距離差,如果這個距離小于等于criteria.epsilon就停止返回當(dāng)前得到的centers,否則繼續(xù)
attempts: 最多嘗試多少次,文檔上說一般設(shè)置為2
flags: 這個主要是傳遞一些配置參數(shù),例如 初始的時候使用user code給定的label –KMEANS_USE_INITIAL_LABELS,若使用kmeans++初始化算法– KMEANS_PP_CENTERS
_centers: 這個就是我們想要的結(jié)果了,該函數(shù)運(yùn)行完畢以后,這個變量里面儲存所有的center的數(shù)據(jù),也就是你想要的東西了,引用例子的程序,稍作修改就拿來用了。
void kmeans_mat(const Mat& src_img,Mat& dst_img)
{
int width_src=src_img.cols;
int height_src=src_img.rows;
Mat samples=Mat::zeros(width_src*height_src,1,CV_32FC3);//創(chuàng)建樣本矩陣,CV_32FC3代表32位浮點3通道(彩色圖像)
Mat clusters;//類別標(biāo)記矩陣
int k=0;
for (int i=0;i)
{
for (int j=0;j)
{
//將像素點三通道的值按順序排入樣本矩陣
samples.at(k,0)[0]=(float)src_img.at(i,j)[0];
samples.at(k,0)[1]=(float)src_img.at(i,j)[1];
samples.at(k,0)[2]=(float)src_img.at(i,j)[2];
}
}
int nCuster=2;//聚類類別數(shù),自己修改。
//聚類,KMEANS PP CENTERS Use kmeans++ center initialization by Arthur and Vassilvitskii
kmeans(samples,nCuster,clusters,TermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,10,1.0),2,KMEANS_PP_CENTERS);
//顯示聚類結(jié)果
if (dst_img.empty())
{
dst_img=Mat::zeros(height_src,width_src,CV_8UC1);
}
k=0;
int val=0;
float step=255/(nCuster-1);
for (int i=0;i)
{
for (int j=0;j)
{
val=255-clusters.at(k,0)*step;//int
dst_img.at(i,j)=val;
}
}
}
來看看聚類結(jié)果先:
聚類效果還不錯,只是比原本的指甲小了點,需要進(jìn)一步修改,或者和前面的邊緣提取相結(jié)合進(jìn)行修正。而且聚類的數(shù)目需要人來控制。
我在opencv的處理中總是遇到一個問題:Bad argument (Ukown array type) in cvarrToMat,后來發(fā)現(xiàn)是opencv庫函數(shù)的使用問題,他有c的也有c++的,Mat一般是c++下的,所以用c的庫函數(shù)會出現(xiàn)這個問題。
另外c版本中的保存圖片為cvSaveImage()函數(shù),c++版本中直接與matlab的相似,imwrite()函數(shù)。小插曲!
評論