问题:
原图中存在两个部分重叠的圆,多余的圆会影响边缘提取的正确度,所以需要从边缘中去掉另一个交叠圆上的点。
方法:
使用之前的方法删除错误的边缘点之后,余下的点中还存在偏离的点需要进一步修正。
由于边界的起点不一定正确,所以先遍历边界点,找出离中心最近的点,从该点出发来查找待
修正的点。
判断是否需要修正的条件:
1)如果当前点和前面一个点相距太大,则当前点需要向中心点平移一段距离才行
2)如果当前点和前一个点相距偏大,且当前点、前一点、中心点三点形成的角度是钝角,则认为
当前点严重偏离中心点,需要作进一步修正。
修正的方法也依照上述两种情况分开处理:
1)如果当前点和前面点的距离太大,则前一点无法作为当前点的参考点,
考虑从中心点出发,向当前点方 向移动,找到最后一个掩膜标记的点作为替换点;
2)否则,直接参考前面点和中心点的距离dis,将当前点向中心点方向移动,
当距离中心点小于等于dis 时,则认为可以停止移动了。
为了加快修正的速度,对于需要修正的一段圆弧,弧上的每个点的移动步数都参考圆弧起点的
移动步数,而不用每个点都使用上面的两个判断来结束移动。
最终的实践效果较好。
代码如下:
int beginid=0;
vector<int>centerdis;
int cx=centerx-vecResult[0].x;
int cy=centery-vecResult[0].y;
int cdis=cx*cx+cy*cy;
centerdis.push_back(cdis);
int dx,dy,dis;
for(int i=1;i<size;i++)
{
cx=centerx-vecResult[i].x;
cy=centery-vecResult[i].y;
cdis=cx*cx+cy*cy;
centerdis.push_back(cdis);
if(cdis<centerdis[beginid])
beginid=i;
}
//最后一个点和起始点求距离
if(beginid==0){
centerdis.push_back(centerdis[0]);
vecResult.push_back(vecResult[0]);
}
else{
centerdis.insert(centerdis.begin()+beginid,centerdis[beginid]);
vecResult.insert(vecResult.begin()+beginid, vecResult[beginid]);
}
beginid++;
queue<int>changeid;
int newsize=size+1;
for (int i = 1; i <= size; i++)
{
int cur=(beginid+i)%newsize;
int prev=(cur+size)%newsize;
//计算前后两点的距离
dx=vecResult[cur].x-vecResult[prev].x;
dy=vecResult[cur].y-vecResult[prev].y;
dis=dx*dx+dy*dy;
//如果前后距离大于等于100,认为需要进行平移
if(dis>=200)
{
changeid.push(cur);
}
else if(dis>=100)
{
//再次判断前后两点与中心点的距离是否接近,如果相差不大,则认为可以接受
cx=vecResult[cur].x-centerx;
cy=vecResult[cur].y-centery;
cdis=cx*cx+cy*cy;
cx=vecResult[prev].x-centerx;
cy=vecResult[prev].y-centery;
int cdis1=cx*cx+cy*cy;
//如果前后两点与中心点的距离相差大于100,则需要进行平移
int abscdis=abs(cdis-cdis1);
if(abscdis>=200)
{
changeid.push(cur);
}
else if(abscdis>100)
{
//以前一点为锚点,计算角度是否为钝角
int x1,y1;
if(cur==beginid-1)
{
cx=centerx-vecResult[cur].x;
cy=centery-vecResult[cur].y;
x1=vecResult[prev].x-vecResult[cur].x;
y1=vecResult[prev].y-vecResult[cur].y;
}
else
{
cx=centerx-vecResult[prev].x;
cy=centery-vecResult[prev].y;
x1=vecResult[cur].x-vecResult[prev].x;
y1=vecResult[cur].y-vecResult[prev].y;
}
float cos=(cx*x1+cy*y1)/sqrt(1.0*(cx*cx+cy*cy)*(x1*x1+y1*y1));
if(cos<0.01)//为钝角
{
changeid.push(cur);
}
}
}
}
int step=MOVELEN;
int changesize=changeid.size();
if(changesize==1)
{
int icur=changeid.front();
//反着,中心尝试向该点移动,第一次碰到
int i=1;
int sx=centerx-vecResult[icur].x;
int sy=centery-vecResult[icur].y;
int maxmove=max(abs(sx),abs(sy));
if(sx!=0)sx=sx/abs(sx);
if(sy!=0)sy=sy/abs(sy);
int newx=centerx-sx;
int newy=centery-sy;
int pos=newy*sWidth+newx;
while(pMaskBuf[pos] && i<=maxmove)
{
newx-=sx;
newy-=sy;
pos=newy*sWidth+newx;
i++;
}
vecResult[icur].x=newx;
vecResult[icur].y=newy;
}
else
{
while(!changeid.empty())
{
int ibegin=changeid.front();
changeid.pop();
int iend=ibegin+1;
if(!changeid.empty())
{
int inext=changeid.front();
if((inext-ibegin)<size/2)
{
iend=inext;
}
}
else
break;
step=MOVELEN;
//要把<=换成!=,因为有可能起点的Id大于终点的id
for(int icur=ibegin;icur!=iend;icur=(icur+1)%newsize)
{
//向中心点平移的单位位移stepx,stepy
int sx=centerx-vecResult[icur].x;
int sy=centery-vecResult[icur].y;
int maxmove=max(abs(sx),abs(sy));
if(sx!=0)sx=sx/abs(sx);
if(sy!=0)sy=sy/abs(sy);
//计算前一个点距离中心点的距离
int iprev=(icur+size)%newsize;
int dis1=centerdis[iprev];
//计算前后两点的初始距离
dx=vecResult[icur].x-vecResult[iprev].x;
dy=vecResult[icur].y-vecResult[iprev].y;
int dis0=dx*dx+dy*dy;
bool isFar=false;
if(dis0>=200) isFar=true;
int newx,newy;
if(step==MOVELEN)
{
//如果最开始的距离就大于200,认为相距太远,不做判断依据
//反着,中心尝试向该点移动,第一次碰到
if(isFar)
{
int i=1;
newx=centerx-sx;
newy=centery-sy;
int pos=newy*sWidth+newx;
//
while(pMaskBuf[pos] && i<=maxmove)
{
newx-=sx;
newy-=sy;
pos=newy*sWidth+newx;
i++;
}
step=maxmove-i;
vecResult[icur].x=newx;
vecResult[icur].y=newy;
}
else
{
newx=vecResult[icur].x + sx;
newy=vecResult[icur].y + sy;
while(step)
{
newx += sx;
newy += sy;
//重新计算和前一个点的距离,如果变得小于100了,则停止移动
dx=newx-vecResult[iprev].x;
dy=newy-vecResult[iprev].y;
dis=dx*dx+dy*dy;
//计算到中心点的距离
cx=newx-centerx;
cy=newy-centery;
cdis=cx*cx+cy*cy;
//如果最开始的距离就大于200,认为相距太远,不做判断依据
if((isFar && (centerdis[iprev]-cdis)<=100) || (!isFar && dis<=100 && (centerdis[iprev]-cdis)<=100))
{
vecResult[icur].x = newx;
vecResult[icur].y = newy;
step=MOVELEN-step;
break;
}
step--;
}
}
}
else
{
int i=step;
newx=vecResult[icur].x + sx;
newy=vecResult[icur].y + sy;
while(i--)
{
newx += sx;
newy += sy;
}
vecResult[icur].x = newx;
vecResult[icur].y = newy;
}
}
}
}
vecResult.erase(vecResult.begin()+beginid);
out.close();
//再做一次凸包修正
vecResult = grahamScan(vecResult);