十六届智能车全向组算法开源(四) 您所在的位置:网站首页 拐点应该怎么写 十六届智能车全向组算法开源(四)

十六届智能车全向组算法开源(四)

2024-02-09 00:22| 来源: 网络整理| 查看: 265

前言

         在我比赛的算法,通常在处理元素之前,需要具备良好的图像边界,拐点,边界起始行,边界截止行等主要条件。之前系列文章介绍过了边界,和拐点。有人留言提到过拐点的程序,其实最简单的方法,就是连续几行的边界做差,差值满足条件就判断为拐点。

        圆环!!这个在我做车三年一直都是噩梦存在的元素,虽然16届增加了新元素三岔,我依然在圆环花费了最多的时间。因为今年选用的是摄像头入环,所以在处理圆环的时候,不仅仅要考虑如何识别,还需要在入环,环内进行补线处理。于是我在处理圆环大致分为识别,入环切线,入环 ,环内,出环,出环切线,完全出环这几个阶段。

void R_uppoint( unsigned char Row_START,unsigned char Row_END ,unsigned char Col_START,unsigned char Col_END,unsigned char Edge_ROW) { int Col; //uint8 N_P=0; int C1=0; int Row=Edge_ROW; for(Row=Edge_ROW;Row>Edge_ROW-7 && Row>ROW_START+1;Row--)//从本行开始向上扫10行 { for(Col=Col_END-2;Col>15;Col--)//初始值固定 { if(difference_sum(image[Row][Col-COL_SPACE],image[Row][Col])>=g_threshold_value)//检测到跳变点 { if( abs(Col-COL_SPACE-C1)L_down_point.x+5>ROW_END-1) Round_row=ROW_END-1; else Round_row=point->L_down_point.x+5; for(;Round_row>point->L_down_point.x-10&&Round_row>=ROW_START;Round_row--)//从左拐点下面5行到上面10行进行搜索 { if(str->RightEdge[Round_row+1]!=0&&str->RightEdge[Round_row]!=0) { //如果右边正常递减,且不丢线 斜率符合要求 if(str->RightEdge[Round_row+1]-str->RightEdge[Round_row]>=0 &&str->RightEdge[Round_row+1]-str->RightEdge[Round_row]Entrance_count++; //圆环入口计数增加 } } } if(round->Entrance_count>=13)//min修改,其中有13行满足条件即可判定为圆环 { round->Round_flag=1; RoundType=Left_Round; RoundProcess=Find_Round; RoadType= Round_Road; // BlueRing; //RoundSize=Large_Round; //待定 } 进环前处理:

我们在识别到环的时候,是在环外的,所以需要保持一段距离直行到环的切点A。我的方法是通过 B点之前的斜率进行补线。   

for(Round_row=ROW_END;Round_row>=ROW_START;Round_row--) { if(str->RightEdge[Round_row]) { char temp_r; char temp_l; char track; temp_r=str->RightEdge[Round_row]; track=Boundary.track_Width[Round_row]; temp_l=temp_r-track-1; if(temp_l>=79) { temp_l=78; } if(temp_lLeftEdge[Round_row]=temp_l; // str->LeftEdge[Round_row]=str->RightEdge[Round_row]-str->track_Width[Round_row];//左边界等于右边界减半宽 } else { str->LeftEdge[Round_row]=0; } }  进环处理:

对于进环,需要将右边线通过补线方式补成一个类似与弯道的情况。然后通过陀螺仪积分判断旋转的角度,当角度满足车身已经进入到环里的条件,就可以正常的巡线走了。

 

case Into_Round://进环 关键 分两步 { // lcd_showint8(110,6, 2); /*进环的补线处理*/ if(!Inflection_point.L_down_point.x&&!Inflection_point.L_up_point.x&&str->LeftEdge[ROW_END-5])//&&str->LeftEdge[ROW-4]) // if(Inflection_point.L_up_point.x==0&&Inflection_point.L_down_point.x&&str->LeftEdge[ROW_END-3]) // if(Inflection_point.L_up_point.x&&(left_ad>=220||right_ad>200)&&!str->LeftEdge[ROW_END-1]) { RoundProcess=Into_Round2; } else { //获取补线点信息 if(point->L_down_point.x>5) //记录上一次拐点存在的信息 { Inflection_Temp_x=point->L_down_point.x; Inflection_Temp_y=point->L_down_point.y; } //得到信息后,开始补线 for(uint8 i=Inflection_Temp_x;i>2;i--) { if(image[i][Inflection_Temp_y]>=Threshold&&image[i-1][Inflection_Temp_y]EndLine=i-1; break; } } for(uint8 i=Inflection_Temp_y;i=Threshold)&&(image[LeftLoopTemp_R-1][i]RightEdge[aa1]-aa2)/(aa1-LeftLoopTemp_R); for(uint8 i=0;iRightEdge[LeftLoopTemp_R+i]=(int)(i*LeftLoopSlope+LeftLoopTemp_C); str->RightEdge[LeftLoopTemp_R+i]=int8_range_protect(str->RightEdge[LeftLoopTemp_R+i],1,79) ; if(str->RightEdge[LeftLoopTemp_R+i]>78||LeftLoopTemp_R+i>ROW_END) break; } } for(uint8 i=str->EndLine;ij+1) str->RightEdge[i]=j+1; break; } } } break; } case Into_Round2://进环 关键 4 { // lcd_showint8(110,6, 3); /*判断是否进入环岛*/ if(angle_zL_StartLine==0&& RoundSize==Small_Round) //定距离一段 { RoundProcess=In_Round; Inflection_Temp_x=0; Inflection_Temp_y=0; //lcd_showint8(80,5, 4); } #if 1 //补线 for(uint8 i=str->EndLine;iRightEdge[i]=j+1; break; } } } /*进环斜率*/ LeftLoopSlope=2.0; for(uint8 i=ROW_END;i>ROW_START;i--) { // lcd_showint8(80,5, 5); if(str->RightEdge[i]!=0) str->RightEdge[i]=str->RightEdge[i]RightEdge[i]:(int)(LeftLoopSlope*i+5); else str->RightEdge[i]=(int)(LeftLoopSlope*i+5); if(str->RightEdge[i]>79) str->RightEdge[i]=0; } for(uint8 i=29;i>str->EndLine&&i>ROW_START+2;i--) { //lcd_showint8(80,5, 6); if(image[i][10]>=Threshold&&image[i-1][10]str->EndLine&&j>ROW_START;j--) { str->LeftEdge[j]=0; } str->EndLine=i-1; //改变endline break; } if(str->LeftEdge[i]>30) { str->LeftEdge[i]=0; //限幅 } } #endif break; }  出环处理:

在出环时,由于左边线不存在,因此也需要进行补线操作。目的就是为了出环时车转弯方向是正确的,

case Leave_Round://离开圆环 { // lcd_showint8(110,4, 6); Round_num=0; for(Round_row=str->R_StartLine;Round_row>str->EndLine+1&&Round_row>ROW_START+10;Round_row--) { if(str->RightEdge[Round_row]==0) { Round_num++; } } if(Round_numR_StartLine-str->EndLine)>22||str->RightEdge[str->EndLine]>18)) //30需要调 huo 判断斜率 { RoundProcess=Leave_Round2;//暂定 } else { LeftLoopSlope=2.5; for(uint8 i=29;i>5;i--) { if(str->RightEdge[i]!=0) str->RightEdge[i]=str->RightEdge[i]RightEdge[i]:(unsigned char)(LeftLoopSlope*i+5); else str->RightEdge[i]=(unsigned char)(LeftLoopSlope*i+5); if(str->RightEdge[i]>79) str->RightEdge[i]=0; } for(uint8 i=29;i>str->EndLine;i--) //消除左线误搜索 { if(str->LeftEdge[i]>40) { str->LeftEdge[i]=0; } if(iROW_START) { if(str->LeftEdge[i]!=0&&str->LeftEdge[i-1]==0&&str->LeftEdge[i+1]==0) str->LeftEdge[i]=0; } } } break; } 出环后处理:

在出环后,由于环岛元素存在的缺口,仍需要补线进行引导。也是通过斜率来进行补线。

 

Round_num=0; for(Round_row=str->R_StartLine;Round_row>str->EndLine+1&&Round_row>ROW_START+10;Round_row--) { if(str->RightEdge[Round_row]==0) { Round_num++; } } if(Round_numR_StartLine-str->EndLine)>22||str->RightEdge[str->EndLine]>18)) //30需要调 huo 判断斜率 { RoundProcess=Leave_Round2;//暂定 } else { LeftLoopSlope=2.5; for(uint8 i=29;i>5;i--) { if(str->RightEdge[i]!=0) str->RightEdge[i]=str->RightEdge[i]RightEdge[i]:(unsigned char)(LeftLoopSlope*i+5); else str->RightEdge[i]=(unsigned char)(LeftLoopSlope*i+5); if(str->RightEdge[i]>79) str->RightEdge[i]=0; } for(uint8 i=29;i>str->EndLine;i--) //消除左线误搜索 { if(str->LeftEdge[i]>40) { str->LeftEdge[i]=0; } if(iROW_START) { if(str->LeftEdge[i]!=0&&str->LeftEdge[i-1]==0&&str->LeftEdge[i+1]==0) str->LeftEdge[i]=0; } } }

之后当车行过缺口就可以恢复正常巡线,这里可以积路程,简单一点,也可以采用起始行是否在图像最底端来判断。

最后

底下附上完整过程代码,以便大家推导理解,对于代码,不建议直接拿去用,因为图像与摄像头参数都不一样。可以根据上面提到的思路,自己写一遍。分阶段来实现进环,至少这套方法我在圆环这里基本没出现过问题,除了速度快了,麦轮没办法很及时的转弯进去。

多嘴一句,这里的方法也不是最好的,但之于我是很有效的。可能也有更快,更好,更丝滑的进环算法。我就充当一个抛砖引玉的角色,希望能帮助没有思路的车友有一种简单有效的方法去实现进环。这一章也是自己用手画的图,在我看来在调试元素的时候,趴赛道才是最好的方法。需要各位仔细琢磨,不断完善,才可以有适合自己的算法。

void Round_Process(Str_Boundary *str,Str_Round *round,Str_Inflection_point *point) { float LeftLoopSlope; float RightLoopSlope; uint8 break_point_num; uint8 many_bp_row; uint8 white_point_num; uint8 Round_num=0; break_point_num=0; switch(RoundType) { case Left_Round: //左环 { switch(RoundProcess) { case Find_Round://发现圆环 { // mark_garage(); // lcd_showint8(110,4, 0); for(uint8 i=29;i>=0&&i>Boundary.EndLine;i--) { if( Boundary.LeftEdge[i]==0 && Boundary.RightEdge[i] ) { for(uint8 j=Boundary.RightEdge[i];j-1>5;j--) { if(mark_middle_num(image[i][j],image[i][j-1],Threshold) && abs( difference_sum(image[i][j],image[i][j-1]) )>=g_threshold_value-10 )//跳变 { break_point_num++; if(break_point_num>7 ) { many_bp_row++; break; } } } } if(many_bp_row>3)//黑白跳变点数 90 { round->Round_flag=0; RoadType= else_road; return; } } // lcd_showint8(120,5,many_bp_row); //*进入下个阶段的判定*/ if(str->L_StartLineL_StartLine;Round_row>=str->L_StartLine-4&&Round_row>=ROW_START+1;Round_row--) //防止误判 检测换中心岛 { if(str->LeftEdge[Round_row]!=0) { Round_num+=str->LeftEdge[Round_row]-str->LeftEdge[Round_row+1] ; } else { Round_num=0; } } if(Round_num>10) { Round_num=0; RoundProcess=Find_Gap;//就认为有缺口 // lcd_showint8(80,1, 1); } } //*入环的补线*/ for(Round_row=ROW_END;Round_row>=ROW_START;Round_row--) { if(str->RightEdge[Round_row]) { char temp_r; char temp_l; char track; temp_r=str->RightEdge[Round_row]; track=Boundary.track_Width[Round_row]; temp_l=temp_r-track-1; if(temp_l>=79) { temp_l=78; } if(temp_lLeftEdge[Round_row]=temp_l; // str->LeftEdge[Round_row]=str->RightEdge[Round_row]-str->track_Width[Round_row];//左边界等于右边界减半宽 } else { str->LeftEdge[Round_row]=0; } } break; } case Find_Gap://发现圆环中心 { // lcd_showint8(110,6, 1); /*下一阶段的判定*/ //底部三行左边界都不丢线 // if(str->LeftEdge[ROW_END-2]&&str->LeftEdge[ROW_END-1]&&str->LeftEdge[ROW_END-3])//&&str->LeftEdge[ROW_END-2] // if(Inflection_point.L_up_point.x&&Inflection_point.L_down_point.x&&(Inflection_point.L_down_point.x-Inflection_point.L_up_point.x)LeftEdge[ROW_END-2]&&str->LeftEdge[ROW_END-1]&&str->LeftEdge[ROW_END-3]&&Inflection_point.L_up_point.x) // mark_garage(); // if(str->LeftEdge[ROW_END-1]-str->LeftEdge[ROW_END-2]>0&&str->LeftEdge[ROW_END-2]-str->LeftEdge[ROW_END-3]>0) // for(uint8 i=29;i>=0&&i>Boundary.EndLine;i--) // { // // if( Boundary.LeftEdge[i]==0 && Boundary.RightEdge[i] ) { // for(uint8 j=Boundary.RightEdge[i];j-1>COL_END-10;j++) // { // if(mark_middle_num(image[i][j],image[i][j-1],Threshold) // && abs( difference_sum(image[i][j],image[i][j-1]) )>=g_threshold_value-10 )//跳变 // { // break_point_num++; // if(break_point_num>7 ) // { // many_bp_row++; // break; // } // } // } } // // if(many_bp_row>2)//黑白跳变点数 90 // { // round->Round_flag=0; // RoadType= else_road; // return; // } // } if(e_distance>1000) { if(Inflection_point.L_up_point.x) { RoundProcess=Into_Round; } } /*左补线*/ for(Round_row=ROW_END;Round_row>=ROW_START;Round_row--) { if(str->RightEdge[Round_row]) { // str->LeftEdge[Round_row]=str->RightEdge[Round_row]-str->track_Width[Round_row];//左边界等于右边界减半宽 char temp_r; char temp_l; char track; temp_r=str->RightEdge[Round_row]; track=Boundary.track_Width[Round_row]; temp_l=temp_r-track; if(temp_l>=79) { temp_l=78; } if(temp_lLeftEdge[Round_row]=temp_l; } else { str->LeftEdge[Round_row]=0; } } break; } case Into_Round://进环 关键 分两步 { // lcd_showint8(110,6, 2); /*进环的补线处理*/ if(!Inflection_point.L_down_point.x&&!Inflection_point.L_up_point.x&&str->LeftEdge[ROW_END-5])//&&str->LeftEdge[ROW-4]) // if(Inflection_point.L_up_point.x==0&&Inflection_point.L_down_point.x&&str->LeftEdge[ROW_END-3]) // if(Inflection_point.L_up_point.x&&(left_ad>=220||right_ad>200)&&!str->LeftEdge[ROW_END-1]) { RoundProcess=Into_Round2; } else { //获取补线点信息 if(point->L_down_point.x>5) //记录上一次拐点存在的信息 { Inflection_Temp_x=point->L_down_point.x; Inflection_Temp_y=point->L_down_point.y; } //得到信息后,开始补线 for(uint8 i=Inflection_Temp_x;i>2;i--) { if(image[i][Inflection_Temp_y]>=Threshold&&image[i-1][Inflection_Temp_y]EndLine=i-1; break; } } for(uint8 i=Inflection_Temp_y;i=Threshold)&&(image[LeftLoopTemp_R-1][i]RightEdge[aa1]-aa2)/(aa1-LeftLoopTemp_R); for(uint8 i=0;iRightEdge[LeftLoopTemp_R+i]=(int)(i*LeftLoopSlope+LeftLoopTemp_C); str->RightEdge[LeftLoopTemp_R+i]=int8_range_protect(str->RightEdge[LeftLoopTemp_R+i],1,79) ; if(str->RightEdge[LeftLoopTemp_R+i]>78||LeftLoopTemp_R+i>ROW_END) break; } } for(uint8 i=str->EndLine;ij+1) str->RightEdge[i]=j+1; break; } } } break; } case Into_Round2://进环 关键 4 { // lcd_showint8(110,6, 3); /*判断是否进入环岛*/ if(angle_zL_StartLine==0&& RoundSize==Small_Round) //定距离一段 { RoundProcess=In_Round; Inflection_Temp_x=0; Inflection_Temp_y=0; //lcd_showint8(80,5, 4); } #if 1 //补线 for(uint8 i=str->EndLine;iRightEdge[i]=j+1; break; } } } /*进环斜率*/ LeftLoopSlope=2.0; for(uint8 i=ROW_END;i>ROW_START;i--) { // lcd_showint8(80,5, 5); if(str->RightEdge[i]!=0) str->RightEdge[i]=str->RightEdge[i]RightEdge[i]:(int)(LeftLoopSlope*i+5); else str->RightEdge[i]=(int)(LeftLoopSlope*i+5); if(str->RightEdge[i]>79) str->RightEdge[i]=0; } for(uint8 i=29;i>str->EndLine&&i>ROW_START+2;i--) { //lcd_showint8(80,5, 6); if(image[i][10]>=Threshold&&image[i-1][10]str->EndLine&&j>ROW_START;j--) { str->LeftEdge[j]=0; } str->EndLine=i-1; //改变endline break; } if(str->LeftEdge[i]>30) { str->LeftEdge[i]=0; //限幅 } } #endif break; } case In_Round://在环内 5 { // lcd_showint8(110,4,4); //记录上一次拐点存在的信息 if(point->R_down_point.x&&image[point->R_down_point.x][point->R_down_point.y-2]>=Threshold&&image[point->R_down_point.x][point->R_down_point.y-3]>=Threshold&&image[point->R_down_point.x-1][point->R_down_point.y]>=Threshold&&image[point->R_down_point.x-2][point->R_down_point.y]>=Threshold) { Inflection_Temp_x=point->R_down_point.x; Inflection_Temp_y =point->R_down_point.y; //判断下一阶段 if(point->R_down_point.x>5) { uint8 hang_num=0; //清除白块计数值 8 for(Round_row=point->R_down_point.x-1; Round_row>=point->R_down_point.x-6&&Round_row>ROW_START ; Round_row-- ) //在搜索到的黑白跳变点后,向上搜索白点,判断是否为干扰点 { if(str->RowLose[Round_row]==4) { hang_num++; } } if( hang_num>2|| point->R_down_point.x>20||Inflection_point.R_down_point.y>30) { RoundProcess=Out_Round; // lcd_showint8(110,4, 4); } } } if(Inflection_Temp_x>0) { //补线 LeftLoopSlope=2.0; for(uint8 i=Inflection_Temp_x+1;i>ROW_START;i--) { str->RightEdge[i]=(int)((i-Inflection_Temp_x)*LeftLoopSlope+Inflection_Temp_y); //fuhao if (str->RightEdge[i]EndLine =i; break; } } //str->StartLine=ROW_END; //memset(str->LeftEdge, 0,sizeof(str->LeftEdge) ); //z左线清空 } for(uint8 i=29;i>str->EndLine;i--) //消除左线误搜索 { if(str->LeftEdge[i]>30) { str->LeftEdge[i]=0; } } break; } case Out_Round://出环 6 { // BlueRing; // lcd_showint8(110,4, 5); LeftLoopSlope=2.1; for(uint8 i=29;i>5;i--)//取小值 { if(str->RightEdge[i]!=0) str->RightEdge[i]=str->RightEdge[i]RightEdge[i]:(unsigned char)(LeftLoopSlope*i+7); else str->RightEdge[i]=(unsigned char)(LeftLoopSlope*i+7); if(str->RightEdge[i]>79) str->RightEdge[i]=0; } // str->StartLine=ROW_END; // memset(str->LeftEdge, 0,sizeof(str->LeftEdge) ); // if(angle_zstr->EndLine;i--) //消除左线误搜索 { if(str->LeftEdge[i]>35) { str->LeftEdge[i]=0; } if(iROW_START) { if(str->LeftEdge[i]!=0&&str->LeftEdge[i-1]==0&&str->LeftEdge[i+1]==0) str->LeftEdge[i]=0; } } /*下一阶段的判定*/ break; } case Leave_Round://离开圆环 { // lcd_showint8(110,4, 6); Round_num=0; for(Round_row=str->R_StartLine;Round_row>str->EndLine+1&&Round_row>ROW_START+10;Round_row--) { if(str->RightEdge[Round_row]==0) { Round_num++; } } if(Round_numR_StartLine-str->EndLine)>22||str->RightEdge[str->EndLine]>18)) //30需要调 huo 判断斜率 { RoundProcess=Leave_Round2;//暂定 } else { LeftLoopSlope=2.5; for(uint8 i=29;i>5;i--) { if(str->RightEdge[i]!=0) str->RightEdge[i]=str->RightEdge[i]RightEdge[i]:(unsigned char)(LeftLoopSlope*i+5); else str->RightEdge[i]=(unsigned char)(LeftLoopSlope*i+5); if(str->RightEdge[i]>79) str->RightEdge[i]=0; } for(uint8 i=29;i>str->EndLine;i--) //消除左线误搜索 { if(str->LeftEdge[i]>40) { str->LeftEdge[i]=0; } if(iROW_START) { if(str->LeftEdge[i]!=0&&str->LeftEdge[i-1]==0&&str->LeftEdge[i+1]==0) str->LeftEdge[i]=0; } } } break; } case Leave_Round2://离开圆环 7 { //可以拉长视野 // lcd_showint8(110,4, 7); for(Round_row=ROW_END;Round_row>=ROW_START;Round_row--) { if(str->RightEdge[Round_row]) { // str->LeftEdge[Round_row]=str->RightEdge[Round_row]-str->track_Width[Round_row];//左边界等于右边界减半宽 //if(str->RightEdge[Round_row]) char temp_r; char temp_l; char track; temp_r=str->RightEdge[Round_row]; track=str->track_Width[Round_row]+2.8; temp_l=temp_r-track; if(temp_l>=79) { temp_l=78; } if(temp_lLeftEdge[Round_row]=temp_l; } else { str->LeftEdge[Round_row]=0; } } if (Lost_numL_StartLine&&str->R_StartLine&&str->L_StartLine==29&&str->R_StartLine==29&&Inflection_point.L_down_point.x==0&&Inflection_point.L_up_point.x==0) { // lcd_showint8(110,4, 7); if(str->LeftEdge[ROW_END-2]-str->LeftEdge[ROW_END-1]>0&&str->LeftEdge[ROW_END-4]-str->LeftEdge[ROW_END-3]>0) { RoundProcess=Round_Not_Found;//暂定 round->Round_flag=0; RoadType= else_road; // BlueQuiet; } } } break; } default: { break; } } break; } }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有