opencv 外边界追踪算法的原理及其C++实现

最近在学习图像处理的知识,在图像分割部分学习过程中,遇到外边界追踪算法,刚看到该内容时觉得有点抽象,但在理清头绪后觉得其实很简单,主要涉及起始点的寻找和追踪准则的应用,有点类似《数据结构》中栈的应用(当时写了一个迷宫寻路程序),这篇文章希望能够帮助初学者更好更快的理解该知识点原理。

追踪算法原理(字数有点长,截取的书本内容,请见谅):

算法简述:

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:

第一次发文章,自己也只是个初学者,只是进行分享,希望能帮更多像我一样的人,不足之处请谅解

  • 15
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值