最近在学习图像处理的知识,在图像分割部分学习过程中,遇到外边界追踪算法,刚看到该内容时觉得有点抽象,但在理清头绪后觉得其实很简单,主要涉及起始点的寻找和追踪准则的应用,有点类似《数据结构》中栈的应用(当时写了一个迷宫寻路程序),这篇文章希望能够帮助初学者更好更快的理解该知识点原理。
追踪算法原理(字数有点长,截取的书本内容,请见谅):
算法简述:
1.找出原图(二值图像)中第一个边界像素,图片的读取顺序一般为从下到上,从左到右,所以读取的第一个边界像素通常靠左下。
2.按照上述的追踪准则进行像素追踪,直到像素点闭合结束。即
(1)确定第一个边界点(起始点 startpoint)
(2)初设追踪方向为右上(0号方向),当然,其他方向也可以,根据自己的图像确定。
(3)判断下一个像素是否为边界像素,是,则更新当前像素(currentpoint)位置,并将输出图像的该点置为0或者255(便于观察),然后将追踪方向逆时针旋转90°,进行下一次追踪。否则,将追踪方向顺时针旋转45°,继续判断下一个点是否为边界,后续步骤同前。
(4)循环,直至初始点与当前点闭合
表达能力有限,没看懂可以直接看代码,注释比较详细
代码实现:
void picture_segmentation::contour_track(Mat& src)//边界像素追踪法
{
Mat image = src.clone();
Mat image_1=Mat::zeros(image.size(),image.type());//新显示图片
for (int i = 0; i < image_1.rows; i++)
{
for (int j = 0; j < image_1.cols; j++)
{
image_1.at<uchar>(i, j) = 255;
}
}
int width = image_1.cols;
int higth = image_1.rows;
int channels = image_1.channels();
cout << "width " << width << " higth" << higth << "channels:" << channels << endl;
//进行二值化处理
for (int i = 0; i < higth; i++)
{
for (int j = 0; j < width; j++)
{
if (image.at<uchar>(i, j) > 230)
{
image.at<uchar>(i, j) = 255;
}
else
{
image.at<uchar>(i, j) = 0;
}
}
}
namedWindow("二值化图像", WINDOW_FREERATIO);
imshow("二值化图像", image);
int dir[8][2] = { {-1,-1},//-135° 0
{0,-1},//-90° 1
{1,-1},//-45° 2
{1,0},//0° 3
{1,1},//45° 4
{0,1},//90° 5
{-1,1},//135° 6
{-1,0} };//180° 7
//边界追踪
Point startpoint;//起始点
Point currentpoint;//当前点
for (int i = 1; i < higth-1; i++)//寻找起始点 图片读取方式 从左到右,从下到上
{
for (int j = 1; j < width-1; j++)
{
int pixex = image.at<uchar>(i, j);
if (pixex == 0)//是图像的边界点
{
startpoint.x = j;
startpoint.y = i;
//找到边界点就将新图像上的该点置为0
image_1.at<uchar>(i, j) = 0;
break;
}
}
}
//初始追踪方向定为左上
int startdir = 0;
//从初始点开始扫描
currentpoint.x = startpoint.x;
currentpoint.y = startpoint.y;
while (1)
{
//查看扫描方向的下一个像素
int pixex = image.at<uchar>(currentpoint.y + dir[startdir][1], currentpoint.x + dir[startdir][0]);
if (pixex == 0)//还是边界点
{
//更新当前点
currentpoint.y = currentpoint.y + dir[startdir][1];
currentpoint.x = currentpoint.x + dir[startdir][0];
//将新图像该点像素置为0
image_1.at<uchar>(currentpoint.y, currentpoint.x)=0;
//判断是否已经闭合
if (currentpoint.y == startpoint.y && currentpoint.x == startpoint.x)
{
break;
}
//更新新的搜索方向
//逆时针旋转90°
startdir--;
if (startdir == -1)
{
startdir = 7;
}
startdir--;
if (startdir == -1)
{
startdir=7;
}
}
else//不是边界点
{
//扫描方向顺时针旋转45
startdir++;
if (startdir == 8)
{
startdir = 0;
}
}
}
namedWindow("外边界像素追踪", WINDOW_FREERATIO);
imshow("外边界像素追踪", image_1);
}
运行结果:
看着不连续,其实是显示问题,用image watch看是正常的。
tip:
第一次发文章,自己也只是个初学者,只是进行分享,希望能帮更多像我一样的人,不足之处请谅解