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

文章目录

  • 图像简单处理附加提升
  • 图像二值化
  • 数据示例
  • 大津阈值法代码实现
  • 图像二值化代码实现
  • 图像处理
  • 找中线代码实现
    • 完整实现
    • 优化
  • 求车身横向偏差
  • 方向 PD 控制

图像简单处理附加提升

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

图像二值化

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<256; 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 H3=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];   // 二维图像临时处理数组2for(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;   // 舵机PWMGET_z = GET_GYRO(Z);   // 获取车身Z轴角速度DUOJI_PWM = DUOJI_ZHONGZHI + KP*ERR + YKP*YERR - KD*GYRO_Z;  // 舵机参数计算PWM_OUT(DUOJI_PWM);    // 控制舵机

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

  1. 第十六届全国大学生智能车| AI视觉组新手入门教程

    ▌00 整体内容 进入正文前,我们通过下方框图整体了解每个章节的内容,先大概了解每个章节做的工作是什么作用,这样有助于理解每个章节的内容.同学们可以参考以下章节内容训练模型,但这只是一个初级参考,相信 ...

  2. 第十五届智能车入门浅谈

    @TOC第十五届智能车入门浅谈 写博客原因 这次第十五届全国智能车大赛已经结束了,对于我而言,确实是我大学中一个不可多得的经历,我希望我的这段经历可以保存下来通过博客的形式,同时可以对于其他人有帮助, ...

  3. 第十七届智能车竞赛英飞凌专题培训 ——四轮摄像头组入门讲解

      四轮摄像头组,作为走过16年仍然最纯粹的竞速组,充满着速度与激情,既有高手选择该组挑战极限,也是新手最喜欢的传统组,还是最能体现智能汽车竞赛魅力和初心的组别,可以说集万千宠爱于一身啦!每届参加人数 ...

  4. 智能车技术与实践_ROS入门

    智能车技术与实践--ROS入门 前言:本次作业旨在通过不同的任务使同学掌握ROS基础,包括工作环境.功能包的创建. 预先要求:ubuntu18.04 + ROS melodic 任务一:创建ROS工作 ...

  5. 智能车入门——‘教程引导’ <新手从零做车>

    前言 本系列文章是针对 第一次接触智能车 /学校没有传承   不知道 如何上手做智能车 的同学 将这个系列看完,应该就能够 做出正常的 一个低速完赛的电磁车, 如果你是想提速,寻找新的方案,那么这个教 ...

  6. 智能车阳光算法(含大津法)

    ** ## 智能车阳光算法 ** 谈不上真正的阳光算法,但是对于一些光干扰的场景和一些有噪点的图像还是可以进行处理. 在之前主流的摄像头主要是ov7725这个摄像头的优点就是硬件二值化,它的处理速度比 ...

  7. 智能车入门——跑车前的零碎知识<新手从零做车>

    17届技术报告 | 杭电四轮电磁一队_卓晴的博客-CSDN博客 建议多看一下一些强校的技术报告 调整舵机中值 装舵机舵盘时,要保证车能够左右打死, 装好舵机后,要调整舵机中值,也就是占空比为何值时车走 ...

  8. [智能车]平衡车/直立车的入门经验(代码讲解)

    做为第十六届智能车的FW,在半年的做车经历中把能踩的坑都踩了个遍.写这篇文章是为了留个纪念,也是为了帮新车友快速入门(可能完全0基础).我自己的经验也不足,所以可能会存在一些漏洞,还请大佬指正. 车模 ...

  9. 第十七届智能车竞赛英飞凌 | 逐飞联合直播-平衡单车组入门讲解

      自平衡.单车.自动驾驶--听起来是不是很像稚晖君的出圈开源项目"我把自行车做成了 自 动 驾 驶 !!".的确,这几个要素放在一起,真有那味道了,虽然车模小了点,更像是电动摩托 ...

最新文章

  1. 【C++标准库】特殊容器
  2. 小学计算机课知识点总结,小学计算机教学总结3篇
  3. 编程学将成为必然趋势,青少年编程,从哪里开始?这里推荐Python
  4. 在wildfly中使用SAML协议连接keycloak
  5. 360更新补丁一直提示正在安装_远程利用POC公布|CVE20200796:微软发布SMBv3协议“蠕虫级”漏洞补丁通告...
  6. 最简单 NDK 样例
  7. 看完这些美食海报,你是不是又有灵感了?
  8. 解决jz2440不能ping同主机问题
  9. Rust 1.34替代Cargo注册表 与crates.io共存
  10. 工业革命 书_工业革命以来最重大的变化
  11. Aug.2019_Memory
  12. 我的大一C++学习笔记
  13. Google Chrome显示粉红色屏幕
  14. Linux下校对服务器时间同网络时间一致
  15. 前端vs图片:0 为什么需要重视图片
  16. 微信支付不成功的几个原因
  17. 改造一台可以计算滤芯使用寿命的智能空气净化器——硬件篇
  18. android最新版下载安装,安卓市场APP2020最新版下载
  19. 【HTML】HTML5网页作业----模仿京东,模仿站点
  20. 2016一周年点滴收获总结——遇见Elixir

热门文章

  1. Linux设备树DTB存储格式
  2. java中字节与位的转换
  3. cifs网络文件系统
  4. 轻松看道C编程 快乐温习基本知识
  5. Chapter 5 Blood Type——19
  6. STM32使用内部参考电压提高ADC采集准确度
  7. Hadoop学习之-Flume
  8. 网络安全专家寻勒索病毒蛛丝马迹 警告更多风险
  9. android smb开源,搭建samba服务---实现跨平台文件共享
  10. mysql gh 划线_MySQL在线DDL gh-ost 使用说明