系列文章目录

硬件开源系列(一)

硬件开源系列(二)

算法开源系列(一)

文章目录

目录

系列文章目录

文章目录

前言

一、灰度边界提取的原理

二、边界提取的策略

中线的提取和偏差的计算



前言

前面写了图像的预处理,包括图像压缩,和大津法,这一章介绍图像边界提取。这里我的算法是基于逐飞开源的灰度图算法写的,但也在上面改进了许多,使得边界的搜取不会出现丢边。


一、灰度边界提取的原理

在我们获取摄像头的数据后,返回回来的是0-255的灰度值。就是时候每一副图都是有许多个值在0-255范围的像素点构成。而比赛时,赛道和赛道背景存在明显的亮暗差异,这也是为什么之前都会采取将图像二值化变成黑白图——便于处理,边界明显。不过今年为了加快处理效率,我选用了直接处理灰度图。

其实处理灰度图最简单的方法就是将灰度图当做黑白图处理,可以直接在搜线的判断条件中设定某个点左边连续两点高于阈值,右边点低于阈值,这个点就是边界点,省去了一个二值化过程。

而我在处理灰度图时,基于逐飞灰度图开源方案加上了大津法计算出来的阈值判断。逐飞开源的方法是隔5个点计算两个点之间的灰度值差,通过差比和将偏差设计到自己想要的范围。当这个差值大于认为设定的阈值后,就认定找到了边界。其实这个方法是会出现丢边的现象,因为仅仅一个条件,在光线不均匀的地方,很容易就会在赛道外满足条件。

针对这个问题,我们采用的办法是选取的两点灰度值必须在一个大于大津法设定的阈值一个小于大津法设定的阈值。我这里用的是压缩后的图(压缩的方法在前一章),所以对于边界的判断条件我这里是每隔两个点比较两点之间的灰度值,但这个偏差大于设定的偏差,且两点灰度值一个大于大津法阈值,一个小于大津法阈值就可以判断边界存在。

附上判断条件的代码,其中difference_sum和mark_middle_num分别为灰度值差比和函数以及阈值范围判断函数。

if(difference_sum(image[EXTRACT_ROW][EXTRACT_COL+COL_SPACE],image[EXTRACT_ROW][EXTRACT_COL])>=g_threshold_value&& mark_middle_num(image[EXTRACT_ROW][EXTRACT_COL],image[EXTRACT_ROW][EXTRACT_COL+COL_SPACE],Threshold)){str->LeftEdge[EXTRACT_ROW]=EXTRACT_COL+COL_SPACE-1;//找到起始行储存L_edge_last=EXTRACT_COL;/*第一次得到线*/if(s_L_get_flag==0){str->L_StartLine=EXTRACT_ROW;}break;}

这里是上面调用两个函数的代码结构。

 //差比和函数int difference_sum(unsigned char a,unsigned char b ){if(a+b==0){return 0;}return (a-b)*300/(a+b);}int mark_middle_num(uint8 num1,uint8 num2,uint8 middle)//阈值比较{if(num1<=num2 && num1<=middle && num2>=middle){return 1;}else if(num2<num1 && num1>middle && num2<middle){return 1;}else{return 0;}}

二、边界提取的策略

对于如何扫描边界其实也需要方法的,很多初学者往往会全部扫描一行,或者从中间向两边扫描,这样其实很浪费时间,也浪费性能。

最简单的方法就是边缘跟踪的扫线,其实网上说的一些八领域之类的也就是跟踪的一类。主体思想就是在上一行边界附近进行扫描,因为我们比赛的赛道总体是连续的,第一行找到了边界之后,就可以顺着这点在下一行对应的这一列周围扫描。而如果不连续了那正好可以拿来做元素的识别判断。

像这里,在我们第一次通过全部扫描最底行找到了A点之后,就可以记住A点的列坐标,在上面C点周围几个点搜索。这样可能只需要扫描很少的几个点就能找到边界了,同时,我们还可以通过C这一点的灰度值,判断搜线方向。比如C这一点是在赛道上是黑的,我们就可以从C点向右搜线,不管左边。如果C点在赛道中间,就往左搜线,不管右边,有节省了一些时间。这是左边线策略,右边线搜线同理。

再调试时,完全可以将边界线打在TFT上,看到自己的边界搜索是否合理。

TFT描点边界线。

中线的提取和偏差的计算

在提取完边界后,就需要计算出中线了。如果左右边界都存在时直接就相加除以二,得到边界。如果只有一个边界时,可以通过赛道宽度来计算边界。一开始我是采用动态的赛道宽度,每次遇到断行后,用断行之后的行数宽度与之前的边界都存在的直道宽度做比值。通过这个比值来选取最近的实际宽度来做补线宽度。后面为了方便直接通过最小二乘法计算得到赛道的宽度一次函数,预先存在程序里。不过这种方法受摄像头角度和高度,也正因如此,我自身很多算法的参数不能直接移植到其他车上。

关于最小二乘法计算宽度的方法是通过10个点的左边界连续点和10个右边界连续点,分别用最小二乘法计算出各自的斜率与常数值。比如左边界函数是y=ax+b,右边界时Y=cx+d,宽度函数就是y=(c-a)x+(d-b)。这要摄像头角度保持合适,这和宽度函数是很准的。

中线的部分代码

  if(str->LeftEdge[ROW_END]!=0 && str->RightEdge[ROW_END]!=0)     //左右都有边界{str->MiddleLine[ROW_END] =(str->LeftEdge[ROW_END] +str->RightEdge[ROW_END])>>1;}else if(str->LeftEdge[ROW_END]!=0 && str->RightEdge[ROW_END]==0)//find left{str->RightEdge[ROW_END]=COL_END;str->MiddleLine[ROW_END]=(str->LeftEdge[ROW_END] + str->RightEdge[ROW_END])>>1;}else if( str->LeftEdge[ROW_END]==0 && str->RightEdge[ROW_END]!=0)//find right{str->LeftEdge[ROW_END]=0;str->MiddleLine[ROW_END]=(str->LeftEdge[ROW_END] + str->RightEdge[ROW_END])>>1;}else if( str->LeftEdge[ROW_END]==0 &&str->RightEdge[ROW_END]==0)//两边丢线   d待处理{str->LeftEdge[ROW_END]=0;str->RightEdge[ROW_END]=COL_END;str->MiddleLine[ROW_END]=(str->LeftEdge[ROW_END] + str->RightEdge[ROW_END])>>1;}

而当中线提取出来之后,就可以计算偏差了,这里我采用的是计算连续几行的偏差做平均,对于不同的赛道元素,选取的偏差行数不同。对于偏差的行数选取,需要根据不同的赛道做判断。这里也是我做的不足之一,对于控制方面,我做的实在太过于简单,只是单纯的选取偏差后进行PID的计算。往往会在弯道出弯处或者知道接弯出现来不及或者超调,尤其当速度上去后,漂移十分常见,而对于控制我能做的就是不停的分段分段再分段。只能做到麦轮稳定在1.8m的沿中线跑,如果速度更快。到2m时,不是压内弯就是压赛道边界。这也是我的败笔吧,缺少好的控制方法,在高速行驶时,车模的控制一点也不稳定。

关于赛道弯道和直道的分段后续再说吧,这一章就到此为止吧。

float Getrouteoffset(unsigned char start,unsigned char end,float midpos)
{unsigned char i=0;//unsigned char iCount=0;float  Black_Sum=0;float weightSum = 0;float TemError = 0.0;if(end<ROW_START){end=ROW_START+2;}if(start<end){return TemError;}else{for(i=start; i>end;i--){Black_Sum += 1.0*(midpos-Boundary.MiddleLine[i]);weightSum += 1;}TemError =Black_Sum*1.0/weightSum;if(TemError > 40){TemError =40;}if(TemError < -40){TemError = -40;}return TemError;}
}

十六届全向组算法开源(二)相关推荐

  1. 十六届全向组硬件开源

    十六届智能车全向组硬件开源 前言:算法开源已经开始 第一章信号的预处理 第二章边界的提取 写在前面: 我是一个做了三年智能车比赛的本科学生,也是挺菜鸡的一个.国奖也只有一个一等一个二等,和一个划水的三 ...

  2. 十六届全向组硬件开源(二)

    前言:算法开源已经开始 第一章信号的预处理 这一章更新下麦轮的驱动方案,使用过CH32的同学都知道,这款单片机的定时器很少,所以推荐的方案中都是采用DRV8701方案来解决一个PWM口控制一路电机,实 ...

  3. 第十六届智能车竞赛开源云台设计

      卓大大想给您投稿一下我们十六届的云台开源文章. §01 云台概况 云台加工方式:3D打印(FDM类型打印机) 3D打印材料:PLA 3D打印填充度:20%-30% 3D打印填充类型:螺旋二十四位面 ...

  4. 十六届智能车全向组算法开源(一)

    系列文章目录 之前也把自己做的全向所有电路都开源了,内容也包含完整的原理图PDF,想了解的可以看看往期博客. 硬件开源第一章 硬件开源第二章 文章目录 目录 系列文章目录 文章目录 前言 一.智能车比 ...

  5. 十六届智能车全向组硬件开源 | 上海海事大学全向行进组

    简 介: 卓大,不知道你能不能看到我的消息.今年是我做车的第三年了,也是最后一年了.三年里经历了许多,走了很多弯路,心里的感慨也不少.这两天在整理资料的时候顺手在CSDN上写了一篇全向组的硬件开源贴, ...

  6. 智能车调试总结——十七届编队组国一、十六届双车组国二(附代码)

    目录 简介 本文以第十六届双车组(直立)软件调试为主,第十七届部分主要讲通讯与控距 一.第十六届双车组: 1.机械结构搭建(以直立为例) 1.1 车模布局 1.2陀螺仪安装 2.软件控制部分 2.1姿 ...

  7. 第十六届全国大学生智能车竞赛-开源-全向行进组-国一控制

    第十六届全国大学生智能车竞赛-全向行进组-国一控制开源 开源代码地址: https://github.com/ittuann/Enterprise_E PID 控制:常规 PID 以及改进式 PID ...

  8. 十六届智能车全向行进组_国一控制开源

      卓大大好,我是来自东北林业大学参加第十六届智能车全向行进组的同学.我们的出身并非老牌强校,但也很幸运的能在最后拿到了国一的成绩.   今年的疫情也对参赛选手也有着不小影响,于是我想把上一届的控制思 ...

  9. 【第十六届全国大学生智能车竞赛回顾——华东赛区单车拉力组(全国二等奖)】

    一.简述 作为第二次参加智能车大赛的"老队员",有了前一届的参赛经验,上手起来确实轻松了不少.因此,在选择组别的时候,我便想挑战一下自己,选择了这个今年新加入的且难度较大的单车拉力 ...

最新文章

  1. 元素算法Bloom Filter
  2. 微软.net一些类的源码
  3. yii2.0使用ActionForm创建表单
  4. A Fully Featured Windows HTTP Wrapper in C++
  5. 2009年9月三级网络技术考前预测_填空题部分
  6. 关于使用QQ、新浪微博、腾讯微博等第三方登录网站的开发过程(一)
  7. JS和安卓 IOS的交互 例子式记录
  8. python回声程序 一行代码_python实现的比较完成的带声音的摩斯码翻译程序的代码...
  9. 关于 mahout factorize-movielens-1M.sh 执行
  10. 今日恐慌与贪婪指数为73 贪婪程度有所上升
  11. 再见 Python!Yann LeCun 警告:深度学习需要新编程语言
  12. bzoj 1799: [Ahoi2009]self 同类分布(数位DP)
  13. SQL教程(从入门到精通)
  14. 基于主从博弈的电热综合能源系统动态定价与能量管理 主要做的是电热综合能源系统的动态定价问题,采用是主从博弈方法
  15. Mysql读写分离的原理及配置--amoeba
  16. Human Muscles/Musculature (人体肌肉组织)
  17. oracle大表新增字段并赋值,oracle批量新增字段 数据赋值应用
  18. 计算机网络应用班级口号霸气押韵,跑操口号大全(精选50句)
  19. gitlab配置发送邮件
  20. 有哪些小而美的中小厂?

热门文章

  1. 【特征提取】Hog特征原理简介与代码实践
  2. php网站访问报错Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to
  3. php waf 搭建,开源WAF搭建
  4. python中进程间通信方式总结
  5. mysql 当前日期后七天
  6. Matplotlib绘图的简单使用(2)
  7. RS485主从式多机通讯协议
  8. 用户没有sudo权限解决方法
  9. Windows 关机或重启出现正在准备Windows,请不要关机
  10. 支持PHP运行环境和系统防火墙配置管理,1Panel开源面板v1.1.0发布