这个算法也是看到有的的,不算复杂,但算法让是个好算法。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; } } } }
经测试发现该算法对整个相连的轮廓检测较好,如果遇到了琐碎的小轮廓它可能找到的就是这个小轮廓,导致大轮廓检测失败。上一组测试图片: