这个算法也是看到有的的,不算复杂,但算法让是个好算法。while(!FindPoint)是关键,它保证了在循环里面找到的点是边界点而不是内部点。
上代码
void CImageColorProcess::TraceContour(LPBYTE lpSrc, LPBYTE lpDst, LPBYTE lpDst_, int nSrcCount, int nW, int nH)
{
this->OSTUThreshold(lpSrc, lpDst_, nSrcCount, nW, nH);//大律法二值化
bool bFindStartPoint;//是否找到起始点及回到起始点
bool bFindPoint;//是否找到一个边界点
int Direction[8][2] = { { -1, 1 }, { 0, 1 }, { 1, 1 }, { 1, 0 },
{ 1, -1 }, { 0, -1 }, { -1, -1 }, { -1, 0 } };//八个方向和起始扫描方向
int BeginDirect;
Point StartPoint, CurrentPoint;//起始点及当前边界点
for (int i = 0; i < nH; i++)// 目标图像设定初始值为背景255
{
for (int j = 0; j < nW; j++)
{
lpDst[i*nW + j] = 255;
}
}
bFindStartPoint = false;
for (int j = 0; j < nH&&!bFindStartPoint; j++)
{
for (int i = 0; i < nW&&!bFindStartPoint; i++)
{
if (lpDst_[(nH-1-j)*nW + i] == 0)// 指向源图像倒数第j行,第i个象素的指针
{
bFindStartPoint = true;
StartPoint.m_row = j;
StartPoint.m_col = i;
lpDst[(nH - 1 - j)*nW + i] = 0;
}
}
}
//由于起始点是在左下方,故起始扫描沿左上方向
BeginDirect = 0;
bFindStartPoint = false;
//从初始点开始扫描
CurrentPoint.m_row = StartPoint.m_row;
CurrentPoint.m_col = StartPoint.m_col;
while (!bFindStartPoint)
{
bFindPoint = false;
while (!bFindPoint)
{
//沿扫描方向查看一个像素
if (lpDst_[(nH-1-(CurrentPoint.m_row + Direction[BeginDirect][1]))*nW + CurrentPoint.m_col
+ Direction[BeginDirect][0]] == 0)
{
bFindPoint = true;
CurrentPoint.m_row = CurrentPoint.m_row + Direction[BeginDirect][1];
CurrentPoint.m_col = CurrentPoint.m_col + Direction[BeginDirect][0];
if (CurrentPoint.m_row == StartPoint.m_row&&CurrentPoint.m_col == StartPoint.m_col)
{
bFindStartPoint = true;
}
lpDst[(nH-1-CurrentPoint.m_row)*nW + CurrentPoint.m_col] = 0;
//扫描的方向逆时针旋转两格
BeginDirect--;
if (BeginDirect == -1)
BeginDirect = 7;
BeginDirect--;
if (BeginDirect == -1)
BeginDirect = 7;
}
else
{
//扫描方向顺时针旋转一格
BeginDirect++;
if (BeginDirect == 8)
BeginDirect = 0;
}
}
}
}
经测试发现该算法对整个相连的轮廓检测较好,如果遇到了琐碎的小轮廓它可能找到的就是这个小轮廓,导致大轮廓检测失败。上一组测试图片:
版权声明: