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