第十八届全国大学生智能汽车竞赛——摄像头算法(附带个人经验)

文章目录

  • 前言
  • 一、摄像头图像处理
    • 1、摄像头图像采集
    • 2、图像二值化与大津算法
  • 二、左右边界,中线扫描

前言

参加了第十六,十七和第十八届全国大学生智能车竞赛,对摄像头的学习有部分心得,分享给大家,三届车赛,车赛生涯也算是到了尽头。打算从基础的算法开始,给各位一些个人看法,也是对车赛的一次总结。

一、摄像头图像处理

闲话:其实摄像头的算法有很多种,弄了两年摄像头,也只是学会了其中很小的一部分,但最终,作用都是大同小异的,也不必太过于追求算法上的完美。只需要达到能稳定提取特征,识别元素其实就够用了。(个人用的是普通大津+二值化+八领域做边界提取)

1、摄像头图像采集

打开摄像头相关例程,可以发现其实最终摄像头所采集的数据都存入了一个二维数组中,工作方式也很简单:图像采集,将图像采集标志置一。手动清零,就可以达到重复采集的目的。(没有相关例程的可以去找客服要,记得B站上也有逐飞的摄像头摄像头图像采集视频讲解)

逐飞科技CH32V307摄像头例程

2、图像二值化与大津算法

智能车使用的摄像头所采集的图像一般都是灰度图像,将图像分割、数字化成一个个的数(一个个的像素点),0~255,像素点颜色越白数字越大。我们可以看出图像信息很丰富,图像处理方法自然也就多种多样了,首先我们可以将图像二值化

二值化就是将图像上的灰度点分别设置为0,255(0xFF)(有点像二级分化)。图像直观上就会变为黑白图像。我们该按照何种规则分黑和白呢?这时候就需要我们找出黑、白的分界值(也就是阈值)(大于阈值即为白,反之为黑),然后可以遍历图像数组中每一个像素点,大于阈值设为0XFF(白),反之设为0(黑)。(二值化有一个进阶的思想:图像每一个点都需要二值化嘛,我们能不能只将要使用的点二值化呢,这样速度是不是就快了,这个其实开始没有必要弄,有一张完整的二值化图也方便我们理解)

:1,数组均从零开始。
2,二值化不能作用于摄像头采集原图上,应该重新定义一个同大小的数组,专门存放二值化后的图像信息。(防止在进行图像处理时,摄像头重新采集数据,覆盖之前数据)

/*
mt9v03x_image_dvp : 原图像   		 存放摄像头灰度原图
mt9v03x_image_baz :二值化图像        用于存放图像右边界 
WHTIE  宏定义  替换作用 与0xff相同
*/
#define WHTIE 0xff //255
#define BLACK 0x00
 //使用宏 通过单词代替抽象的数字 
    for(uint8_t i=0;i<MT9V03X_DVP_H;i++)             //MT9V03X_DVP_H:图像高
    {
        for(uint8_t j=0;j<MT9V03X_DVP_W;j++)         //MT9V03X_DVP_W:图像宽
        {
            if(mt9v03x_image_dvp[i][j]>=threshold )  //threshold:图像阈值
            {
               mt9v03x_image_baz[i][j]=WHITE;
            }
            else
            {
               mt9v03x_image_baz[i][j]=BLACK;


            }
        }
    }

后面就是确定图像的阈值了,因为真实环境亮度是变化的,单纯的给定阈值二值化就显得不够稳定,在图像的基础上动态的计算阈值适应性更强。我选择的是大津算法,也是常用且基础的一种了,缺点就是运算时间有点稍长。

大津算法的相关我就不说了,网上有很多相关介绍。(其实我理解的也不太透彻, 手动狗头保命)

二、左右边界,中线扫描

在二值化之后,我们得到了一个由黑和白组成的二维数组,而我们的目的是让小车时刻处于赛道中间位置,也就是图像中间位置。我们想要小车不出赛道,如果能让赛道的中线始终贴合图像数组的中间(此处图像数组的中间我们可以想象为图像的宽/2),那我们的小车是不是就不会出赛道了。图像数组的中间就像PID中的理论值,实际赛道的中线就像实际值。这样我们是不是就可以将图像与PID联系起来。
说回边界扫描,想直接找赛道中线还是比较难的,主要是没有明显特征,我们不妨先寻找左右边界(左右边界黑白相夹),左右相加除二求得中线。这样就得到比较真实的中线坐标,再对比理想中线坐标(图像中间,也就是图像宽/2),从而求出中线偏差,用于PID控制。思路大抵都是这样,但找的方法就很多种多样了。

基础的方法就是从中间往两边找,缺点是遍历了整幅图像,消耗时间稍长,而进阶的就有对普通两边找线方法的优化,(如:双最长白列法)。再进一步稍微复杂一点的有八邻域,迷宫法等等。

我们先来看看普通的两边找线法:
在这里插入图片描述

基本思路就是从最下行往上 (利于对之后对中线的处理),每一行从中间往两边,分别寻找左右边界(特征:黑白跳变),存入左右边界数组。
同时存下中线坐标,用于下一行中线的扫描。(这样减小运算量的同时还可以加大中线扫描时的连续性)左右边界相加除2求出该行中线坐标,存入中线数组。
注:

/* 
        last_mid:                   边界扫描起始坐标 每行边界从此开始 起始行为图像宽/2 后为前一行图像中线坐标
        MT9V03X_DVP_W:              图像宽
        MT9V03X_DVP_H:              图像高
        mt9v03x_image_baz[][]:      二值化图像数组
        left_flag[] :               左边界存在数组 左边界存在 标志置1
        left_flag[] :               右边界存在数组 右边界存在 标志置1
        left_border[]:              左边界数组 存放左边界坐标
        right_border[]:             右边界数组 存放右边界坐标
        Mid_border[]:               中线左边数组 存放中线坐标
*/

last_mid = MT9V03X_DVP_W / 2;    
for (int i = MT9V03X_DVP_H - 1; i >= 0; i--)//从下往上扫描
{
    left_flag[i] = 1;
    right_flag[i] = 1;


    for (int j = last_mid; j > 1; j--)//中间往左边扫描
    {

        if (mt9v03x_image_baz[i][j] == 0xff && mt9v03x_image_baz[i][j-1] == 0x00 &&  mt9v03x_image_baz[i][j-2]==0x00)//黑黑白认为找到左边界
        {

            left_border[i] = j;                       //将左边界存入左边界数组
            left_flag[i] = 1;                         //左边界找到,标志置0
            break; 				//跳出循环
        }

    }
    if (left_flag[i]==0) left_border[i]=0;              //补线标志未置一,此行左丢线,取图像左边界

    for (int j = last_mid; j < MT9V03X_DVP_W-2; j++)  //往右扫描
    {
    
        if (mt9v03x_image_baz[i][j]==0xff && mt9v03x_image_baz[i][j+1]==0x00 && mt9v03x_image_baz[i][j+2]==0x00)//白黑黑认为找到右边界
        {

            right_border[i] = j;                        //将右边界存入右边界数组
            right_flag[i] = 1;                         //右边界找到,标志置0
            break; 				//跳出循环
        }
    }
    if (right_flag[i]==0) right_border[i] = MT9V03X_DVP_W-1;           //补线标志未置一,此行右丢线,取图像右边界

    Mid_border[i] = (left_border[i] + right_border[i]) / 2;		//中线坐标
    mt9v03x_image_baz[i][left_border[i]-2] = BLACK; 	//左边界涂黑
    mt9v03x_image_baz[i][Mid_border[i]] = BLACK; 	//中线涂黑
    mt9v03x_image_baz[i][right_border[i]+2] = BLACK; 	//右边界涂黑       
   /* 注意  左右边界-2 +2 很容易存在数组越界 导致程序卡住 如  左边界点  left_border[i]=0;   [right_border[i]=MT9V03X_DVP_W-1
   自己使用时可以加个限制如
   mt9v03x_image_baz[i][(left_border[i]<2?2:left_border[i])-2] = BLACK; 	//左边界涂黑
   */
    last_mid = Mid_border[i];		//中线查找开始点,方便中线寻找
}

可以在图像上把边界显示出来,方便后面观察图像,像这样:
边界显示
后续给各位说说我对八领域的理解,欢迎大家关注!!!




本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/467470.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法第三十天-矩阵中移动的最大次数

矩阵中移动的最大次数 题目要求 解题思路 网格图 DFS 从第一列的任一单元格 ( i , 0 ) (i,0) (i,0) 开始递归。枚举往右上/右/右下三个方向走&#xff0c;如果走一步后&#xff0c;没有出界&#xff0c;且格子值大于 g r i d [ i ] [ j ] grid[i][j] grid[i][j]&#xff0c;则…

堆叠与集群

8.1堆叠与集群概述 随着企业的发展&#xff0c;企业网络的规模越来越大&#xff0c;这对企业网络提出了更高的要求&#xff1a;更高的可靠性、更低的故障恢复时间、设备更加易于管理等。传统的园区网高可靠性技术出现故障时切换时间很难做到毫秒级别、实现可靠性的方案通常为一…

YOLOv8改进算法之添加CA注意力机制

1. CA注意力机制 CA&#xff08;Coordinate Attention&#xff09;注意力机制是一种用于加强深度学习模型对输入数据的空间结构理解的注意力机制。CA 注意力机制的核心思想是引入坐标信息&#xff0c;以便模型可以更好地理解不同位置之间的关系。如下图&#xff1a; 1. 输入特…

敏捷开发——elementUI/Vue使用/服务器部署

1. 创建vue项目 2. 安装element-ui组件库 npm i -S element-ui或 npm install element-ui3. 在main.js中导入element-ui组件 import ElementUI from element-ui import element-ui/lib/theme-chalk/index.css Vue.use(ElementUI)4. 运行 npm run serve后可以使用 ctrc终止进…

一个 Java8 的坑坑了我 2 小时试错...

背景 趁着失业的间隙想要重温一下Flink相关的学习&#xff0c;当前一切就绪之后&#xff0c;想要用我的 mac运行一个 flink版 helloworld 来验证整体环境是否 OK的时候出现了如下问题&#xff0c;这个问题我未曾遇到过&#xff0c;如下&#xff1a; Failed to write core dump…

【iOS】Blocks

文章目录 前言一、什么是Blocks二、Blocks模式1.Block语法2.Block类型变量3.截获自动变量值4.__block说明符5.截获的自动变量 三、Blocks的实现1.Block的实质__main_block_impl_0Block对象的实现结构体初始化 2.截获自动变量值3.__block说明符4.Block存储域5.__block变量存储域…

LM studio使用gemmar聊天小试

通过LM studio可以方便的使用各种模型&#xff0c;使用LM提供的chat界面或者是使用python代码。 试试代码 在windows下使用python简单一试&#xff0c;例子直接复制LM界面上的代码&#xff1a; 用pip安装 openai包在LM界面 Start Server 需要安装 openai包。 本地电脑是I7…

ArcGIS巧思制作3D景观地图

John Nelson 又制作了一个制图教程视频,我原以为只是一个简单的局部场景DEM夸张实现的3D地图。 不过细看以后…… 还就是比较简单的3D场景地图,操作不难,但是 John Nelson 就是天才。 为什么? 他使用 ArcGIS Pro,在普通的3D地图中,不仅仅是图层混合制作地形效果,还巧妙的…

GPT实战系列-LangChain的Prompt提示模版构建

GPT实战系列-LangChain的Prompt提示模版构建 LangChain GPT实战系列-LangChain如何构建基通义千问的多工具链 GPT实战系列-构建多参数的自定义LangChain工具 GPT实战系列-通过Basetool构建自定义LangChain工具方法 GPT实战系列-一种构建LangChain自定义Tool工具的简单方法…

LLM 构建Data Multi-Agents 赋能数据分析平台的实践之②:数据治理之一

概述 数据治理不仅是产业数字化转型的基石&#xff0c;更是推动产业向更高层次、更精细化、更智能的方向发展的重要引擎。通过科学有效的数据治理实践&#xff0c;产业能够在数字化进程中实现数据驱动的决策与行动&#xff0c;最终达到转型升级的战略目标。 一、数据治理在产业…

800万像素车载摄像头的一些思考

1. 800万像素摄像头与算力、算法以及数据的关系 随着800万像素摄像头在2021款理想One上首次量产应用&#xff0c;800万像素摄像头的议论热潮 再次兴起。有一个话题大家普遍很关注&#xff0c;那就是800万像素摄像头与算力、算法以及数据之 间的关系&#xff0c; 例如&#xf…

深入理解快速排序

一、快速排序 快速排序是冒泡排序的一种改进算法&#xff0c;相比于冒泡排序效率更优。 算法过程分析&#xff1a; 通过采用分治策略&#xff0c;围绕一个 x 将原始数组划分为两个子数组&#xff0c;使得前一个子数组的元素≤ x ≤ 后一个子数组元素&#xff0c;对两个子数组进…

体验OceanBase OBD V2.5.0 组件内扩容和组件变更

背景 OBD 是OceanBase的命令行部署工具&#xff0c;在 obd V2.5.0 版本之前&#xff0c;其主要功能主要是部署各类组件&#xff0c;例如 oceanbase-ce,obproxy-ce,obagent 等。然而&#xff0c;它并不支持组件的变更操作以及组件内部的扩缩容调整。具体来说&#xff1a; 1、若…

#每天一道面试题# 什么是MySQL的回表查询

MySQL中的索引按照物理存储的方式分为聚集索引和非聚集索引&#xff1b; 聚集索引索引和数据存储在一起&#xff0c;B树的叶子节点就是表数据&#xff0c;如果通过聚集索引查询数据&#xff0c;直接就可以查询出我们想要的数据&#xff1b;非聚集索引B树的叶子节点存储的是主键…

流畅的python--小技巧总结

对于python菜鸟来说&#xff0c;只看基本教程后的结果就是看是看过了&#xff0c;但依然不会用&#xff0c;遇事先百度&#xff1b; 此文整理了一些python区别于js的一些小技巧&#xff08;鄙人前端学py&#xff09;&#xff0c;可以快速高效实现功能&#xff0c;当个笔记&…

【嵌入式学习收徒,高薪offer等你来!!!】

有粉丝问了一个问题&#xff0c;说他今年要毕业了&#xff0c;投了好多简历都石沉大海&#xff0c;感觉好多公司都不招人了&#xff0c;想问一下现在究竟是不是如此&#xff0c;不清楚我当年毕业的时候是怎么样的。 我先不直接回答这个问题&#xff0c;先来看一组数据&#xf…

Day 1.数据结构----单向链表(无头单向链表)

数据结构 如何组织存储数据 程序 数据结构 算法 MVC&#xff1a;软件设计结构 M&#xff1a;数据的管理&#xff08;数据结构&#xff09; V&#xff1a;视图&#xff0c;数据的反映及人机交互 C&#xff1a;逻辑控制 单向链表 有头链表&#xff1a;第一个链表结点中…

山景BP1048 升级狗烧写

1.打开MVAssistant_BP10xx工具&#xff0c;在芯片型号栏中选择B1X系列。 2.模式选择 选 M2.仅升级Flash SH(可选) 3 .Code数据选择SDK编译好的bin文件 4.const数据选择编译好的提示音bin文件。 5.点击升级狗下载。 6. 如下图所示&#xff0c;出现提示为正在给升级狗正在下载程…

Machine Learning ---- Feature Scaling

目录 一、What is feature scaling:&#xff1a; 二、Why do we need to perform feature scaling? 三、How to perform feature scaling: 1、Normalization: 2、Mean normalization: 3、Standardization (data needs to follow a normal distribution): 一、What is featur…

salesforce生产环境如何删除触发器

由于生产环境不能直接删除触发器&#xff0c;所以需要在sandbox中先让触发器inactive再部署到生产环境&#xff0c;就可以让触发器失效了。