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