开源汇总写在下面
第18届天下大门生智能汽车比赛四轮车开源讲授_Joshua.X的博客-CSDN博客
开源链接写在下面
https://gitee.com/joshua_xu/the-18th-smartcarhttps://gitee.com/joshua_xu/the-18th-smartcar
注:文章中全部参数,角点范围之类的东西仅作为参考,实际参数,请根据必要实际调解!!!!!!!!!
实际上,智能车全部参数都必要根据你的实际情况举行调解,万万不可照搬不误!!!!!
一、元素辨认
智能车泯灭时间最多的就是元素辨认这一环节,颠末我们前几章摄像头改正,边线提取,中线盘算,速率/方向控制。这几个环节都做好的话,车子是可以在简朴的赛道中心举行根本的寻迹。沿着直道,弯道走。
但是想要完成比赛要求,必要对元素举行处置惩罚,包罗但不限于:弯道,直道,十字,环岛,坡道,横断,断路,车库,三叉,T字等。
我们从本章开始举行图像元素辨认,元素辨认告急是依赖特性点的分列组合,以及防止误判。
而且元素辨认最告急的是思绪,我会详细讲授我的图像辨认的思绪,讲授特性点的提取。代码并不告急,我在下面提供的代码各位仅供参考。
还是那句话:差异算法之间没有优劣之分,多少国赛选手仍跑着最简朴的算法,这并不影响什么。
注:以下方案有大概会用到一个大概多个下述变量,以下变量均在开源【3】边线提取一章有讲。
- const uint8 Standard_Road_Wide[MT9V03X_H];//标准赛宽数组
- volatile int Left_Line[MT9V03X_H]; //左边线数组
- volatile int Right_Line[MT9V03X_H];//右边线数组
- volatile int Mid_Line[MT9V03X_H]; //中线数组
- volatile int Road_Wide[MT9V03X_H]; //实际赛宽数组
- volatile int White_Column[MT9V03X_W];//每列白列长度
- volatile int Search_Stop_Line; //搜索截止行,只记录长度,想要坐标需要用视野高度减去该值
- volatile int Boundry_Start_Left; //左右边界起始点
- volatile int Boundry_Start_Right; //第一个非丢线点,常规边界起始点
- volatile int Left_Lost_Time; //边界丢线数
- volatile int Right_Lost_Time;
- volatile int Both_Lost_Time;//两边同时丢线数
- int Longest_White_Column_Left[2]; //最长白列,[0]是最长白列的长度,也就是Search_Stop_Line搜索截止行,[1】是第某列
- int Longest_White_Column_Right[2];//最长白列,[0]是最长白列的长度,也就是Search_Stop_Line搜索截止行,[1】是第某列
- int Left_Lost_Flag[MT9V03X_H] ; //左丢线数组,丢线置1,没丢线置0
- int Right_Lost_Flag[MT9V03X_H]; //右丢线数组,丢线置1,没丢线置0
复制代码 二、直道
先看几张标准直道图像。
直道 直道 直道 这几张图像都是在跑车时间实际的图片,各位可以看一看,长直道有什么特点。
我在判断的时间用了以下几个特性点:
- 前瞻很远,也就是Search_Stop_Line计数很大
- 界限起始点很靠下
- 赛道没有丢线,大概丢线很少
- 摄像头获取到的偏差很小
代码如下
- /*-------------------------------------------------------------------------------------------------------------------
- @brief 直道检测
- @param null
- @return null
- Sample Straight_Detect();
- @note 利用最长白列,边界起始点,中线起始点,
- -------------------------------------------------------------------------------------------------------------------*/
- void Straight_Detect(void)
- {
- Straight_Flag=0;
- if(Search_Stop_Line>=65)//截止行很远
- {
- if(Boundry_Start_Left>=68&&Boundry_Start_Right>=65)//起始点靠下
- {
- if(-5<=Err&&Err<=5)//误差很小
- {
- Straight_Flag=1;//认为是直道
- }
- }
- }
- }
复制代码 我的直道判断写的实在不好,下面是我在比赛后看了一些技能陈诉,包罗本身的一些想法
由于直道的情况下中线近乎是一条直线,以是中线数组的方差肯定不会太大。
视野远处到近处的斜率可以作为火线门路是否“直”的一个判断标准。
三、弯道
缓弯 急弯 弯道我没有举行处置惩罚,直接用的摄像头偏差丢给pid举行盘算的,但是想要跑的好,实在可以区分巨细弯,这里可以提供一些发起。
- 视野长度
- 最长白列偏左还是偏右
- 左/右边丢线数
- 界限起始点位置
- 中线位置
- 曲率盘算
这些都可以组合起来,分辨出差异的弯,然后对应差异的参数,得到比力好的控制结果。
s弯也黑白常磨练控制技能的一环。他不专门作为元素,但是比赛中大概会出现。处置惩罚的好可以做到如履平地,直线飞过。
小s弯 s弯 实物图和图像图放在上面,各人可自行分析出特点,举行对应处置惩罚。
四、十字
提及十字,各人是不是想到如许的一张图
标准十字 正入十字环 这是一张标准的十字,正常处置惩罚可以很简朴。
中心地域丢线多,找到四个拐点,连线即可即可。
但是,你常常看到的是如许的十字:
超远十字 十字中途 近处变形十字 斜入十字 斜出十字 这种斜入,斜出,弯道入,十字中途,都是十字。
处置惩罚元素就要处置惩罚各种情况下的元素,否则没有实际意义。
起首要观察这几张十字都有什么特性。
- 存在双边丢线,且双边丢线根本位于视野中心。
- 存在最少2个角点大概更多。
- 最长白列较长。
当发现以上情况可以启动十字判断流程。
1.正入十字
注:以下文章中:角点==拐点,两者是一个东西,没有区别。
我们关注一下正入十字时的边线情况。
标准十字边线情况 我们以左下角点为例,将图像放大来看。
左下角点放大情况 画圆处是抱负的角点,我们可以找一找他有什么规律。
- 角点向下几个边线横坐标差距不大。
- 角点向上几个边线横坐标差距较大,越向上横差距越大。
- 角点向上大概会有丢线。
当同时满足这些条件的时间,我以为我找到了一个角点。
我将这种判断办法我称为界限扯破法。
右下角点情况 右上角点情况 左上角点情况 其他几个点的情况也差不多,都是在上角点上侧边线差距不大,下面边线差距很大,尚有大概出现丢线,下角点同理。(角点只必要找到他所在的行数即可,找到所在行数,再去访问改行的左/右边线数组,就可以得到角点的坐标。举例:我找到左角点为i行,那么我访问Left_Line,这个值即为他的列数,也就确定了这个角点的位置)
左下角点判断函数参考如下:
- /*-------------------------------------------------------------------------------------------------------------------
- @brief 左下角点检测
- @param 起始行,终止行
- @return 返回角点所在的行数,找不到返回0
- Sample left_down_guai[0]=Find_Left_Down_Point(MT9V03X_H-1,20);
- @note 角点检测阈值可根据实际值更改
- -------------------------------------------------------------------------------------------------------------------*/
- int Find_Left_Down_Point(int start,int end)//找左下角点,返回值是角点所在的行数
- {
- int i,t;
- int left_down_line=0;
- if(Left_Lost_Time>=0.9*MT9V03X_H)//大部分都丢线,没有拐点判断的意义
- return left_down_line;
- if(start<end)//--访问,要保证start>end
- {
- t=start;
- start=end;
- end=t;
- }
- if(start>=MT9V03X_H-1-5)//下面5行上面5行数据不稳定,不能作为边界点来判断,舍弃
- start=MT9V03X_H-1-5;//另一方面,当判断第i行时,会访问到i+3和i-4行,防止越界
- if(end<=MT9V03X_H-Search_Stop_Line)
- end=MT9V03X_H-Search_Stop_Line;
- if(end<=5)
- end=5;
- for(i=start;i>=end;i--)
- {
- if(left_down_line==0&&//只找第一个符合条件的点
- abs(Left_Line[i]-Left_Line[i+1])<=5&&//角点的阈值可以更改
- abs(Left_Line[i+1]-Left_Line[i+2])<=5&&
- abs(Left_Line[i+2]-Left_Line[i+3])<=5&&
- (Left_Line[i]-Left_Line[i-2])>=5&&
- (Left_Line[i]-Left_Line[i-3])>=10&&
- (Left_Line[i]-Left_Line[i-4])>=10)
- {
- left_down_line=i;//获取行数即可
- break;
- }
- }
- return left_down_line;
- }
复制代码 注:
有许多同砚表现找不到角点,问我什么情况。
实在我没见过你的车,也不知道你的代码怎么写的,也不知道你的图像什么样,我怎么知道为什么找不到角点呢?这里给各人写一下排查思绪吧。
- 角点判断与赛道边线有直接关系,发起先想办法看一下边线数据是否正常。
- 我利用的是边线作差,有大概是你的图像和我不一样,角点处边线的差不是那么大,导致不绝不满足扯破条件,没有辨认角点。
- 大概丢线之类的条件根本没满足,都没进入到这里的函数,去查察一下丢线标志位之类的函数。
相类似的角点判断这里不在重复论述,焦点原理是找到界限扯破,记载界限扯破起始处的行数。
当找到四个角点时,对应连线即可。
 左右对应点连上即可 这里提供一下左边线连线函数,右边线同理,不再赘述。
- /*-------------------------------------------------------------------------------------------------------------------
- @brief 左补线
- @param 补线的起点,终点
- @return null
- Sample Left_Add_Line(int x1,int y1,int x2,int y2);
- @note 补的直接是边界,点最好是可信度高的,不要乱补
- -------------------------------------------------------------------------------------------------------------------*/
- void Left_Add_Line(int x1,int y1,int x2,int y2)//左补线,补的是边界
- {
- int i,max,a1,a2;
- int hx;
- if(x1>=MT9V03X_W-1)//起始点位置校正,排除数组越界的可能
- x1=MT9V03X_W-1;
- else if(x1<=0)
- x1=0;
- if(y1>=MT9V03X_H-1)
- y1=MT9V03X_H-1;
- else if(y1<=0)
- y1=0;
- if(x2>=MT9V03X_W-1)
- x2=MT9V03X_W-1;
- else if(x2<=0)
- x2=0;
- if(y2>=MT9V03X_H-1)
- y2=MT9V03X_H-1;
- else if(y2<=0)
- y2=0;
- a1=y1;
- a2=y2;
- //这里有bug,下方循环++循环,只进行y的互换,但是没有进行x的互换
- //建议进行判断,根据a1和a2的大小关系,决定++或者--访问
- //这里修改各位自行操作
- if(a1>a2)//坐标互换,这里建议修改,x坐标,y坐标一起交换,单纯换y坐标可能会导致bug
- {
- max=a1;
- a1=a2;
- a2=max;
- }
- for(i=a1;i<=a2;i++)//根据斜率补线即可
- {
- hx=(i-y1)*(x2-x1)/(y2-y1)+x1;
- if(hx>=MT9V03X_W)
- hx=MT9V03X_W;
- else if(hx<=0)
- hx=0;
- Left_Line[i]=hx;
- }
- }
复制代码 焦点也就是两点确定一条直线。根据数学中的直线函数的两点式,填入对应数据,补线就行。
固然,这是最抱负的情况。
2.斜入十字
但凡车入十字时歪了,大概是急弯接着十字下面的两个拐点就看不见了。
各人看一看上面我枚举的几张斜入十字的图,但凡十字出现,下面的角点会有大概看不见,但是上面肯定存在两个角点。
以是我将十字判断的焦点放到了上面两个角点上。
只要上面两个拐点同时出现,且坐标位置公道,我就以为当前元素是十字,下面两个角点存在与否不告急,下面有点,那就连上,没有点就用其他办法。
整套十字处置惩罚代码如下。
全套函数中用到了
void Find_Up_Point(int start,int end); //搜刮上角点,左上+右上
void Find_Down_Point(int start,int end);//搜刮下角点,左下+右下
函数内容如下:
- void Cross_Detect()
- {
- int down_search_start=0;//下角点搜索开始行
- Cross_Flag=0;
- if(Island_State==0&&Ramp_Flag==0)//与环岛互斥开
- {
- Left_Up_Find=0;
- Right_Up_Find=0;
- if(Both_Lost_Time>=10)//十字必定有双边丢线,在有双边丢线的情况下再开始找角点
- {
- Find_Up_Point( MT9V03X_H-1, 0 );
- if(Left_Up_Find==0&&Right_Up_Find==0)//只要没有同时找到两个上点,直接结束
- {
- return;
- }
- }
- if(Left_Up_Find!=0&&Right_Up_Find!=0)//找到两个上点,就认为找到十字了
- {
- Cross_Flag=1;//确定对应标志位,便于各元素互斥掉
- down_search_start=Left_Up_Find>Right_Up_Find?Left_Up_Find:Right_Up_Find;//用两个上拐点坐标靠下者作为下点的搜索上限
- Find_Down_Point(MT9V03X_H-5,down_search_start+2);//在上拐点下2行作为下角点的截止行
- if(Left_Down_Find<=Left_Up_Find)
- {
- Left_Down_Find=0;//下点不可能比上点还靠上
- }
- if(Right_Down_Find<=Right_Up_Find)
- {
- Right_Down_Find=0;//下点不可能比上点还靠上
- }
- if(Left_Down_Find!=0&&Right_Down_Find!=0)
- {//四个点都在,无脑连线,这种情况显然很少
- Left_Add_Line (Left_Line [Left_Up_Find ],Left_Up_Find ,Left_Line [Left_Down_Find ] ,Left_Down_Find);
- Right_Add_Line(Right_Line[Right_Up_Find],Right_Up_Find,Right_Line[Right_Down_Find],Right_Down_Find);
- }
- else if(Left_Down_Find==0&&Right_Down_Find!=0)//11//这里使用的是斜率补线
- {//三个点 //01
- Lengthen_Left_Boundry(Left_Up_Find-1,MT9V03X_H-1);
- Right_Add_Line(Right_Line[Right_Up_Find],Right_Up_Find,Right_Line[Right_Down_Find],Right_Down_Find);
- }
- else if(Left_Down_Find!=0&&Right_Down_Find==0)//11
- {//三个点 //10
- Left_Add_Line (Left_Line [Left_Up_Find ],Left_Up_Find ,Left_Line [Left_Down_Find ] ,Left_Down_Find);
- Lengthen_Right_Boundry(Right_Up_Find-1,MT9V03X_H-1);
- }
- else if(Left_Down_Find==0&&Right_Down_Find==0)//11
- {//就俩上点 //00
- Lengthen_Left_Boundry (Left_Up_Find-1,MT9V03X_H-1);
- Lengthen_Right_Boundry(Right_Up_Find-1,MT9V03X_H-1);
- }
- }
- else
- {
- Cross_Flag=0;
- }
- }
- //角点相关变量,debug使用
- //ips200_showuint8(0,12,Cross_Flag);
- // ips200_showuint8(0,13,Island_State);
- // ips200_showuint8(50,12,Left_Up_Find);
- // ips200_showuint8(100,12,Right_Up_Find);
- // ips200_showuint8(50,13,Left_Down_Find);
- // ips200_showuint8(100,13,Right_Down_Find);
- }
复制代码 判断流程如下
- 当前状态不是环岛,不是坡道,由于必要做到元素互斥,一次只有大概是一个元素。
- 图像中累计双边丢线数目大于10,开始找上拐点。
- 上拐点找到了,以上拐点纵坐标靠下者作为下拐点搜刮的上限。
- 搜刮下拐点。
- 下拐点位置公道性判断,下拐点不大概比上拐点还靠上。
- 如果四个点都存在,直接连线;三个点存在,根据条件利用斜率补线和直接连线。
- 只有两个上点存在,举行斜率补线。
十字判断流程图 如许处置惩罚十字有一个长处,不消举行十字的状态机处置惩罚。
传统十字必要区分如下状态:
- 车即将入十字,存在四个角点;
- 车已经进入十字,只有两个上角点,
- 车即将出十字,上角点靠下;
- 车出十字,角点消散。
我实测四个角点同时出现的情况太少了,险些看不到,以是没有利用传统方法。
用我们如今这种方法可以省去状态机,有几个角点就按照对应着连线,不再区分十字状态。
3.补线
我的十字补线函数有两种:
- Lengthen_Left_Boundry (Left_Up_Find-1,MT9V03X_H-1);
- Lengthen_Right_Boundry(Right_Up_Find-1,MT9V03X_H-1);
- Left_Add_Line (Left_Line [Left_Up_Find ],Left_Up_Find ,Left_Line [Left_Down_Find ] ,Left_Down_Find);
- Right_Add_Line(Right_Line[Right_Up_Find],Right_Up_Find,Right_Line[Right_Down_Find],Right_Down_Find);
复制代码 一个是Add_Line,一个是Lengthen_Left,两者有很大区别。
Add_Line的用途:两点确定一条直线。
Lengthen_Left用途:只有一个点,在这个点向上找点确定斜率,画出一根线。由于十字角点向上肯定是短直道,那么我就沿着直道向下做一个斜率补线。
Lengthen_Left详情如下。
- 函数有两个参数,一个是补线起始行,一个是停止补线行。
- 角点处开始,向上移动三行,趁便访问该行的边线的横坐标。
- 如许我们就得到了两个点(补线起始行,补线起始行上面第3行,确定了行数再去找一下对应行数的界限的横坐标,就有了两个点的坐标),就可以算出这一条短线的斜率。
- 有一个点(起始点),有斜率(起始点,起始点向上数3行的点,这两点之间的斜率),就可以向下补线,补到停止行即可。
 斜率补线表示图 如许补的线和下面的角点就没有关系,无论有没有下角点,都可以补出一条界限限。
代码如下
- /*-------------------------------------------------------------------------------------------------------------------
- @brief 右左边界延长
- @param 延长起始行数,延长到某行
- @return null
- Sample Lengthen_Right_Boundry(int start,int end);
- @note 从起始点向上找3个点,算出斜率,向下延长,直至结束点
- -------------------------------------------------------------------------------------------------------------------*/
- void Lengthen_Right_Boundry(int start,int end)
- {
- int i,t;
- float k=0;
- if(start>=MT9V03X_H-1)//起始点位置校正,排除数组越界的可能
- start=MT9V03X_H-1;
- else if(start<=0)
- start=0;
- if(end>=MT9V03X_H-1)
- end=MT9V03X_H-1;
- else if(end<=0)
- end=0;
- if(start<=5 && start <= end)//因为需要在开始点向上找3个点,对于起始点过于靠上,不能做延长,只能直接连线
- {
- Right_Add_Line(Right_Line[start],start,Right_Line[end],end);
- }
- else
- {
- k=(float)(Right_Line[start]-Right_Line[start-4])/5.0;//这里的k是1/斜率
- if(start<=end)
- {
- for(i=start;i<=end;i++)
- {
- Right_Line[i]=(int)(i-start)*k+Right_Line[start];//(x=(y-y1)*k+x1),点斜式变形
- if(Right_Line[i]>=MT9V03X_W-1)
- {
- Right_Line[i]=MT9V03X_W-1;
- }
- else if(Right_Line[i]<=0)
- {
- Right_Line[i]=0;
- }
- }
- }
- else
- {
- for(i=end;i<=start;i++)
- {
- Right_Line[i]=(int)(i-start)*k+Right_Line[start];//(x=(y-y1)*k+x1),点斜式变形
- if(Right_Line[i]>=MT9V03X_W-1)
- {
- Right_Line[i]=MT9V03X_W-1;
- }
- else if(Right_Line[i]<=0)
- {
- Right_Line[i]=0;
- }
- }
- }
-
- }
- }
复制代码 但斜率补线也有bug,当图像的界限扯破不是那么显着的时间,会找错角点,然后根据斜率补出一条有题目的线。
 角点处扯破不显着,斜率补线出现bug  十字出现bug 上面一张图出现2个bug。
- 左上角点附近扯破不显着,角点附近过斜率缓,导致角点向上的边线斜率与正常直道斜率不划一,补线出现非常。
- 右下角角点没判,是由于角向上几行扯破程度小于阈值,就不以为他是角点。就没有利用上下角点之间直接拉线,用的斜率补线。
以是必要我们将十字附近黑胶贴的稳固,笔挺,牢固,防止反光之类的情况发生。
别的角点的阈值也必要根据实际情况举行修改,做到稳固不误判。
下面是我利用上面的十字判断方法实际跑出来的小s接十字环,结果很好。
小s入十字环 五、关于屏幕表现边线,以及利用的发起
近来许多多少人问我为什么在屏幕上表现界限,补线等信息后屏幕会一闪一闪的,这里我提出一些本身的想法和发起。
起首,屏幕闪灼,很大概是屏幕在表现过程中表现差异东西,差异函数表现地域有重叠。表现一样平常放在while中(屏幕表现函数不发起放在停止),造成同一个地域两个函数左右互搏,造成闪灼。
尚有大概是先表现图像,再表现补线之类,如许实在就是左右互搏。图像表现地域肯定和补线地域重合。以是我发起先补线,末了再表现图像。
其次,纵然已经非常公道的分别好了表现地域,函数调用机会差异,也有大概出现这种情况。比如在while最开始二值化后调用了图像表现。车模在十字时间,各人想看一下补线情况,就在十字判断处表现补线情况,在函数某处还调用了各自标志位表现函数,在while竣事调用了边线表现函数。如许在不消时间对屏幕差异地域举行表现也有大概会对表现造成影响。只管克制。
这里给各人说下我保举的做法。(固然在debug的时间肯定各种表现函数漫天放,这是没有办法的变乱。但是在debug完毕后,各人肯定记得将干系调试时的用于辅助的表现函数关闭)
一些发起如下:
- 全部表现函数放在一起。是指调用表现函数时间一起调用,第一行表现a,第二行表现b,只要把这一批函数解释掉,屏幕就空了。否则你有大概很希奇,屏幕上的是什么玩意,显着已经把表现关掉了,实在是你在工程某个角落还调用了某个元素标志位表现。
- 全部图像表现放在while的末了。如果是先辈行图像表现,后又举行了补线,那么图像表现的仍然是原来没补线的内容。由于你表现函数运行的时间还没补线呢。
- 我边线表现是在全部边线,元素处置惩罚完毕后直接修改二值化数组,不是在屏幕上利用点表现。(我也利用过点表现,在图线边线处利用红点将左边线表现出来,绿点中线,蓝点右线,如许有概率会屏幕闪灼)
以下是我的边线表现函数,他实在是一个半成品,只是在《二值化数组》界限点处将相应的点涂黑,边线+1大概-1是为了让边线不贴合优劣接壤处,让肉眼更清晰的看到边线。
他并不具备表现功能,想要表现必要调用图像表现函数,也因此我只必要表现一次图像就好,不存在图像表现重叠的题目,而且利用图传也可以瞥见边线(补线实在也是修改的边线数据,全部不受补线影响)。
- /*-------------------------------------------------------------------------------------------------------------------
- @brief 边界显示,用于图传,显示到屏幕上,
- @param null
- @return null
- Sample 直接调用
- @note 显示左中右边界,中线,
- 正常情况下不要用,因为直接在原图上写入了边界信息
- 会对元素判断造成干扰的,调试时候调用,
- 使用时请保证所有边线数据,元素处理都完成
- 此函数后请调用图线显示函数
- -------------------------------------------------------------------------------------------------------------------*/
- void Show_Boundry(void)
- {
- int16 i;
- for(i=MT9V03X_H-1;i>=MT9V03X_H-Search_Stop_Line;i--)//从最底下往上扫描
- {
- image_two_value[i][Left_Line[i]+1]=IMG_BLACK;
- image_two_value[i][(Left_Line[i]+Right_Line[i])>>1]=IMG_BLACK;
- image_two_value[i][Right_Line[i]-1]=IMG_BLACK;
- }
- }
复制代码 这是main函中while(1)的函数调用序次:
- while(1)//实测一圈while基本10ms左右,理论上在15毫秒左右,都在可接受范围之内
- {
- if(mt9v03x_finish_flag)//图像获取
- {
- if(Img_Disappear_Flag==0)//图没有丢,正常计算阈值
- {
- Threshold=My_Adapt_Threshold(mt9v03x_image[0],MT9V03X_W, MT9V03X_H);//大津计算阈值
- }
- else
- {
- //出界后不算阈值,由于全局变量特性,会保留上次的阈值,确保出去之后屏幕是黑的,防止出现雪花屏
- }
- Image_Binarization(Threshold);//图像二值化
- mt9v03x_finish_flag=0;//标志位清除,自行准备采集下一帧数据
- }
- Longest_White_Column();//最长白列巡线
- //元素放在下面
- if(Go==7)//GO==7才是常规寻迹,不在7里面,只做最简单的巡线,不去识别元素
- {
- Zebra_Stripes_Detect();
- Ramp_Detect();
- Barricade_Detect();
- Break_Road_Detect();
- Island_Detect();
- Cross_Detect();
- Img_Disappear_Detect();
- ////Straight_Detect();//赛场上估计没有长直道
- }
- //元素放在上面
- Err=Err_Sum(); //误差计算
- Direction_Control();//方向控制
- // Show_Boundry();
- // ips200_show_gray_image(0,0,image_two_value[0],MT9V03X_W,MT9V03X_H,MT9V03X_W,MT9V03X_H,0);
- // Zw_SendImage(image_two_value[0]);
- }
复制代码
- 起首是图像预处置惩罚,阈值,二值化之类的操纵;
- 然后是根本巡线,搜刮边线,丢线,记载赛道根本数据;
- 元素判断,根据根本数据举行元素判断,在元素中会举行角点,单调点等举行进一步判断,同时举行界限补线等;
- 偏差盘算,补线在元素处置惩罚中就完成了,到这里边线数据就可以变为偏差控制数据;
- 边线直接写入图像,由于我直接修改了二值化图像,以是必须比及全部图像处置惩罚后才可以利用此函数;
- 表现,由于我的边线信息直接写进图像内里,那我直接利用图传,大概屏幕表现图像函都可瞥见边线。
固然,出现题目时间,一行一行代码解释,一行一行再加返来,精确定位故障代码,没什么好办法。
盼望可以或许资助到一些人。
本人菜鸡一只,各位大佬发现题目接待留言指出
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金 |