问题:目前分割得到的圆形边缘和理想边缘相比,部分向外偏离,需要向内收缩
探索方法1:
假设在理想情况下,圆形物体的掩膜是绝对正确的。此时可以遍历当前的边缘点,判断每个边缘点的两侧的掩膜标记是否不同。如果两侧的邻域点掩膜都为0,说明该边缘点偏外,需要向内收缩,使用最近的掩膜点来替换掉越界了的点。
但是此方法在项目中行不通,因为项目中的掩膜文件是有误差的,不能表示正确的圆形。
下面记录一下此方法的实现代码:
//找出两侧都是0的点,说明此处需要收缩
while (i < vecCurContour.size() - 1)
{
Pt2D curPos(vecCurContour[i]);
Pt2D nextPos(vecCurContour[i + 1]);
int diffx = nextPos.x - curPos.x;
int diffy = nextPos.y - curPos.y;
Pt2D sideA = { curPos.x + diffy, curPos.y - diffx };
Pt2D sideB = { curPos.x - diffy, curPos.y + diffx };
//检测两侧的邻域点是否都为0
long a = sideA.y*sWidth + sideA.x;
long b = sideB.y*sWidth + sideB.x;
if (!(pMaskBuf[a] == 0 && pMaskBuf[b] == 0))
{
i++;
continue;
}
else
{
//起点已找到
int begin = i - 1;
//从此点开始,寻找待处理的线段的终点
while (i < vecCurContour.size() - 1)
{
curPos = vecCurContour[i];
nextPos = vecCurContour[i + 1];
diffx = nextPos.x - curPos.x;
diffy = nextPos.y - curPos.y;
Pt2D sideA = { curPos.x + diffy, curPos.y - diffx };
Pt2D sideB = { curPos.x - diffy, curPos.y + diffx };
//检测两侧的邻域点是否都为0
a = sideA.y*sWidth + sideA.x;
b = sideB.y*sWidth + sideB.x;
if ((pMaskBuf[a] == 0 && pMaskBuf[b] == 1) ||
(pMaskBuf[a] == 1 && pMaskBuf[b] == 0))
break;
i++;
}
//终点已找到
int end = i;
if (begin < 0) continue;
int Neb[8][2] = EIGHT_NEIGHBORHOOD2;
int dir = 0;
/*接着继续查找下一段的起点(在前一段圆弧修正之后,下一段正确的圆弧也需要跟着做些微调整,
以保证整个圆形边缘的光滑度*/
int newend = end;
int nextstart = end;
while (i < vecCurContour.size() - 2)
{
i++;
curPos = vecCurContour[i];
nextPos = vecCurContour[i + 1];
diffx = nextPos.x - curPos.x;
diffy = nextPos.y - curPos.y;
Pt2D sideA = { curPos.x + diffy, curPos.y - diffx };
Pt2D sideB = { curPos.x - diffy, curPos.y + diffx };
//检测两侧的邻域点是否都为0
a = sideA.y*sWidth + sideA.x;
b = sideB.y*sWidth + sideB.x;
if (pMaskBuf[a] == 0 && pMaskBuf[b] == 0)
{
if (i - end > 3)
break;
else
end = i;
}
}
nextstart = i - 1;
//方法:使用最近的初始边缘点来替换掉越界了的点
dir = 0;
queue addPt;//用来替换的点
//需要确保起点是和初始的边缘重合的
bool isFind = false;
int findnum = begin > 6 ? 6 : begin;
int findindex;
for (findindex = 1; findindex < findnum; findindex++)
{
int pos = vecCurContour[begin - findindex].y*sWidth +
vecCurContour[begin - findindex].x;
if (pContourMask[pos]){ isFind = true; break; }
}
if (!isFind)
{
//如果没有找到,则用宽度优先,寻找最近的初始边缘点
queue qfindpt;
qfindpt.push(vecCurContour[begin]);
while (!qfindpt.empty() && !isFind)
{
Pt2D pt = qfindpt.front();
qfindpt.pop();
for (int i = 0; i < 8; i++)
{
int x = pt.x + Neb[i][1];
int y = pt.y + Neb[i][0];
int pos = y*sWidth + x;
if (x >= 0 && x < sWidth && y >= 0 && y < sHeight)
{
if (pContourMask[pos])
{
Pt2D temp = { x, y };
addPt.push(temp);
isFind = true;
break;
}
Pt2D temp = { x, y };
qfindpt.push(temp);
}
}
}
}
else
{
begin -= findindex;
addPt.push(vecCurContour[begin]);
}
int dir = 0;
for (int index = begin; index < end; index++)
{
Pt2D curPt;
Pt2D newPt;
if (index == begin)
{
curPt = vecCurContour[index];
//计算初始方向
int diffx = vecCurContour[index + 1].x - vecCurContour[index].x;
int diffy = vecCurContour[index + 1].y - vecCurContour[index].y;
if (diffy == -1)
dir = diffx + 2;
else if (diffy == 0)
dir = (diffx == -1) ? 0 : 4;
else if (diffy == 1)
dir = 6 - diffx;
}
for (int i = 0; i < 8; i++)
{
int xx = curPt.x + Neb[dir][1];
int yy = curPt.y + Neb[dir][0];
long lNewOff = yy * sWidth + xx;
if (xx >= 0 && xx < sWidth && yy >= 0 && yy < sHeight)
{
if (pContourMask[lNewOff])
{
newPt.x = (SINT)xx;
newPt.y = (SINT)yy;
addPt.push(newPt);
curPt = newPt;
if (dir % 2 == 0)
{
dir = (dir + 7) % 8;
}
else
{
dir = (dir + 6) % 8;
}
break;
}
else
dir = (dir + 1) % 8;
}
else
dir = (dir + 1) % 8;
}
}
//替换点
for (int index = begin; index <= end; index++)
{
vecCurContour[index].x = addPt.front().x;
vecCurContour[index].y = addPt.front().y;
addPt.pop();
}
//计算nextstart和endpt之间的新线段,保证圆弧的光滑
//两个点之间连线
if (nextstart - end > 3)
{
Pt2D temp = vecCurContour[end];
vector insertpt;
int diffx = vecCurContour[end].x - vecCurContour[nextstart].x;
int diffy = vecCurContour[end].y - vecCurContour[nextstart].y;
int absx = 0, 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 != vecCurContour[nextstart].x)
temp.x = temp.x + absx;
if (temp.y != vecCurContour[nextstart].y)
temp.y = temp.y + absy;
insertpt.push_back(temp);
}
//替换点
vecCurContour.erase(vecCurContour.begin()+end+1,
vecCurContour.begin()+nextstart);
vecCurContour.insert(vecCurContour.begin()+end+1,
insertpt.begin(),insertpt.end());
i += (end - begin + insertpt.size() + 1);
}
else
i += end - begin + 1;
break;