图像轮廓缺陷修补
通过简单的二值化和边缘提取可以得到封闭的图像轮廓。但大多数边缘提取算子得到的轮廓都可能存在缺陷,即轮廓不封闭。如:Cannyl算子,通过调节两个 阈值可以有效提取目标轮廓,但并不保证轮廓的封闭性,因此往往需要对轮廓进行进一步处理。可以使用闭运算等形态学操作来对轮廓进行处理,但作为像素点级别 的形态学操作往往不能满足要求,如:两条轮廓线相距仅为一个像素,在进行闭运算操作时会使这两条轮廓粘连在一起。
图像轮廓修补仅需要对轮廓端点进行处理,而不是轮廓上的每一个点。对轮廓端点的定义为:对于轮廓上的任意一点,如果满足其8领域按顺时针或逆时针方向像素 值变化次数为0次或者2次,则该点为轮廓端点。当变化次数为0次时,该点为孤立点,即轮廓的两个端点重合。任意两端点之间的距离不大于给定阈值时,用直线 连接这两个端点。
![](http://www.cqthx.com/mr/upload/defectcontour.jpg)
![](http://www.cqthx.com/mr/upload/defectsrepair.jpg)
#include <vector> #include "cxcore.h" #pragma comment(lib, "cxcore.lib") // 缺陷修补 // 参数: // 1. pBinary: 输入二值图像,单通道,位深IPL_DEPTH_8U。 // 2. fDisThre: 距离阈值,当两轮廓端点距离小于等于fDisThre时,进行修补。 void DefectsRepair(IplImage *pBinary, float fDisThre) { int x, y, i, j; int x0, x1, x2; int n, dx, dy, nSize; unsigned char *pLine[3]; float fDistance; CvPoint ptPoint; // 轮廓端点坐标 std::vector<CvPoint> vecPoint; // 执行条件 if (pBinary) { for (y = 1; y < pBinary->height - 1; y++) { pLine[0] = (unsigned char*) (pBinary->imageData + pBinary->widthStep * (y - 1)); pLine[1] = (unsigned char*) (pBinary->imageData + pBinary->widthStep * y); pLine[2] = (unsigned char*) (pBinary->imageData + pBinary->widthStep * (y + 1)); for (x = 1; x < pBinary->width - 1; x++) { if (pLine[1][x] > 0) { n = 0; x0 = x - 1; x1 = x; x2 = x + 1; if (pLine[0][x0] != pLine[0][x1]) n++; if (pLine[0][x1] != pLine[0][x2]) n++; if (pLine[0][x2] != pLine[1][x2]) n++; if (pLine[1][x2] != pLine[2][x2]) n++; if (pLine[2][x2] != pLine[2][x1]) n++; if (pLine[2][x1] != pLine[2][x0]) n++; if (pLine[2][x0] != pLine[1][x0]) n++; if (pLine[1][x0] != pLine[0][x0]) n++; // 孤立点 if (n == 0) { if (pLine[1][x] != pLine[0][x0]) { ptPoint.x = x; ptPoint.y = y; vecPoint.push_back(ptPoint); } } // 轮廓端点 else if (n == 2) { ptPoint.x = x; ptPoint.y = y; vecPoint.push_back(ptPoint); } } } } // 缺陷修补 nSize = (int) vecPoint.size(); for (i = 0; i < nSize - 1; i++) { for (j = i + 1; j < nSize; j++) { dx = vecPoint[i].x - vecPoint[j].x; dy = vecPoint[i].y - vecPoint[j].y; fDistance = (float) (dx * dx + dy * dy); if (fDistance <= fDisThre * fDisThre) { cvLine(pBinary, vecPoint[i], vecPoint[j], CV_RGB(255, 255, 255), 1, 8, 0); } } } } }