智能车数字图像处理算法入门及C语言实现
Posted -素心向暖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了智能车数字图像处理算法入门及C语言实现相关的知识,希望对你有一定的参考价值。
文章目录
图像简单处理附加提升
二值化 - 边缘提取 - 特征识别 - 补线 - 中心巡线 - 偏差曲率计算
图像二值化
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; // 计算当前行中心点
优化
- 大湾
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语言实现的主要内容,如果未能解决你的问题,请参考以下文章
智能车竞赛技术报告 | 智能车视觉 - 中南林业科技大学 - 弃车人队