智能车数字图像处理算法入门及C语言实现

Posted -素心向暖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了智能车数字图像处理算法入门及C语言实现相关的知识,希望对你有一定的参考价值。

https://www.bilibili.com/video/BV1eL411L7NR?spm_id_from=333.999.0.0&vd_source=d59d7bc22106d87da35c63b8af6491e8

文章目录

图像简单处理附加提升

二值化 - 边缘提取 - 特征识别 - 补线 - 中心巡线 - 偏差曲率计算

图像二值化

0 - 255 >> 0 - 1
1. 固定阈值
最简单,不用
2. 动态阈值
由近向远逐行迭代阈值
3. 大津法
灰度直方图找谷底

数据示例

一行数据:
38 36 40 60 55 78 99 111 114 121 115 120 118 100 110 106 80 60 40 35 42 40 36

二值化:
0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0

边缘提取:
0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0

差比和计算偏差

if( (dat[0]-dat[1]/dat[0]+dat[1]) > 斜率阈值) dat[0]=1; dat[1]=1;

大津阈值法代码实现

// DMA 模块+外部中断结合,自动读取摄像头数据
#define pixel_num 4800
uchar image[pixel_num];	// 图像数组 60*80

// 大津法二值化
uint huidu[256]=0;	// 灰度直方图数组
uchar YUZHI;	// 二值化阈值

for(i=0; i<4800; i++)	// 遍历所有像素

	huidu[image[i]]++;	// 统计灰度直方图


uint H1=0, H2=0;	//第一、第二高峰海拔值
uchar D1=0, D2=0;	// 第一、第二高峰位置

#define KUAN 30	// 山峰宽度阈值

for(i=0; i<255; i++)	// 遍历灰度直方图

	if(huidu[i] > H1)	// 寻找最大值
	
		H1 = huidu[i];	// 记录海拔
		D1 = i;	// 记录位置
	
	


bit OK = 0;	// 是否找到第二高峰
/* 要找的是第二高峰,不是第二高点 */
for(i=H1-5; i>0; i-=5)	// 向下切,找第二高峰

	for(j=0; j<256; j++)	// 遍历这一行
	
		if(huidu[j] > i && abs(j-D1) > KUAN)	// 有上面部分
		
			H2 = i;	// 记录第二高峰海拔
			D2 = j;	// 记录第二高峰位置
			OK = 1;	// 标志置位
			break;
		
	
	if(OK)	break;	// 如果找到,直接跳出


uint L3=pixel_num;	// 山谷海拔值
uchar D3=0;	// 山谷位置
if(OK)	// 已经找到2座山

	if(D1<D2)	// 找山谷
	
		for(i=D1; i<D2; i++)
		
			if(huidu[i]<H3)	// 寻找最小值
			
				H3 = huidu[i];
				D3 = i;
			
		
	
	else
	
		for(i=D2; i<D1; i++)
		
			if(huidu[i]<H3)
			
				H3 = huidu[i];
				D3 = i;
			
		
	

	YUZHI = D3;	// 获取阈值

图像二值化代码实现

uchar image1[60][80];	// 二维图像临时处理数组1
uchar image2[60][80];	// 二维图像临时处理数组2

for(i=0; i<4800; i++)

	if(image[i]>YUZHI)	// 判断灰度值
	
		image1[i/80][i%80] = 1;	// 白点
	
	else
	
		image1[i/80][i%80] = 0;	// 黑点
	

图像处理

灵魂
通过关键点特征来判断

uchar AX, AY;	// A点
uchar BX, BY;	// B点
uchar CX, CY;	// C点
uchar DX, DY;	// D点

AY = 59;	// 获取 AB 点
BY = 59;
for(i=39; i>=1; i--)	// 从中间向左找上升

	if(image1[59][i] - image1[59][i-1] == 1// 找到上升沿 
	
		AX = i;	// A 横坐标
	


for(i=39; i<79; i++)	// 从中间向右找上升沿

	if(image1[59][i] - image1[59][i+1] == 1)	// 找到上升沿
	
		BX = i;	// B 横坐标
	 


CY = AY-1;	// 迭代 C 点
CX = AX-1;	// 去到下一行的边界黑点
for(i=CY; i>0; i--)	// 由近及远

	for(j=CX; j<80; j++)	// 由左向右
	
		if(image[i][j] == 1)	// 找到白点
		
			CX = j-1;	// 得到上一行黑点X位置
			break;
		
	
	if(image1[i-1][CX] == 1)	// 判断上方是否还有黑点
	
		CY = i;	// 得到C点Y位置
		break;
	


DY = BY-1;	// 迭代D点
DX = BX+1;	//	得到下面一行黑点 
for(i=DY; i>0; i--)	// 由近及远

	for(j=DX; j>0; j--)
	
		if(image1[i][j] == 1)	// 找到白点
		
			DX = j + 1;
			break;
		
	
	if(image1[i-1][DX] == 1)
	
		DY = i;
		break;
	


if(abs(CY-DY)<10) && CY > 30 && DY > 30)	// 初级判断十字路口 

	uchar Y = min(CY, DY);	// 获取CD高度较小值
	uchar HEI = 0;	// 十字路口上方区域黑点数量
	for(i=Y; i>Y-10; i-=2)	// Y抽点轮训
	
		for(j=10; j<70; j+=5)	// X抽点轮训
		
			if(image1[i][j] == 0)	// 如果有黑点
			
				HEI++;	// 计数变量++
			
		
	
	if(HEI < 10)	// 最终判断十字路口,并补线
	
		float K;	// 补线斜率
		K = (CX-AX)/(CY-AY);	// 计算AC点斜率

		for(i=CY; i>CY-20; i--)	// 补AC延长2像素宽线
		
			image1[i][CX+(CY-i)*K] = 0;	//把图像对应点涂黑
			image1[i][(CX+(CY-i)*K)-1] = 0;
		

		K = (DX-BX)/(DY-BY);	// 计算AC点斜率

		for(i=DY; i>DY-20; i--)	// 补AC延长2像素宽线
		
			image1[i][DX+(DY-i)*K] = 0;	//把图像对应点涂黑
			image1[i][(DX+(DY-i)*K)-1] = 0;
		
	

找中线代码实现

uchar ZHONGXIAN[60] = 39;	// 中线位置
uchar ZUO[60] = 0;	// 左线位置
ucahr YOU[60] = 79;	// 右线位置

// 先找最底下一行中心线
for(i=ZHONGXIAN[59]; i>=1; i--)	// 从中间向左找上升

	if(image1[59][i] - image1[59][i-1] == 1// 找到上升沿 
	
		ZUO[59] = i;
	


for(i=ZHONGJIAN[59]; i<79; i++)	// 从中间向右找上升沿

	if(image1[59][i] - image1[59][i+1] == 1)	// 找到上升沿
	
		YOU[59] = i;	// 右线
	 


ZHONGJIAN[59] = (ZUO[59] + YOU[59]) /2;	// 最底下一行中心线位置找到

完整实现

uchar ZHONGXIAN[60] = 39;	// 中线位置
uchar ZUO[60] = 0;	// 左线位置
ucahr YOU[60] = 79;	// 右线位置

for(i=59; i>=0; i--)	// 向上迭代中心线 ,从靠近摄像头到远离摄像头

	for(j=ZHONGJIAN[i]; j>=1; j--)	// 从中间向左找上升沿
	
		if(image1[i][j] - image1[i][j-1] == 1)	// 找到上升沿
			ZUO[i] = j;	// 左线
	
	for(j=ZHONGJIAN[i]; j<79; j++)	// 从中间向右找上升沿
	
		if(image1[i][j] - image1[i][j+1] == 1)	// 找到上升沿
			YOU[i] = j;	// 右线
	
	ZHONGJIAN[i] = (ZUO[i] + YOU[i]) / 2;	// 计算当前行中心点

优化

  1. 大湾
for(j=ZHONGJIAN[i+1]; j<79; j++)	// 从中间向右找上升沿

以上一次的中间值为这一行的中值向两侧寻找
避免如下情况,找不到中间值

2. 图像截取
图片拟出来的中点向上应该为白色;否则此时不为赛道。

if(h > 1 && ZHONGJIAN[h-1]==0)	// 此时截止

求车身横向偏差

可以通过求曲率,太复杂这里不展示

 uchar QIANZHAN = 15;	// 摄像头前瞻
 uchar YUAN, ZHONG, JIN;	// 中线所在位置
 char ERR = 0;	// 前瞻偏差
 char YERR = 0;	// 车身横向偏差
 
 JIN = ZHONGJIAN[59];
 ZHONG = ZHONGJIAN[59-QIANZHAN];
 YUAN = ZHONGJIAN[59-QIANZHAN*2];
 
 /*  分情况讨论,右负左正 */
 if(YUAN<ZHONGJIAN && ZHONG < JIN)	// 情况1
 
 	ERR = ( (ZHONG - YUAN ) + (JIN - ZHONG) )/2;	// 获取前瞻偏差
 
 else if(YUAN < ZHONG && ZHONG >= JIN)	// 情况2
 
 	ERR = JIN - ZHONG;	// 获取前瞻偏差
 
 else if(YUAN >= ZHONG && ZHONG < JIN)	// 情况3
 
 	ERR = JIN - ZHONG;	// 获取前瞻偏差
 
 else
 
 	ERR = ( (ZHONG - YUAN ) + (JIN - ZHONG) )/2;	// 获取前瞻偏差
 

YERR = JIN - 39;	// 获取车身横向偏差

方向 PD 控制

PID参数随机编撰

float KP = 1.0;	// 方向控制前瞻比例系数
float KD = 1.0;	// 方向控制前瞻微分系数
float YKP = 1.0;	// 方向横向控制比例系数

float GYRO_Z;	// 车身Z轴角速度

#define DUOji_ZHONGZHI 840	// 前轮正方向的舵机占空值

uint DUOJI_PWM;	// 舵机PWM

GET_z = GET_GYRO(Z);	// 获取车身Z轴角速度

DUOJI_PWM = DUOJI_ZHONGZHI + KP*ERR + YKP*YERR - KD*GYRO_Z;	// 舵机参数计算

PWM_OUT(DUOJI_PWM);	// 控制舵机

以上是关于智能车数字图像处理算法入门及C语言实现的主要内容,如果未能解决你的问题,请参考以下文章

智能车竞赛视觉AI组总结 西南科技大学 – 西科二队

智能车竞赛技术报告 | 智能车视觉 - 中南林业科技大学 - 弃车人队

智能车竞赛技术报告 | 智能视觉组 - 北京科技大学智能视觉组

C语言数字图像处理进阶---1 Photoshop图层算法

C语言数字图像处理进阶---1 Photoshop图层算法

汉罗塔与青蛙跳台阶的递归实现(及扩展青蛙跳台阶)C语言从入门到入土(入门篇)(算法篇p2)