问题:
原图中存在两个部分重叠的圆,多余的圆会影响边缘提取的正确度,所以需要从边缘中去掉另一个交叠圆上的点。
方法:
先使用边缘点计算出新的中心点的坐标B,保留相距中心点的最短距离radius。
如果中心点坐标A和B点的距离超过了radius,则认为当前图中存在两个相交的圆,需要对边
缘做进一步的处理。
依据中心点坐标A得到相对于B点的对称点A’即为交叠圆的圆心。
重新计算所有的边缘点距离新圆心A’的距离,如果该点距离A’比距离A更近,则认为该点在以
A’为圆心的圆形上,需要从边缘点集合中剔除掉该点。
#include<map>
#include<stack>
bool cvCircle(UCHAR *pContourMask, vector<Pt2D> & vecContour, int sWidth, int sHeight)
{
int centerx=sWidth/2;
int centery=sHeight/2;
//先要依据边缘统计各个半径的数目,用map存储
vector<int>distance;
map<int,int>radius;
int num=vecContour.size();
int newx=0,newy=0;
int mindis=sWidth*sWidth+sHeight*sHeight;
for(int i=0;i<num;i++)
{
int diffx=vecContour[i].x-centerx;
int diffy=vecContour[i].y-centery;
int dis=diffx*diffx+diffy*diffy;
distance.push_back(dis);
if(dis<mindis)mindis=dis;
//记录偏移的中心
newx+=vecContour[i].x;
newy+=vecContour[i].y;
if(radius.find(dis)!=radius.end())
radius[dis]++;
else
radius[dis]=1;
}
//计算整个边界的新的中心位置,和真正的中心位置的偏移量是否达到了最小半径
newx /= num;
newy /= num;
int diffx = newx-centerx;
int diffy = newy-centery;
int dis = diffx*diffx+diffy*diffy;
/*如果新的center与中心相距超过最小距离,
则认为存在第二个圆,否则直接退出不做处理*/
if(dis<=mindis) return false;
//依据center计算另一个圆心
int movx=newx+diffx;
int movy=newy+diffy;
//如果某个边缘点距离新圆心更近,则剔除掉此点
stack<int>delPt;
int label=0;
vector<Pt2D>endpt;
for(int i=0;i<num;i++)
{
int diffx=vecContour[i].x-movx;
int diffy=vecContour[i].y-movy;
int dis=diffx*diffx+diffy*diffy;
if(dis<distance[i])
{
delPt.push(i);
//如果Label==0,表示从边界起点开始,此处待改进
if(label==0) printf("0需要移除\n");
//如果等于1,表示此前是有带保留段的
else if(label==1)
{
label=2;
endpt.push_back(vecContour[i-1]);
}
}
else
{
if(label==0)
{
label=1;
if(i!=0)
{
endpt.push_back(vecContour[i]);
}
}
else if(label==2)
{
label=3;
endpt.push_back(vecContour[i]);
}
}
}
while(!delPt.empty())
{
int i=delPt.top();
delPt.pop();
vecContour.erase(vecContour.begin()+i);
}
if(label==2)
{//两个端点交换一下位置
Pt2D temp=endpt[0];
endpt[0]=endpt[1];
endpt[1]=temp;
}
int insertindex=0;
for(int i=0;i<vecContour.size();i++)
{
if(vecContour[i].x==endpt[0].x && vecContour[i].y==endpt[0].y)
insertindex=i+1;
}
//三个点:endpt[0],{newx,newy},endpt[1]
Pt2D newpt={newx,newy};
endpt.insert(endpt.begin()+1,newpt);
//三个点确定一段弧
Pt2D temp=endpt[0];
vector<Pt2D>insertpt;
for(int j=0;j<2;j++)
{
temp.x=endpt[j].x;temp.y=endpt[j].y;
diffx=endpt[j+1].x-endpt[j].x;
diffy=endpt[j+1].y-endpt[j].y;
int absx=0;
int absy=0;
if(diffx!=0)absx=diffx/abs(diffx);
if(diffy!=0)absy=diffy/abs(diffy);
int maxdis=max(abs(diffx),abs(diffy));
for(int i=0;i<maxdis;i++)
{
if(temp.x!=endpt[j+1].x)
temp.x=temp.x+absx;
if(temp.y!=endpt[j+1].y)
temp.y=temp.y+absy;
insertpt.push_back(temp);
}
if(j==0)
insertpt.push_back(newpt);
}
vecContour.insert(vecContour.begin()+insertindex,insertpt.begin(),insertpt.end());
memset(pContourMask,0,sWidth*sHeight);
for(vector<Pt2D>::iterator it=vecContour.begin();it!=vecContour.end();it++)
{
int pos=it->y*sWidth+it->x;
pContourMask[pos]=1;
}
return true;
}