關於opencv4.1的dnn及findpeak二維極值

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://answers.opencv.org/question/198805/how-to-load-a-keras-model-build-with-tensorflow-backend-in-opencv/

http://www.liuxiao.org/2018/10/tensorflow-c-%E4%BB%8E%E8%AE%AD%E7%BB%83%E5%88%B0%E9%83%A8%E7%BD%B23%EF%BC%9A%E4%BD%BF%E7%94%A8-keras-%E8%AE%AD%E7%BB%83%E5%92%8C%E9%83%A8%E7%BD%B2-cnn/

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的圖效果較好

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章