关于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的图效果较好

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