简介
什么是图像的轮廓?在这里不去深入研究它的定义,简单的理解,当人站在太阳下,产生的影子的边界就是轮廓。大致是这样子吧。
轮廓提取的原理
做为一个初学者,试想如果提取轮廓?我首先想到的是沿着轮廓边界搜索。很显然,每个点有8个相邻点也就是8个方向,只要对每个点的8个方向做递归判断就可以了吧。这是我初次接触轮廓提取时的第一想法。当然,轮廓提取应该有很多算法,我是个学习者,并没有充足的时间去把每种轮廓算法研究一遍。我的做法是找到轮廓算法的大致原理,并尝试实现它。然后在学习数字图像处理的其他部分。
有一种算法原理是这样的:
或许该称之为转体算法吧,这种算法每找到一个边界点,就以该点为当前点,检测它的8个临域。
c++版轮廓提取:
///find first boundry point
vector<cqPoint> boundryPoints;
int x;
int y;
int flag = 1;
for (x = 1; x < width; x++)
{
for (y = height -1; y > 0; y --)
{
if (dst.at<uchar>(y,x)== 255 )
{
boundryPoints.push_back(cqPoint(x, y));
globleX = x;
globleY = y;
mydebug (x<<"::"<<y);
goto end;
}
}
}
///first boundry point is x,y. begin scan from postion of 2
end:cqBackTrace(x, y, 2, dst, boundryPoints, flag);
///
/// \brief cqAlgorithm::cqBackTrace
/// \param x: x of current boundry point
/// \param y: y of current boundry point
/// \param pos: the postion of boundry point's neighbor
/// 4- 5- 6
/// 3 -P -7
/// 2 -1- 8
/// \param srcMat: image
/// \param boundryPoints: all found boundry points are stored in here
///
void cqAlgorithm::cqBackTrace(int x, int y, int pos, cv::Mat srcMat, vector<cqPoint> boundryPoints, int& flag)
{
///
///flag 0 means to stop the backtrace,otherwise continue
///
if (flag)
{
cq8Neighbor neighbor (x, y);//create neighbor of current boundry x,y
cqPoint curPoint = neighbor.getPointByPosition(pos);
int curPointX = curPoint.getX();
int curPointY = curPoint.getY();
int value = srcMat.at<uchar>(curPointY, curPointX);
///
///boundry point is fond;
///
if (value)
{
mydebug ("boundry is fond");
///
///if back to start point, then boundry search has been finished
///
if (globleX == curPointX and globleY == curPointY)
{
mydebug (curPointX<< ":"<< curPointY);
mydebug ("is start point");
flag = 0;
}
///
///if not return to the start point, then continue our search
///
else
{
mydebug ("not start point");
///add boundry point to boundryPoints vector
boundryPoints.push_back(curPoint);
///change the value to let us see succeed in find a bountry point
srcMat.at<uchar>(curPointY, curPointX) = 50;
mydebug (curPointX<< ":"<< curPointY);
///since new boundry is found, this point will set to be the current point, and we are going to search the
/// neighbor of this point, the index of neighbor is given by pos
if (pos == 1 or pos == 2)
cqBackTrace(curPointX, curPointY, 7, srcMat, boundryPoints, flag);
if (pos == 3 or pos == 4)
cqBackTrace(curPointX, curPointY, 1, srcMat, boundryPoints, flag);
if (pos == 5 or pos == 6)
cqBackTrace(curPointX, curPointY, 3, srcMat, boundryPoints, flag);
if (pos == 7 or pos == 8)
cqBackTrace(curPointX, curPointY, 5, srcMat, boundryPoints, flag);
}
}
///
///boundry point is not found,move to next pos and check again
///
else
{
if (8 == pos)
cqBackTrace(x, y, 1, srcMat, boundryPoints, flag);
else
cqBackTrace(x, y, pos + 1, srcMat, boundryPoints, flag);
}
}
}
在我的QT程序中显示的寻找边界的结果,找到边界后,把该边界点像素值降低,用来告诉我们成功找到。
其中比较有意思的一个问题是:当找到一个新的边界点后,以这个新边界点为中心,搜索临域,但是每个点有8个临域,该从哪个临域开始搜索呢?
这个图可以帮助我们理解上面的问题,只要自己动手实践,所有的问题都会迎刃而解。