八领域边界追踪算法

八领域边界追踪 C语言

其中_Binary为输入的bmp二值化图像,_TracingPtr为轮廓空间点(类型为结构体)

typedef struct Contours
{
	int height;
	int width;
	int stateFlag;
} contour;

void edgeTracing( const unsigned char* _Binary, contour** _TracingPtr, const int _Width, const int _Height )
{
	unsigned char* _Mark = NULL;//标记矩阵
	int direction[8][2] = { 0,-1, -1,-1, -1,0, -1,1, 0,1, 1,1, 1,0, 1,-1 };//方向数组
	int i = 0, j = 0;//行、列计数
	int start_I = 0, start_J = 0;//轮廓的起始点
	int rec_I = 0, rec_J = 0;//待检测轮廓点坐标
	int mov_I = 0, mov_J = 0;//待检测轮廓点周围8领域逆时针旋转点
	int tmp_I = 0, tmp_J = 0;//临时点保存
	int point_Count = 0;//轮廓点计数
	int direc_Count = 0;//方向转次数计数
	int rot_Direct = 0;//方向数组计数
	int stepWidth = (_Width + 3) & ~3;//灰度图行步长
	int contour_Succe_Flag = 0;//轮廓寻找成功标志位
	int contour_Point_Now = 0;//现已开辟轮廓空间点数量
	int contour_Point_Add = 0;//需要增加的轮廓空间点数量
	contour* ptr_Contour_First = NULL;//轮廓点数组首地址


	contour_Point_Now = 4 * (_Width+_Height);
	contour_Point_Add = _Width + _Height;
	*_TracingPtr = (  contour *)malloc( contour_Point_Now * sizeof( contour) );//为储存轮廓点创建内存块
	ptr_Contour_First = *_TracingPtr;
	_Mark = ( unsigned char*)malloc( stepWidth*_Height );//轮廓标记矩阵
	memset(_Mark, 0, stepWidth*_Height);//轮廓标记矩阵清零
	for ( i = 0; i < _Height; i ++ )
	{
		for ( j = 1; j < _Width; j ++ )
		{
			if ( 255 == _Binary[ i*stepWidth + j - 1] && 0 == _Binary[ i*stepWidth + j] && 0 == _Mark[i*stepWidth + j] )
			{
				direc_Count = 0;//方向计数置零
				rot_Direct = 0;//旋转方向计数置零
				start_I = i;//保存每个轮廓的起始点
				start_J = j;
				rec_I = i;//存储第一个b点的行坐标
				rec_J = j;//存储第一个b点的列坐标
				mov_I = i;//存储第一个c点的行坐标
				mov_J = j-1;//存储第一个c点的列坐标
				while ( direc_Count < 8 && mov_I > 0 && mov_I < _Height && mov_J > 0 && mov_J < _Width )
				{
					direc_Count ++;
					rot_Direct ++;//顺时针方向转45°
					if ( 8 == rot_Direct) rot_Direct = 0;//使方向循环且不溢出
					mov_I = rec_I + direction[rot_Direct][0];//转完之后c点的行坐标
					mov_J = rec_J + direction[rot_Direct][1];//转完之后c点的列坐标
					if ( 0 == _Binary[ mov_I*stepWidth + mov_J]
						&& mov_I > 0 && mov_I < _Height
						&& mov_J > 0 && mov_J < _Width
						&& ( start_I != mov_I || start_J != mov_J ) )
					{
						if ( 0 == rot_Direct ) rot_Direct = 7;//方向回到上一个角度
						else rot_Direct --;
						
						tmp_I = rec_I;//记录变换前b点行坐标
						tmp_J = rec_J;//记录变换前b点列坐标
						rec_I = mov_I;//新的c点坐标赋值给b点
						rec_J = mov_J;
						mov_I = tmp_I + direction[rot_Direct][0];//将上一个c点坐标赋值给新c点坐标
						mov_J = tmp_J + direction[rot_Direct][1];

						direc_Count = 0;//方向次数计数清零

						if ( rec_I > mov_I )//计算现在c点相对b点的方位
							rot_Direct = 2;
						else if ( rec_I < mov_I )
							rot_Direct = 6;
						else if ( rec_J > mov_J )
							rot_Direct = 0;
						else if ( rec_J < mov_J )
							rot_Direct = 4;
					}
					else if ( start_I == mov_I && start_J == mov_J )
					{
						//如果等于起始点,则重新遍历该轮廓,标记轮廓并储存轮廓点
						if ( point_Count > contour_Point_Now-1 )
						{
							//若轮廓空间点超出范围,则加入额外轮廓空间点
							ptr_Contour_First = (  contour *)malloc( contour_Point_Now * sizeof( contour) );
							memcpy( ptr_Contour_First, *_TracingPtr, contour_Point_Now * sizeof( contour) );
							*_TracingPtr = (  contour *)malloc( (contour_Point_Now + contour_Point_Add) * sizeof( contour) );
							memcpy( *_TracingPtr, ptr_Contour_First, contour_Point_Now * sizeof( contour) );
							contour_Point_Now += contour_Point_Add;
							free( ptr_Contour_First);
							ptr_Contour_First = NULL;
							ptr_Contour_First = *_TracingPtr;
						}
						
						ptr_Contour_First[ point_Count].height = start_I;//储存起始点
						ptr_Contour_First[ point_Count].width = start_J;
						ptr_Contour_First[ point_Count].stateFlag = 1;//状态标志位stateFlag:
																	  //1为起始点,0为普通边缘点,2为结束点
						_Mark[ start_I*stepWidth + start_J] = 255;//标记为已搜索过的点

						direc_Count = 0;//方向计数置零
						rot_Direct = 0;//旋转方向计数置零
						rec_I = start_I;//存储b点的行坐标
						rec_J = start_J;//存储b点的列坐标
						mov_I = start_I;//存储 c点的行坐标
						mov_J = start_J-1;//存储c点的列坐标
						while ( direc_Count < 8 && mov_I > 0 && mov_I < _Height && mov_J > 0 && mov_J < _Width )
						{
							direc_Count ++;
							rot_Direct ++;//顺时针方向转45°
							if ( 8 == rot_Direct) rot_Direct = 0;//使方向循环且不溢出
							mov_I = rec_I + direction[rot_Direct][0];//转完之后c点的行坐标
							mov_J = rec_J + direction[rot_Direct][1];//转完之后c点的列坐标
							if ( 0 == _Binary[ mov_I*stepWidth + mov_J]
								&& mov_I > 0 && mov_I < _Height
								&& mov_J > 0 && mov_J < _Width
								&& ( start_I != mov_I || start_J != mov_J ) )
							{
								if ( 0 == rot_Direct ) rot_Direct = 7;//方向回到上一个角度
								else rot_Direct --;

								tmp_I = rec_I;//记录变换前b点行坐标
								tmp_J = rec_J;//记录变换前b点列坐标
								rec_I = mov_I;//新的c点坐标赋值给b点
								rec_J = mov_J;
								mov_I = tmp_I + direction[rot_Direct][0];//将上一个c点坐标赋值给新c点坐标
								mov_J = tmp_J + direction[rot_Direct][1];

								direc_Count = 0;//方向次数计数清零

								if ( rec_I > mov_I )//计算现在c点相对b点的方位
									rot_Direct = 2;
								else if ( rec_I < mov_I )
									rot_Direct = 6;
								else if ( rec_J > mov_J )
									rot_Direct = 0;
								else if ( rec_J < mov_J )
									rot_Direct = 4;

								point_Count ++;//压入新点之前,轮廓计数自加

								if ( point_Count > contour_Point_Now-1 )
								{
									//若轮廓空间点超出范围,则加入额外轮廓空间点
									ptr_Contour_First = (  contour *)malloc( contour_Point_Now * sizeof( contour) );
									memcpy( ptr_Contour_First, *_TracingPtr, contour_Point_Now * sizeof( contour) );
									*_TracingPtr = (  contour *)malloc( (contour_Point_Now + contour_Point_Add) * sizeof( contour) );
									memcpy( *_TracingPtr, ptr_Contour_First, contour_Point_Now * sizeof( contour) );
									contour_Point_Now += contour_Point_Add;
									free( ptr_Contour_First);
									ptr_Contour_First = NULL;
									ptr_Contour_First = *_TracingPtr;
								}

								ptr_Contour_First[ point_Count].height = rec_I;//储存新轮廓点
								ptr_Contour_First[ point_Count].width = rec_J;
								ptr_Contour_First[ point_Count].stateFlag = 0;//状态标志位stateFlag:
																			  //1为起始点,0为普通边缘点,2为结束点
								_Mark[ rec_I*stepWidth + rec_J] = 255;//标记为已搜索过的点
							}
							else if ( start_I == mov_I && start_J == mov_J )
							{
								//如果等于起始点,则把之前最后一个点改为终点,跳出开始新的搜索
								ptr_Contour_First[ point_Count].stateFlag = 2;//状态标志位stateFlag:
																			  //1为起始点,0为普通边缘点,2为结束点
								contour_Succe_Flag = 1;//轮廓完整,标志位置一
								point_Count ++;//为下一个轮廓开辟一个新点
								break;
							}
						}						
					}

					if ( contour_Succe_Flag )//如果一个轮廓搜索并储存成功,则开始找新的起始点
					{
						contour_Succe_Flag = 0;//轮廓搜索成功标志位置零
						break;
					}
				}
			}
		}
	}
	ptr_Contour_First[0].stateFlag = point_Count;//将轮廓点数量保存在第一个空间点的状态位
}


评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值