matlab得找極值的函數findpeak只能找一維極值,而且opencv沒有對應的函數,所謂極值就是比周圍的值都大,然後看需求要什麼程度的極值:
/*計算可分割石頭的中心點--大石頭會有點過分割
* singlechannel----單通道的距離變換的圖像,類型float
* lengthresh-------峯值點周圍lengthresh個像素內沒有出現比峯值點大的數,則是真的峯值;否則不要這個峯值
* peaks------------找到的輸入圖像的各個可分割石頭的中心點,即符合要求的峯值點
* */
int OreStoneDegreeCalculate::findPeaks(Mat &singlechannel,int lengthresh,vector<Point> &peaks)
{
if(peaks.size()!=0)
{
peaks.clear();
}
int rownumber = singlechannel.rows;
int colnumber = singlechannel.cols;
if(rownumber < 3 || colnumber < 3){
return -1;
}
for(int start_row = 0;start_row!=rownumber;start_row++)
{
for(int start_col = 0;start_col!=colnumber;start_col++)
{
float current=singlechannel.ptr<float>(start_row)[start_col];
if(current<2)
{
continue;
}
//8 neighbors 鍒濇鎵懼埌宄板�肩偣
//如果一個像素點的值比周圍8鄰域的所有值都高,那麼它可能是一個峯值點
bool ispeak=true;
for(int rr=-1;rr!=2;rr++)
{
if(!ispeak)
{
break;
}
for(int cc=-1;cc!=2;cc++)
{
if((rr==0 && cc==0)||((start_row+rr<0 || start_col+cc<0)||(start_row+rr>=singlechannel.rows || start_col+cc>=singlechannel.cols)))
{
continue;
}
if(current<singlechannel.ptr<float>(start_row+rr)[start_col+cc])
{
ispeak=false;
break;
}
}
}
//瀵瑰嘲鍊肩偣榪涜鍐嶅垽鏂紝鏄惁鏄痜lat peak錛屽墶鍘繪帀
//對初步找到的峯值進行二次判斷,看是否是真的峯值或者假峯值
if(ispeak)
{
//如果此峯值點的周圍lengthresh範圍內所有點都比峯值點的值小,那麼這是一個真的峯值點,即石頭中心
//如果此峯值點的周圍lengthresh範圍內有大於此峯值點,則這個峯值點是假的。
int length=2;
bool ignore=false;
while((!ignore) && (length<lengthresh))
{
for(int rr=-1*length;rr!=1*length+1;rr++)
{
if(ignore)
{
break;
}
for(int cc=-1*length;cc!=1*length+1;cc++)
{
if((rr==0 && cc==0)||((start_row+rr<0 || start_col+cc<0)||(start_row+rr>=singlechannel.rows || start_col+cc>=singlechannel.cols)))
{
continue;
}
if(current<singlechannel.ptr<float>(start_row+rr)[start_col+cc])
{
ignore=true;
break;
}
if(current==singlechannel.ptr<float>(start_row+rr)[start_col+cc])
{
singlechannel.ptr<float>(start_row)[start_col]=1;
ignore=true;
break;
}
}
}
length++;
}
if(!ignore)
{
peaks.push_back(Point(start_col,start_row));
}
}
//這一個峯值點的真假已經判斷完畢
//姝ゅ嘲鍊兼槸鍚︽槸鐪熺殑宄板�� 鍒ゆ柇瀹屾瘯
}
}
//圖像內的所有點遍歷完畢,所有峯值都找到了。
//鍥懼儚鎵�鏈夌偣閬嶅巻瀹屾瘯
return 0;
}
對於粘連目標,我用這個極值法求出極值然後+分水嶺分割,效果比我之前試過的分割方法都好,而且簡單耗時少。
像這樣找的中心區域點都比較準,然後分水嶺分割時過分割就會較少。
但這個辦法應該再優化一下,因爲這樣找的極值對單個大目標不友好,單個大目標會找出幾個極值。至於優化的代碼就不發了(公司內部使用)。
有一個疑惑:今天調試時,分水嶺結果怎麼還有未知區域沒被分配:
這裏竟然還有0---未知區域的值,明明是已經分水嶺後的結果:
/*分水嶺分割處理
* srcmatbw--------二值圖 單通道
* everycenters----可分割石頭的中心圖,背景爲黑色0,中心爲白點255
* imglabels-------分水嶺結果 背景是100,分界線是-1,可分割石頭是1~N(可能有0已容錯)
* */
int watershedSegmentProc(Mat &srcmatbw,Mat &everycenters,Mat &imglabels)
{
// int not_zero_count=countNonZero(srcmatbw);
// float white_count_thre=srcmatbw.rows*srcmatbw.cols;
// white_count_thre*=0.8;
// if((not_zero_count<20 )||(not_zero_count>(int)white_count_thre))
// {
// return 2;
// }
Mat element = getStructuringElement(MORPH_ELLIPSE, Size(11, 11));
Mat element2 = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
Mat binary_dilate;//every centers
dilate(everycenters, binary_dilate, element2, Point(-1, -1), 1);
Mat binary_8UC3;
vector<Mat> resultmats;
resultmats.push_back(srcmatbw);
resultmats.push_back(srcmatbw);
resultmats.push_back(srcmatbw);
merge(resultmats,binary_8UC3);
Mat unknown;//得到未知區域 即分界線的劃分涉及區域
bitwise_xor(srcmatbw,binary_dilate,unknown);
//合併標記圖像
Mat imgstats, imgcentroid;
connectedComponentsWithStats(binary_dilate, imglabels, imgstats, imgcentroid); //連通域標記
imglabels.convertTo(imglabels, CV_32SC1); //圖像類型轉換
imglabels = imglabels + 100;//背景區域像素爲100
for (int i=0;i<unknown.rows;i++)
{
uchar* ptr = unknown.ptr<uchar>(i);
for (int j=0;j<unknown.cols;j++)
{
if (255==ptr[j])
{
imglabels.at<int>(i, j) = 0; //未知區域像素爲0
}
}
}
//分水嶺分割
watershed(binary_8UC3, imglabels);
}
那個0不知道怎麼回事?!
/**********************************************************************/
關於opencv4.1調用tensorflow訓練好的帶有DropOut或BatchNorm節點的.pb模型,一個新同事說opencv c++不支持,我查了下:
https://answers.opencv.org/question/175364/export-tensorflow-graph-with-batchnorm-to-opencv-dnn/
https://fossies.org/linux/opencv/modules/dnn/src/tensorflow/tf_importer.cpp
https://github.com/opencv/opencv/issues/9563
https://github.com/davidsandberg/facenet/issues/357
查了一下opencv4.1源碼,看到是寫了fushBatchNorm的接口的,如果不支持,那opencv爲什麼要寫這個接口,不是雞肋嗎:
看,的確可以識別這個節點的。我覺得就是要按opencv c++規定的方式來,它纔來加載python下訓練好的模型。
至於dropout節點,opencv源碼中我暫時沒看到,但是我看到網上講了解決辦法:
而且另一個人連在python下訓練好帶有dropout節點的模型然後opencv c++調用的代碼都寫好了。
所以我覺得這些不是不支持,opencv c++只是比python下嚴苛一些而已,按它的規則來就可以加載,只是我們還在弄清楚這些規則的路上而已。
今天翻牆找到一些非常有用的圖像分割資料,可惜沒有對應代碼,有一篇特別好,是講通過形狀匹配或擬合來分割重疊不規則目標的(如下圖)。我都上傳在CSDN https://download.csdn.net/download/wd1603926823/11541160 了 希望自己有時間將其實現可以用在另一個項目中。下圖是論文中的結果:感覺對high overlapping & out of focus的圖效果較好