如标题,又说回分水岭。
分水岭的源码分析可参考OpenCV 源码中分水岭算法 watershed 函数源码注解_Endless_91的博客-CSDN博客_watershed源码这个博主。
然后我写了下流程:
?而对于我的应用,不是彩图,是二值图,所以只能如下去构造。
connectedComponents(peak_image, imglabels);
imglabels.convertTo(imglabels, CV_32SC1);
///分水岭分割
vector<Mat> resultmats;
Mat binary_8UC3;
resultmats.push_back(realsingleimg);
resultmats.push_back(realsingleimg);
resultmats.push_back(realsingleimg);
merge(resultmats,binary_8UC3);
Mat unknown;//得到未知区域 即分界线的划分涉及区域
bitwise_xor(realsingleimg,peak_image,unknown);
imglabels.forEach<int>(
[&unknown](int &pixel, const int *position) -> void
{
pixel+=100;
if((unknown.ptr<uchar>(position[0])[position[1]])>0)
{
pixel=0;
}
}
);
watershed(binary_8UC3, imglabels);///分水岭分割结束
这样的后果就是过分割严重,想着用下面的轴相似来抑制极大值。但是鲁棒性并没有我之前传的那一版本好。
/*
*float mergedistanceth:每两个中心点 每个轴之间的距离差阈值,小于此阈值则是相似轴。越小相似轴越少,则合并的点越少
*float similarratio:相似轴占所有轴的比例,大于此阈值则合并。越小合并的点越多。
* */
void peakNMSuppress(Mat objbw,vector<Point> origipeaks,float mergedistanceth,float similarratio,vector<Point> &mergepeaks)
{
int origipeaksnum=origipeaks.size();
vector<PEAKINFO> peaksaxises;
for(int ptid=0;ptid!=origipeaksnum;ptid++)
{
PEAKINFO tmppeakinfo;
tmppeakinfo.peak=origipeaks[ptid];
tmppeakinfo.proceeded=0;
//得到每个peak的四个轴
getAxisLengths(objbw,origipeaks[ptid],tmppeakinfo.axises);
peaksaxises.push_back(tmppeakinfo);
}
//对每个点的特征进行判断,极度相似的才是需要合并的
for(int peakid=0;peakid!=peaksaxises.size();peakid++)
{
if(peaksaxises[peakid].proceeded)
continue;
Vec4b currentpeakinfo=peaksaxises[peakid].axises;
vector<Point> tmpmerged;
tmpmerged.push_back(peaksaxises[peakid].peak);
peaksaxises[peakid].proceeded=1;
for(int compareid=peakid+1;compareid!=peaksaxises.size();compareid++)
{
if(peaksaxises[compareid].proceeded)
continue;
Vec4b comparepeakinfo=peaksaxises[compareid].axises;
float similarcount=0.0f;
for(int id=0;id!=4;id++)
{
float similardegree=abs(currentpeakinfo.val[id]-comparepeakinfo.val[id]);
if(similardegree<mergedistanceth)
{
similarcount += 1;
}
}
similarcount /= 4;//表示极度相似的轴的比例
if(similarcount>=similarratio)
{
peaksaxises[compareid].proceeded=1;
tmpmerged.push_back(peaksaxises[compareid].peak);
}
}
int similarpeaksnum=tmpmerged.size();
if(similarpeaksnum==1)
{
mergepeaks.push_back(tmpmerged[0]);
}
else
{
//merge many peak points...
float xsum=tmpmerged[0].x,ysum=tmpmerged[0].y;
for(int pid=1;pid!=similarpeaksnum;pid++)
{
xsum += tmpmerged[pid].x;
ysum += tmpmerged[pid].x;
}
Point mergedpeak(xsum/similarpeaksnum,ysum/similarpeaksnum);
mergepeaks.push_back(mergedpeak);
}
}
}
//得到每个peak的四个轴
void getAxisLengths(Mat objbw,Point peakpt,Vec4w &axislengths)
{
int rows=objbw.rows;
int cols=objbw.cols;
//0 degree...水平
axislengths.val[0]=1;
int r=peakpt.y;
//left...
for(int c=peakpt.x-1;c>-1;c--)
{
if(objbw.ptr<uchar>(r)[c]!=0)
{
(axislengths.val[0])++;
}
else
break;
}
//right...
for(int c=peakpt.x+1;c!=cols;c++)
{
if(objbw.ptr<uchar>(r)[c]!=0)
{
(axislengths.val[0])++;
}
else
break;
}
//90 degree...垂直
axislengths.val[1]=1;
int c=peakpt.x;
//up...
for(r=peakpt.y-1;r>-1;r--)
{
if(objbw.ptr<uchar>(r)[c]!=0)
{
(axislengths.val[1])++;
}
else
break;
}
//bottom...
for(r=peakpt.y+1;r!=rows;r++)
{
if(objbw.ptr<uchar>(r)[c]!=0)
{
(axislengths.val[1])++;
}
else
break;
}
//45 degree...
axislengths.val[2]=1;
c=peakpt.x;
r=peakpt.y;
//up...
for(r=peakpt.y-1;r>-1;r--)
{
for(c=peakpt.x+1;c!=cols;c++)
{
if(objbw.ptr<uchar>(r)[c]!=0)
{
(axislengths.val[2])++;
}
else
break;
}
}
c=peakpt.x;
r=peakpt.y;
//down...
for(r=peakpt.y+1;r!=rows;r++)
{
for(c=peakpt.x-1;c>-1;c--)
{
if(objbw.ptr<uchar>(r)[c]!=0)
{
(axislengths.val[2])++;
}
else
break;
}
}
//135 degree...
axislengths.val[3]=1;
c=peakpt.x;
r=peakpt.y;
//up...
for(r=peakpt.y-1;r>-1;r--)
{
for(c=peakpt.x-1;c>-1;c--)
{
if(objbw.ptr<uchar>(r)[c]!=0)
{
(axislengths.val[3])++;
}
else
break;
}
}
c=peakpt.x;
r=peakpt.y;
//down...
for(r=peakpt.y+1;r!=rows;r++)
{
for(c=peakpt.x+1;c!=cols;c++)
{
if(objbw.ptr<uchar>(r)[c]!=0)
{
(axislengths.val[3])++;
}
else
break;
}
}
}
还是没有链接里的效果好。?
|