软件设计(中线提取优化)

前面的简单提取程序只能让小车跑起来,并不能很完美的跑,这也跟提取出来的中线有关,因为那样提取出的中线,不连续,不具备很好的跟随性,这次,介绍一种跟随性较好的中线提取算法。
在这里插入图片描述

  • 当我们图像失真时,我们可以通过数学的思想来算出他没有显示在图像上的点,也就是说假设我们第三行的右边界丢失,但是我们已经得到了第一行和第二行的坐标,那我们可以通过这两个点来确定一条直线,而第三行的点也会在这个直线附近(利用已知2点计算出补线坐标)代码如下:
int16 Calculate_Add(uint8 i, float Ka, float Kb)	// 计算补线坐标
{
	float res;
	int16 Result;

	res = i * Ka + Kb;
	Result = range_protect2((int32)res, 1, CAMERA_W-1);	//限幅

	return Result;
}

这就是简单的y=kx+b的方程

  • 有了斜率补线,我们还需要知道哪些需要补线,哪些不需要补线,所以我们还要设置一个补线标志位,所以我们在进行左右遍历时,同时也需要记录下哪些需要补线,哪些不需要补线,代码如下:

void Traversal_Mid_Line(uchar i, uint8 (*data)[CAMERA_W], uchar Mid, uchar Left_Min, uchar Right_Max, uchar *Left_Line, uchar *Right_Line, uchar *Left_Add_Line, uchar *Right_Add_Line)
{
	uchar j;
	
	Left_Add_Flag[i] = 1;	// 初始化补线标志位
	Right_Add_Flag[i] = 1;
	
	Left_Min = range_protect2(Left_Min, 1, 79);	// 限幅,防止出错
	
	Right_Max = range_protect2(Right_Max, 1, 79);
	
	
	Right_Line[i] = Right_Max;
	Left_Line[i] = Left_Min;	// 给定边界初始值
	
	for (j = Mid; j >= Left_Min; j--)	// 以前一行中点为起点向左查找边界
	{
		if (!data[i][j])	// 检测到黑点
		{
			Left_Add_Flag[i] = 0;	//左边界不需要补线,清除标志位
			Left_Line[i] = j+1;	//记录当前j值为本行实际左边界
			Left_Add_Line[i] = j+1;	// 记录实际左边界为补线左边界
			
			break;
		}
	}
        
	for (j = Mid; j <= Right_Max; j++)	// 以前一行中点为起点向右查找右边界
	{
		if (!data[i][j])	//检测到黑点
		{
			Right_Add_Flag[i] = 0;		//右边界不需要补线,清除标志位
			Right_Line[i] = j-1;	//记录当前j值为本行右边界
			Right_Add_Line[i] = j-1;	// 记录实际右边界为补线左边界
			
			break;
		}
	}
      
	if (Left_Add_Flag[i])	// 左边界需要补线
	{
		if (!data[(i-2)][Left_Add_Line[i+2]] || !data[(i-4)][Left_Add_Line[i+2]])	// 可能是反光干扰
		{
			Left_Add_Flag[i] = 0;	//左边界不需要补线,清除标志位
			Left_Line[i] = Left_Add_Line[i+2];		//记录当前j值为本行实际左边界
			Left_Add_Line[i] = Left_Add_Line[i+2];	// 记录实际左边界为补线左边界
		}
		else
		{
			if (i >= 55)	// 前6行
			{
				Left_Add_Line[i] = Left_Line[59];	// 使用底行数据
			}
			else
			{
				Left_Add_Line[i] = Left_Add_Line[i+2];	// 使用前2行左边界作为本行左边界
			}
		}
	}
	if (Right_Add_Flag[i])	// 右边界需要补线
	{
		if ((!data[(i-2)][Right_Add_Line[i+2]])|| (!data[(i-4)][Right_Add_Line[i+2]]))	// 可能是反光干扰
		{
			Right_Add_Flag[i] = 0;	//左边界不需要补线,清除标志位
			Right_Line[i] = Right_Add_Line[i+2];		//记录当前j值为本行实际左边界
			Right_Add_Line[i] = Right_Add_Line[i+2];	// 记录实际左边界为补线左边界
		}
		else
		{
			if (i >= 55)	// 前6行
			{
				Right_Add_Line[i] = Right_Line[59];	// 使用底行数据
			}
			else
			{
				Right_Add_Line[i] = Right_Add_Line[i+2];	// 使用前2行右边界作为本行右边界
			}
		}
	}
	Width_Real[i] = Right_Line[i] - Left_Line[i];			// 计算实际赛道宽度
	Width_Add[i] = Right_Add_Line[i] - Left_Add_Line[i];	// 计算补线赛道宽度
}

  • 后面呢,就是检测补线
        if (Left_Add_Flag[i])	// 左侧需要补线
		{
			if (i >= 53)	// 前三行补线不算
			{
				if (!Left_Add_Start)
				{
					Left_Add_Start = i;	// 记录补线开始行
					Left_Ka = 0;
					Left_Kb = Left_Add_Line[i+2];
				}
				Left_Add_Line[i] = Calculate_Add(i, Left_Ka, Left_Kb);	// 使用前一帧图像左边界斜率补线
			}
			else
			{
				if (!Left_Add_Start)	// 之前没有补线
				{
					Left_Add_Start = i;	// 记录左侧补线开始行
					Curve_Fitting(&Left_Ka, &Left_Kb, &Left_Add_Start, Left_Add_Line, Left_Add_Flag, 1);	// 使用两点法拟合直线
				}
				Left_Add_Line[i] = Calculate_Add(i, Left_Ka, Left_Kb);	// 补线完成
			}
		}
		else
		{
			if (Left_Add_Start)	// 已经开始补线
			{
				if (!Left_Add_Stop && !Left_Add_Flag[i+2])
				{
					if (Left_Add_Line[i] >= Left_Add_Line[i+2])
					{
						Left_Add_Stop = i;	// 记录左侧补线结束行
					}
				}
			}
		}
  • 所以的线都补好后就可以开始求中线了
for (i = 59; i >= 9;)
	{
		i -= 2;
		Mid_Line[i] = (Right_Add_Line[i] + Left_Add_Line[i]) / 2;	// 计算赛道中点
		Width_Add[i] = Right_Add_Line[i] - Left_Add_Line[i];		// 计算赛道宽度
	}

由于一些原因代码无法公开,限于作者水平有限,这里只供新手参考思想,更往各位大神指点,讨论^ - ^/…

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值