飞思卡尔国赛摄像头组程序
单片机源程序如下:
- #include "include.h"
- #include "calculation.h"
- #include"VisualScope.h"
- #include "CCD.h"
- #include "LQ12864.h"
- s16 INT_COUNT=100; //LPT 产生中断的计数次数
- extern u32 LPT_INT_count;
- s16 count;
- #define duoji_center 2400//*舵机中值,根据自己的小车自行修改
- /* 接口:PWM:PTC1,PTC2,PTC3,PTC4
- 舵机:PTA8
- 摄像头:行中断:PTD13,场中断:PTC8,PCLK:PTD12,数据端:PTD0~PTD7
- 带有//*的是需要修改的参数 关于下面的P、I、D最好先清零,即SpeedKP=0,SpeedKI=0,TurnP=0,TurnD=0*/
- //PID参数
- float TurnP=4.4,TurnD=0.6;//*转向PD
- float SpeedKP =6;//*速度P 过大,车轮旋转一前转一后转,表现为走走停停
- float SpeedKI =1;//*速度I
- float g_Speedgoal=500;//*目标速度 即编码器的目标脉冲值
- //时间标志位
- extern u8 TIME1flag_100ms,flag_1ms ;
- extern u8 TIME1flag_1s ; //PT1口1s定时标志位
- int start_flag=0,stop_jiasu=0;//开机静止跑道2秒标志
- s32 ATimeCount=0;//100ms进入pid标志
- s32 TimeCount ;//1ms中断标志
- //速度变量
- s16 g_nLeftMotorPulse,g_nRightMotorPulse,g_nLeftMotorPulseSigma,g_nRightMotorPulseSigma,lm,rm;
- extern s32 LeftMotorOut ,RinghtMotorOut ;
- float g_SpeedControlOutNew,g_SpeedControlOutOld ;
- s16 SpeedPeriodCount=0 ;
- s32 SpeedPWM = 0 ;
- s32 LastSpeedPWM = 0 ;
- s32 MotorSpeedPWM,MotorTurnPWM ;
- s32 PWMout ;
- s16 zhidao=1,wandao=0;
- //CCD变量
- extern s32 g_SpeedControlIntegral;
- s16 TurnPeriodCount=0 ;
- s16 TurnPWMOUT=0 ;
- s16 LastTurnPWMOUT=0;
- int sudu_xianshi=0;
- void run();
- void main()
- {
- DisableInterrupts; //禁止总中断
- uart_init (UART0,9600);//初始化UART0,串口频率 9600
- FTM2_QUAD_Iint();//一路正交解码 A相---PTA10 B相---PTA11
- gpio_init (PORTA , 17, GPO,HIGH); //程序运行灯
- // oled_init();
- CCD_init (); //摄像头初始化
- pit_init_ms(PIT0, 1); //初始化PIT0,定时时间为: 1ms
- pit_init_ms(PIT1, 100);//初始化PIT1,定时时间为: 100ms
- set_irq_priority (90,3);//行中断
- set_irq_priority (89,2);//场中断
- set_irq_priority (84,1);//PIT0中断 优先级最高
- FTM_init() ; //FTM初始化
- lptmr_counter_init(LPT0_ALT2,INT_COUNT,2,LPT_Rising);//PTC5脚 脉冲累加计数器
- EnableInterrupts;//开总中断
- uart_irq_EN(UART0);//开串口0中断
- while(1)
- {
- if(flag_1ms==1)//运行run函数
- {
- flag_1ms=0;
- run();
- }
- // display_suducaiji();//速度显示函数
- }
- }
- void run()//在isr.c中的1ms中断中调用 PIT0_IRQHandler
- {
- TimeCount++ ;
- SpeedPeriodCount++;
- TurnPeriodCount++;
- MotorTurnPWM = TurnPWMOut(TurnPWMOUT,LastTurnPWMOUT,TurnPeriodCount) ;
- MotorSpeedPWM = SpeedPWMOut(g_SpeedControlOutNew ,g_SpeedControlOutOld,SpeedPeriodCount);
- if(TimeCount>=5)//读速度 5us
- {
- TimeCount=0;
- GetMotorPulse();//正交解码读取其中一路速度
- }
- else if(TimeCount == 1)//为空
- {
- PWMout=MotorSpeedOut(MotorSpeedPWM);//电机输出
- }
- else if(TimeCount == 2)//速度控制
- {
- ATimeCount ++ ;
- if(ATimeCount >= 20)
- {
- ATimeCount=0;
- sudu_xianshi=1;//采集完速度的标志,用于向上位机发送速度
- count =get_counter_value(); //读取LPTMR0_CNR之前需要先对这个寄存器赋值!!!
- lptmr_counter_clean(); //清空脉冲计数器计算值(马上清空,这样才能保证计数值准确)
- g_nLeftMotorPulseSigma=LPT_INT_count*INT_COUNT+count;//每LPT_INT_count个脉冲产生一次中断,LPT_INT_count为中断的次数,
- if(PWMout>0)//由于这一路没有使用正交解码,因此速度脉冲方向由电机方向判定
- g_nLeftMotorPulseSigma=-g_nLeftMotorPulseSigma;
- LPT_INT_count=0;//对中断次数清零 //count为不足产生一次中断的值
- lm=g_nLeftMotorPulseSigma;//获得左、右轮速度用于上位机显示
- rm=g_nRightMotorPulseSigma;
- SpeedPID() ; //速度PI调节
- SpeedPeriodCount = 0 ;
- }
- }
- else if(TimeCount == 3)//方向控制
- {
- FTM_CnV_REG(FTMx[FTM1], CH0) =MotorTurnPWM+duoji_center;//方向控制 要加上舵机中值
- LastTurnPWMOUT = TurnPWMOUT ;
- TurnPeriodCount = 0 ;
- }
- else if(TimeCount == 4)
- {
- if(TIME1flag_1s == 1)//程序运行灯
- {
- TIME1flag_1s=0;
- PTA17_OUT=~PTA17_OUT;
- }
- }
- }
复制代码- #include "common.h"
- #include "include.h"
- #include "calculation.h"
- #include "CCD.h"
- #include"VisualScope.h"
- #include "LQ12864.h"
- extern s16 zhidao,wandao;
- float S_xy=0,S_xx=0,x=0,y=0,S_y=0,S_x=0;//算斜率的
- int slope=0;
- int youbian_ysy=0,jinduan_ybx=0,zuobian_ysy=0,jinduan_zbx=0,ztuichu=0;//拟合中线
- int yici_zuo=0,yici_you=0;
- int zuoqishi=0,youqishi=0,zzxqishi=0,yzxqishi=0,zxqishi=0,zstop=0,ystop=0;
- int yx_left=0,yx_right=0;//根据近端中线方向判别断行处应该具有的方向
- int youbian_qi=0,zuobian_qi=0;//判断是否为弯道
- int zuobian_youxiao=0,zuobian_stop=0,youwan_youxiao=0,youwan_flag=0,youwan_center=0,youwan_centerstop=0;
- int youbian_youxiao=0,youbian_stop=0,zuowan_youxiao=0,zuowan_flag=0,zuowan_center=0,zuowan_centerstop=0;
- int value=0,wandao_youxiao=0,zuowan=0,youwan=0;
- int zhangai_qishi=0,zhangai_jieshu=0;//障碍起始 可惜没用上
- int start_y=0,yous=0,stop_z=0,start_z=0,zuos=0,stop_y=0,zuozs=0,youzs=0,youss=0,zuoss=0;//十字 有点复杂
- int left_sz=0,right_sz=0,left_xsz=0,right_xsz=0;
- int zshizi=0,zxshizi=0,yxshizi=0;
- int xieshizi_zuoflag=0,youxiaozuoxieshizi=0,xiexs=0,xieys=0;//斜十字标志
- int xieshizi_youflag=0,youxiaoyouxieshizi=0,xiees=0,xiefs=0;
- int left=0,right=0,leftzuo=0,rightzuo=0,leftyou=0,rightyou=0,rightsz=0,leftsz=0;
- s16 centerxunizuo[50],centerxuniyou[50];//虚拟中心 判别用
- s16 centerszyupan[50],centerzuoyupan[50],centeryouyupan[50];
- int youxiaoyoubianyan=0,lastyoubianyan=0;
- int youxiaozuo=0,youxiaoyoubian=0;
- int youxiaoyou=0,youxiaozuobian=0;
- int as,bs,cs,ds;
- int is,js,jz,shizi_flag=0,youxiao_shizi=0,jieshu_shizi=0,qishi_shizi=0;
- int xs=0,ys=0,es=0,fs=0;
- int szis=0;
- int jdt=0,id,jd;
- s16 direction,TurnPosition,TurnMidPosition=78;//靠左减小值
- float lasterror ;
- float sum=0;
- int zhengshizi=0;
- int szq=0,szs=0;
- int m1=0,m2=0,m3=0,m4=0,m5=0,m6=0;
- int n1=0,n2=0,n3=0,n4=0,n5=0,n6=0;
- extern float TurnP,TurnD;
- extern s16 g_nDirectionControlFlag ;
- s16 yuzhizhi;//阈
- extern s16 TurnPWMOUT ,LastTurnPWMOUT;//转向PWM
- u8 ImageBuf[DATALINE][lie];
- u8 shizibx[DATACOUNT];
- u8 yuzhipd[50];
- u8 ImageBuf2[DATALINE][DATACOUNT];
- s16 blackright[DATALINE];
- s16 blackleft[DATALINE];
- s16 center[DATALINE];
- s16 valuerownum=0,value_flag=0,value_yici=0;
- s8 badframe=0;
- float CenterEx[3]={0,0,0};
- int CenterEq=0;
- //加权平均参数,一般是远大近小,间隔均匀,根据小车情况调
- float CorrectEx[50]={2.6,2.6,2.6,2.6,2.6,2.56,2.52,2.48,2.44,2.4,
- 2.36,2.32,2.3,2.26,2.22,2.18,2.14,2.1,2.06,2.02,
- 1.98,1.94,1.9,1.86,1.82,1.78,1.74,1.7,1.66,1.62,
- 1.58,1.54,1.5,1.47,1.42,1.38,1.34,1.3,1.26,1.22,
- 1.18,1.14,1.10,1.07,1.03,1.0,1.0,1.0,1.0,1.0
- };
- u8 bxiankuan[50]={21,22,22,23,24,24,25,26,26,27,
- 28,28,29,30,30,31,32,33,33,34,
- 34,35,36,37,37,38,39,40,41,42,
- 43,45,46,47,49,50,51,52,53,54,
- 55,56,57,58,59,59,59,60,60,61};//赛道宽度的一半
- void CCD_init (void)
- {
- exti_init(PORTC,8, falling_down) ; //场中断
- exti_init(PORTD,13, falling_down) ; //行中断
- }
- void fasongtuxiang()//发送原始图像到红树伟业上位机
- {
- int i,j;
- for(i=0;i<DATALINE;i++)//采样行数 50
- {
- for(j=32;j<lie;j++)//采样点数 100
- {
- if(ImageBuf[i][j]==0xff)
- ImageBuf[i][j]=0xfe;
- uart_putchar (UART0,ImageBuf[i][j]);
- }
- }
- uart_putchar (UART0,0xff );
- }
- float absx(float i)//作用: 求绝对值 浮点型
- {
- if(i<0) return (-i);
- else return i;
- }
- s32 absi(s32 i)//作用: 求绝对值 int型
- {
- if(i<0) return (-i);
- else return i;
- }
- u16 yuzhi(u16 i)//作用: 求一行的阈值
- {
- u16 j,max=0,min=255;
- for(j=0;j<DATACOUNT;j++)//采样点数 100
- {
- if(ImageBuf[i][j]>max)
- {
- max=ImageBuf[i][j];
- }
- else if(ImageBuf[i][j]<min)
- {
- min=ImageBuf[i][j];
- }
- }
- return (u16)((min+max)/2);//此处需要-20;自己试试
- }
- void erzhihua()//作用: 将采集的数据二值化
- {
- u16 i,j;
- for(i=0;i<DATALINE;i++)//由于实验室光线不均匀,近端与远端使用不同的阈值
- {
- if(i>30)//近端
- yuzhizhi=yuzhi(i)+12;//加大后黑色变多 根据场地不同调参数
- else //远端
- yuzhizhi=yuzhi(i)+19;//根据场地不同调参数
- for(j=32;j<lie;j++)
- {
- if(ImageBuf[i][j]<yuzhizhi) //二值化为0和1 白为0,黑为1
- ImageBuf2[i][j-32]=0x01;
- else
- ImageBuf2[i][j-32]=0x00;
- }
- }
- }
- s16 yp_left=0,yp_right=0;
- s16 yupan_fangxiang(s16 yp_qishi)//只是预判,与最终中线无关!!!
- {
- yp_left=0,yp_right=0,szis=0;
- for(is=yp_qishi;is<=48;is++)
- {
- if(blackright[is]>(DATACOUNT-2)&&blackleft[is]==0)
- centerzuoyupan[is]=DATACOUNT/2;//中心预判
- else if(blackright[is]>(DATACOUNT-2)&&blackleft[is]!=0&&(is>0))
- centerzuoyupan[is]=blackleft[is]+bxiankuan[is];//一端没线,粗略地根据赛道进行平移
- else if(blackright[is]<(DATACOUNT-2)&&blackleft[is]==0&&(is>0))
- centerzuoyupan[is]=blackright[is]-bxiankuan[is];
- else
- centerzuoyupan[is]=(blackright[is]+blackleft[is])/2;//两边都有,取中值
- szis++;
- if(szis>=1)
- {
- if((centerzuoyupan[is]-centerzuoyupan[is-1])<=-1)
- yp_right++;//右倾
- else if((centerzuoyupan[is]-centerzuoyupan[is-1])>=1)
- yp_left++;//左倾
- }
- }
- if((yp_right>=(yp_right+yp_left+1)/2))
- return 1 ;//右倾较多
- if((yp_left>=(yp_right+yp_left+1)/2))
- return 2;//左倾较多
- }
- //作用: 求有效行,并且求左右边缘,最终求的中心
- void countcenter()
- {
- s16 i,j,m;
- s16 rightstart,leftstart,rightend,leftend;
- m1=0,m2=0,n1=0,n2=0;
- for(i=0;i<DATALINE;i++)//对图像处理参数初始化
- {
- blackright[i]=DATACOUNT;
- blackleft[i]=0;
- center[i]=0;
- centerxunizuo[i]=centerxuniyou[i]=DATACOUNT/2;
- centerszyupan[i]=centerzuoyupan[i]=centeryouyupan[i]=0;
- right=left=0;
- rightzuo=leftzuo=0;
- rightyou=leftyou=0;
- rightsz=leftsz=0;
- zuoqishi=youqishi=0;
- }
- //计算前2行的左右边缘
- for(i=DATALINE-1;i>DATALINE-3;i--)
- {
- for(j=(DATACOUNT/2-10);j<(DATACOUNT-1);j++)//计算前2行右边界 起始点靠左一点
- {
- if(ImageBuf2[i][j-1]==0&&ImageBuf2[i][j]==1&&ImageBuf2[i][j+1]==1&&blackright[i]==DATACOUNT)//省掉break,
- {
- blackright[i]=j;
- }
- }
- for(m=(DATACOUNT/2+10);m>0;m--) //计算前2行左边界 起始点靠右一点
- {
- if(ImageBuf2[i][m-1]==1&&ImageBuf2[i][m]==1&&ImageBuf2[i][m+1]==0&&blackleft[i]==0)//省掉break,
- {
- blackleft[i]=m;
- }
- }
- if(blackleft[i]!=0&&blackright[i]!=DATACOUNT)
- centerxunizuo[i]=(blackleft[i]+blackright[i])/2;//算出虚拟中线,为后面决策作参考
- else if(blackleft[i]==0&&blackright[i]!=DATACOUNT)
- centerxunizuo[i]=blackright[i]-bxiankuan[i];
- else if(blackleft[i]!=0&&blackright[i]==DATACOUNT)
- centerxunizuo[i]=blackleft[i]+bxiankuan[i];
- }
- //前2行循环
- //over
- rightstart=blackright[DATALINE-2]-3;//根据前两行来确定搜索的起始点
- rightend=blackright[DATALINE-2]+3;
- leftstart=blackleft[DATALINE-2]+3;
- leftend=blackleft[DATALINE-2]-3;
- if(leftend<=0)
- leftend=0;
- if(rightend>=DATACOUNT)
- rightstart=DATACOUNT;
- //计算右边界的有效行数和右边界
- for(i=DATALINE-3;i>=0;i--)//
- {
- for(j=rightstart;j<rightend;j++)//右线用0xx011,比较稳定可靠
- {
- if(rightend>=DATACOUNT)
- rightend=DATACOUNT;
- if(ImageBuf2[i][j-4]==0&&ImageBuf2[i][j-1]==0&&ImageBuf2[i][j]==1&&ImageBuf2[i][j+1]==1) //在范围内找到黑线,这个地方需要注意
- {
- blackright[i]=j;
- rightstart=j-4;//找到黑线,为下一行的起始赋值
- rightend=j+4;
- if(rightstart<=1)
- rightstart=1;
- if(rightend>=DATACOUNT)
- rightend=DATACOUNT;
- m1++;//无用,可删掉
- break;
- }
- }
- if(j==rightend) //在范围内没有找到黑线
- {
- rightstart=rightstart-bxiankuan[i];//平移半个赛道宽重新找黑线 可优化
- rightend=DATACOUNT;//
- if(rightstart<=1)
- rightstart=1;
- for(j=rightstart;j<rightend;j++)//同样是0xx011
- {
- if(ImageBuf2[i][j-4]==0&&ImageBuf2[i][j-1]==0&&ImageBuf2[i][j]==1&&ImageBuf2[i][j+1]==1) //在范围内找到黑线&&ImageBuf2[i-1][j+1]==1
- {
- blackright[i]=j;
- rightstart=j-4;
- rightend=j+4;
- if(rightstart<=1)
- rightstart=1;
- if(rightend>=DATACOUNT)
- rightend=DATACOUNT;
- m2++;
- break;
- }
-
- }
- if(j==rightend) //在范围内没有找到黑线
- rightstart=rightstart+bxiankuan[i];//还未找到?起始点还原到上次确定的起始点
- }
- for(m=leftstart;m>leftend;m--)//左线用110xx0 以下有上面对称,不再注释
- {
- if(ImageBuf2[i][m+4]==0&&ImageBuf2[i][m+1]==0&&ImageBuf2[i][m]==1&&ImageBuf2[i][m-1]==1)
- {
- blackleft[i]=m;
- leftstart=m+4;
- leftend=m-4;
- if(leftend<=0)
- leftend=0;
- if(leftstart>=DATACOUNT)
- leftstart=DATACOUNT;
- n1++;
- break;
- }
- }
- if(m==leftend)
- {
- leftstart=leftstart+bxiankuan[i];//centerxunizuo[i+1];
- leftend=0;//leftend-6;
- if(leftend<=0)
- leftend=0;
- if(leftstart>=DATACOUNT)
- leftstart=DATACOUNT;
- for(m=leftstart;m>leftend;m--)
- {
- if(ImageBuf2[i][m+4]==0&&ImageBuf2[i][m]==1&&ImageBuf2[i][m+1]==0&&ImageBuf2[i][m-1]==1)
- {
- blackleft[i]=m;
- leftstart=m+3;
- leftend=m-3;
- if(leftend<=0)
- leftend=0;
- if(leftstart>=DATACOUNT)
- leftstart=DATACOUNT;
- n2++;
- break;
- }
-
- }
- if(m==leftend)
- leftstart=leftstart-bxiankuan[i];
- }//右边界循环结束
- if(blackleft[i]!=0&&blackright[i]!=DATACOUNT)
- centerxunizuo[i]=(blackleft[i]+blackright[i])/2;//计算虚拟中线
- else if(blackleft[i]==0&&blackright[i]!=DATACOUNT)
- centerxunizuo[i]=blackright[i]-bxiankuan[i];
- else if(blackleft[i]!=0&&blackright[i]==DATACOUNT)
- centerxunizuo[i]=blackleft[i]+bxiankuan[i];
- }
- }
- //十字处理函数,比较麻烦,情况分为正十字(分为远处四点都有,近处只有两点两种情况),左斜十字和右斜十字,
- //在实际操作时可能会发现,各自分类的界限并没有很明确,可能斜十字的情况在正十字里就补好线了,这是为了
- //有交集,这样不会丢失各种情况,不会有“都不管”的情况
- void shizi_handle()
- {
- int i,kk,jj,tt,ss;
- zshizi=0,zxshizi=0,yxshizi=0;
- shizi_flag=youxiao_shizi=0, jieshu_shizi=0,qishi_shizi=0;
- xs=ys=fs=es=0,left_sz=0,right_sz=0;
- zstop=0,ystop=0,zxqishi=0,zzxqishi=0,yzxqishi=0;
- start_y=0,yous=0,stop_z=0,start_z=0,zuos=0,stop_y=0,zuozs=0,youzs=0;
- /////////////////////////正十字补线///////////////////////
- //连续3行以上都是全白,且中点也是白
- for(is=DATALINE-1;is>=10;is--)//提取特征:两端都是白色的,搜不到黑线
- {
- if(youxiao_shizi==0&&(blackleft[is]==0)&&(blackright[is]==DATACOUNT)&&(blackleft[is-1]==0)&&(blackright[is-1]==DATACOUNT)&&(blackleft[is-2]==0)&&(blackright[is-2]==DATACOUNT)&&
- ImageBuf2[is][blackleft[is]]==0&&ImageBuf2[is-1][blackleft[is-1]]==0&&ImageBuf2[is][blackright[is]-1]==0&&ImageBuf2[is-1][blackright[is-1]-1]==0&&ImageBuf2[is][DATACOUNT/2]==0)
- youxiao_shizi=is;//十字开始行
- if(shizi_flag==0&&youxiao_shizi!=0&&blackleft[is]==0&&blackright[is]==DATACOUNT&&blackleft[is-1]==0&&(blackright[is-1]==DATACOUNT)&&(ImageBuf2[is][blackleft[is]]==0)&&
- (ImageBuf2[is-1][blackleft[is-1]]==0)&&(ImageBuf2[is][blackright[is]-1]==0)&&(ImageBuf2[is-1][blackright[is-1]-1]==0)&&ImageBuf2[is][DATACOUNT/2]==0&&
- (ImageBuf2[is-2][blackright[is-2]-1]==1||ImageBuf2[is-2][blackleft[is-2]]==1||blackleft[is-2]>0||blackright[is-2]<=(DATACOUNT-1)))
- { //其实前面两条就够了,后面这两条为了保险才加的
- shizi_flag=is-1; //十字结束行 在起始行的基础上继续搜索得到
- break;//跳出,省时间
- }
- }
- if((youxiao_shizi-shizi_flag)>=1&&(youxiao_shizi-shizi_flag)<=25)//对白色纵向宽度做限制
- {
- for(is=DATALINE-1;is>youxiao_shizi;is--)
- { //左下端特征:边线存在且大于0;拐点之下由近端到拐点呈递增趋势(且比较陡),之上呈递减趋势(且比较缓).
- if(blackleft[is]>1&&blackleft[is+1]>1&&(blackleft[is]-blackleft[is+1])>=0&&
- (blackleft[is]-blackleft[is-1])>=1&&(blackleft[is]-blackleft[is-2])>=3&&zstop==0)
- {
- zzxqishi=is;//由近到远 寻找左下端拐点
- zstop=1;
- }
- //右下端特征:边线存在且小于DATACOUNT;拐点之下由近端到拐点呈递减趋势(且比较陡),之上呈递增趋势(且比较缓).
- if(blackright[is]<DATACOUNT&&blackright[is+1]<DATACOUNT&&(blackright[is]-blackright[is+1])<=0&&
- (blackright[is]-blackright[is-1])<=-1&&(blackright[is]-blackright[is-2])<=-3&&ystop==0)
- {
- yzxqishi=is;//寻找右下端拐点
- ystop=1;
- }
- }
- //此处针对靠下的拐点
- if(zzxqishi>=yzxqishi&&(zzxqishi<=47)) zxqishi=zzxqishi;//比较后使用最靠近车的行
- else if (zzxqishi<yzxqishi&&(yzxqishi<=47)) zxqishi=yzxqishi;
- else if(zzxqishi==0&&yzxqishi!=0) zxqishi=yzxqishi;//一端没有,用另一端的作为最后的拐点
- else if(zzxqishi!=0&&yzxqishi==0) zxqishi=zzxqishi;
- else zxqishi=0;//两端都没有,即车体进入十字中,此时没有最下端的拐点
- // yupan_fangxiang(zxqishi);//主要为下面服务的 预判函数
- }
- if((youxiao_shizi-shizi_flag)>=1&&(youxiao_shizi-shizi_flag)<=25)
- {//由于存在十字的原因,之前搜到的边线可能不准,需要重新搜线,需要确定搜线的起始列,即left_sz,right_sz
- //最远行对应的列坐标应该位于赛道的中心位置!!!
- for(int jdf=0;jdf<DATACOUNT;jdf++)
- shizibx[jdf]=shizi_flag;//初始化为十字的结束行
- jdt=shizi_flag;//初始化为十字的结束行
- for(jd=0;jd<DATACOUNT;)//纵向搜线,寻找最远端
- {
- for(id=shizi_flag;id>0;id--)//从十字的结束行往上搜索直到第一行
- {
- if(ImageBuf2[id+1][jd]==0&&ImageBuf2[id][jd]==1&&ImageBuf2[id-1][jd]==1)
- {//由下到上纵向搜索,011成立便找到点了
- shizibx[jd]=id;//将第id行存入数组中
- break;
- }
- }
- jd+=10;//此时只是粗略地找最远端,所以不需要每一列都搜索,隔10列可以节约时间
- }
- for(int jdf=0;jdf<DATACOUNT;jdf++)
- {//最远处的行应小于“上一次的最远行”!!!,且不等于结束行
- if((shizibx[jdf]<shizibx[jdt])&&shizibx[jdf]!=shizi_flag)
- jdt=jdf;//获得最远行对应的列坐标,如此反复进入几次就能把最远行对应的列坐标求出
- }
- left_sz=jdt+10;//有了列坐标就能推出左右的起始列了。因为最远行对应的列坐标应该位于赛道的中心位置!!!
- right_sz=jdt-10;//左右都平移一段距离,留出余量
- //重新遍历后面的行
- for(int ig=youxiao_shizi;ig>=0;ig--)
- {
- if(left_sz>blackright[ig]) left_sz=blackright[ig];//越界限制
- for(int jg=left_sz;jg>=1;jg--)//左线是110,且列大于左下端点的列坐标或 其根本没有下端点
- {
- if(ImageBuf2[ig][jg-1]==1&&ImageBuf2[ig][jg]==1&&ImageBuf2[ig][jg+1]==0&&(jg>=blackleft[zzxqishi]||zxqishi==0)) //在范围内找到黑线
- {
- blackleft[ig]=jg;
- kk++;
- break;
- }
- }
- if(kk>5&&((blackright[ig+1]-blackleft[ig+1])<(2*bxiankuan[ig+1]+10)))//限制条件,求出的赛道宽度小于直道的宽度加一个允许波动值
- {//由于赛道不是直线,每5行更新一次left_sz,作为下一次搜线的起始列
- kk=0;
- left_sz=blackleft[ig+1]+bxiankuan[ig+1];//根据上一行的左线虚拟出下一次的起始列
- }
- if(right_sz<blackleft[ig]) right_sz=blackleft[ig];//越界限制
- for(int mg=right_sz;mg<=DATACOUNT-1;mg++)//右线是011,且列小于右下端点的列坐标或 其根本没有下端点
- {
- if(ImageBuf2[ig][mg-1]==0&&ImageBuf2[ig][mg]==1&&ImageBuf2[ig][mg+1]==1&&(mg<=blackright[yzxqishi]||zxqishi==0)) //在范围内找到黑线
- {
- blackright[ig]=mg;
- jj++;
- break;
- }
- if(jj>5&&((blackright[ig+1]-blackleft[ig+1])<(2*bxiankuan[ig+1]+10)))
- {//由于赛道不是直线,每5行更新一次right_sz,作为下一次搜线的起始列
- jj=0;
- right_sz=blackright[ig+1]-bxiankuan[ig+1];//根据上一行的右线虚拟出下一次的起始列
- }
- }
- }
- for(is=DATALINE-3;is>1;is--)//求出拐点!
- {
- as=(blackleft[is]-blackleft[is-2]);//与上两行做一次差
- bs=(blackleft[is]-blackleft[is+2]);//与下两行做一次差
- js=blackleft[is]; //为该行的列坐标
- if((bs>=5&&as<=0)&&xs==0&&(absi(as)<=6)&&(is<=shizi_flag)&&(is>=(shizi_flag-18))&&(blackleft[is]>1)&&((ImageBuf2[is+1][js+1]+ImageBuf2[is+1][js]+ImageBuf2[is+1][js-1])<=1))
- xs=is;//上面 左上拐点的特征:之下为递增(或直接增),之上为递增,之下两行的绝对值比较小,左上拐点在十字起始行上面,且在一个范围内,周围几个点的白色多一些
- if((as>=4&&bs>=0)&&ys==0&&(absi(bs)<=6)&&(is>=xs)&&(is>=youxiao_shizi)&&blackleft[is]>1&&((ImageBuf2[is-1][js+1]+ImageBuf2[is-1][js]+ImageBuf2[is-1][js-1])<=1))
- ys=is;//下面 左下拐点的特征:之下为递增,之上为递减(或直接减),在十字起始行下面
- cs=(blackright[is]-blackright[is-2]);
- ds=(blackright[is]-blackright[is+2]);
- jz=blackright[is];
- if((ds<=-5&&cs>=0)&&es==0&&(absi(cs)<=6)&&(is<=shizi_flag)&&(is>=(shizi_flag-18))&&(blackright[is]<=(DATACOUNT-2))&&((ImageBuf2[is+1][jz+1]+ImageBuf2[is+1][jz]+ImageBuf2[is+1][jz-1])<=1))
- es=is;//上面 右上拐点的特征:之下为递减(或直接减),之上为递减,。。。
- if((ds<=0&&cs<=-3)&&fs==0&&(absi(ds)<=6)&&(is>=es)&&(is>=youxiao_shizi)&&(blackright[is]<=(DATACOUNT-2))&&((ImageBuf2[is-1][jz+1]+ImageBuf2[is-1][jz]+ImageBuf2[is-1][jz-1])<=1))
- fs=is;//下面 右下拐点的特征:之下为递减,之上为递增(或直接增)
- }
- //有下端拐点的进来!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- //下端拐点在十字开始行的下面,且(左线在中线以左 或 下端拐点处的右线在中线以右),
- if((zxqishi-12)<youxiao_shizi&&((blackleft[zxqishi]<(DATACOUNT/2-10))||blackright[zxqishi]>(DATACOUNT/2+10))&&
- zxqishi!=0&&(zzxqishi!=0||yzxqishi!=0)&&zxqishi<=(DATACOUNT-3)) //有拐点的进来
- {//且下端拐点的确存在,且左、右拐点至少存在一个;限幅
- if(xs!=0&&ys!=0&&ys<=(zxqishi+10)&&ys>=(zxqishi-10)&&blackleft[xs]>=blackleft[ys])//左侧进行连线
- {//左侧上下拐点都存在,且下拐点在下端点拐点的合理范围之内,左上拐点比左下拐点靠右
- for(int iz=xs-1;iz<=ys+1;iz++)//一次函数连线
- {//为了更加平滑,各让一步
- blackleft[iz+1]=(blackleft[iz]-blackleft[ys+1])/(iz-ys-1)+blackleft[iz];//注意顺序,上面拐点在左还是在右
- zshizi=1;//正入十字标志置1,为下面使用
- }
- }//同样,不作注释
- if(es!=0&&fs!=0&&fs<=(zxqishi+10)&&fs>=(zxqishi-10)&&blackright[fs]>=blackright[es])//右侧进行连线
- {
- for(int iz=es-1;iz<=fs+1;iz++)
- {
- blackright[iz+1]=((blackright[fs+1]-blackright[iz])/(fs+1-iz))+blackright[iz];
- zshizi=1;//正入十字标志置1,为下面使用
- }
- }
- //为了下面求中线的起始行和结束行而使用
- if(xs>=es) szq=es;//仅为标准正十字服务
- else szq=xs;//十字起始行以上为主
- if(ys>=fs) szs=ys;
- else szs=fs;//十字接收行以下为主
- if(xs!=0&&ys!=0&&es!=0&&fs!=0)//标准正十字 四拐点都存在
- {
- for(i=szq-1;i<=szs+1;i++)//为了平滑,各让一步
- if(center[i]==0)//由于前面已经补线了,此处只需求中值即可
- center[i]=(blackright[i]+blackleft[i])/2;
- }
- else if(xs!=0&&ys!=0&&(es==0||fs==0))//右侧丢失
- {
- for(i=xs-1;i<=ys+1;i++)
- if(center[i]==0)//中线靠左线加赛道宽度而得
- center[i]=(bxiankuan[i]+blackleft[i]);
- }
- else if(es!=0&&fs!=0&&(xs==0||ys==0))//左侧丢失
- {
- for(i=es-1;i<=fs+1;i++)
- if(center[i]==0)//中线靠右线减赛道宽度而得
- center[i]=(blackright[i]-bxiankuan[i]);
- }
- }
- //近端处理 无下拐点的进来!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- else if(youxiao_shizi>=30&&shizi_flag>=24&&(es!=0&&xs!=0)&&(es>=(xs-13)&&xs>=(es-13)))//如果刚进入十字,则只有最上面两个拐点,
- { //十字比较靠近车 且两个上拐点都存在,es与xs在合理的范围内
- for(int iz=xs-1;iz<DATALINE-1;iz++)//此时补线利用左拐点与左下角坐标值连线,右拐点与右下角坐标值连线
- {//一次函数连线
- blackleft[iz+1]=-(blackleft[iz])/(DATALINE-1-iz)+blackleft[iz];//注意顺序,上面拐点在左还是在右
- zshizi=1;//正入十字标志置1,为下面使用
- }
- for(int iz=es-1;iz<DATALINE-1;iz++)
- {
- blackright[iz+1]=((DATACOUNT-blackright[iz])/(49-iz))+blackright[iz];
- zshizi=1;//正入十字标志置1,为下面使用
- }
- if(xs>=es) szq=es;//选取靠上的拐点,作为下面求中线的起始行
- else szq=xs;
- for(i=szq;i<=49;i++)
- center[i]=(blackright[i]+blackleft[i])/2;
- }
- //十字后期处理 主要处理一些不常见的情况,可不看
- if(zshizi==1)
- {
- for(i=DATALINE-1;i>1;i--)
- {
- if(blackleft[i]<=1&&blackright[i]<(DATACOUNT-1)&¢er[i]==0)//左线丢失
- {
- if(center[i-1]!=0)//给下端补线
- center[i]=blackright[i]-(blackright[i-1]-center[i-1]+1);
- else if(center[i+1]!=0)//给上端补线
- center[i]=blackright[i]-(blackright[i+1]-center[i+1]-1);
- else
- center[i]=blackright[i]-bxiankuan[i];
- }
- if(blackleft[i]>1&&blackright[i]==DATACOUNT&¢er[i]==0)//右线丢失
- {
- if(center[i-1]!=0)//给下端补线
- center[i]=blackleft[i]+(center[i-1]-blackleft[i-1]+1);
- else if(center[i+1]!=0)//给上端补线
- center[i]=blackleft[i]+(center[i+1]-blackleft[i+1]-1);
- else
- center[i]=blackleft[i]+bxiankuan[i];
- }
- }
- }
- }
- //左侧斜十字补线 各标志位清零
- xieshizi_zuoflag=0,xieshizi_youflag=0,youxiaozuoxieshizi=0,youxiaoyouxieshizi=0,xiexs=0,xieys=0,xiees=0,xiefs=0;
- for(is=DATALINE-3;is>5;is--)
- {//连续两行的左线都存在 下增上减
- if(blackleft[is]>1&&blackleft[is+1]>1&&(blackleft[is]-blackleft[is+1])>=0&&
- (blackleft[is]-blackleft[is+2])>=1&&(blackleft[is]-blackleft[is-1])>=1&&(blackleft[is]-blackleft[is-2])>2)
- {
- zuoqishi=is;//先寻找左下拐点
- break;
- }
- }
- if(zuoqishi!=0)//左下拐点存在才能进入
- {
- for(is=zuoqishi;is>2;is--)//从左下拐点向上寻找
- { //连续三行左端都没找到线
- if(youxiaozuoxieshizi==0&&blackleft[is]==0&&blackleft[is-1]==0&&blackleft[is-2]==0&&
- ImageBuf2[is][blackleft[is]]==0&&ImageBuf2[is-1][blackleft[is-1]]==0)
- {//并且连续两行左端 二值化图像 都是白的
- if(youxiaozuoxieshizi==0)//进行遍历,寻找起始行
- youxiaozuoxieshizi=is;
- } //连续两行没找到线,且从下到上是白到黑或左线找到了
- if(youxiaozuoxieshizi!=0&&blackleft[is]==0&&blackleft[is-1]==0&&ImageBuf2[is-1][blackleft[is-1]]==0&&
- (ImageBuf2[is-2][blackleft[is-2]]==1||blackleft[is-2]!=0))//一般上侧结束行都是极值,只有分辨图像是黑是白
- {
- xieshizi_zuoflag=is-1;//寻找结束行
- break;//找到就跳出,省时间
- }
- }
- }
- //斜十字补线 左侧 白色区域在合理范围内, 下拐点在白色下面
- if((youxiaozuoxieshizi-xieshizi_zuoflag)>2&&(youxiaozuoxieshizi-xieshizi_zuoflag)<30&&(zuoqishi-15)<youxiaozuoxieshizi&&
- (blackleft[zuoqishi]<(DATACOUNT/2+30))&&zuoqishi!=0&&yupan_fangxiang(zuoqishi)==1)
- { // 右倾较多
- left_xsz=centerxunizuo[zuoqishi]+25;//根据预判得出虚拟中线,
- for(int ig=zuoqishi;ig>0;ig--)//重新搜线
- {
- if(left_xsz>=blackright[ig]) left_xsz=blackright[ig];
- for(int jg=left_xsz;jg>=0;jg--)
- {
- if(ImageBuf2[ig][jg+1]==0&&ImageBuf2[ig][jg]==1&&ImageBuf2[ig][jg-1]==1&&jg>=blackleft[zuoqishi]) //在范围内找到黑线
- {
- blackleft[ig]=jg; //更新左线数组
- ss++;
- break;
- }
- }
- if(ss>4)
- {
- ss=0;
- left_xsz=blackleft[ig+1]+bxiankuan[ig+1];
- }
- }
- xieshizi_zuoflag=0;
- for(is=zuoqishi;is>5;is--)//斜十字补线 再判断 由于前面更新了左线数组,此时再次确认无误
- {
- if(youxiaozuoxieshizi==0&&blackleft[is]==0&&blackleft[is-1]==0&&blackleft[is-2]==0)
- {
- if(youxiaozuoxieshizi==0)
- youxiaozuoxieshizi=is;//得出起始行
- }
- if(youxiaozuoxieshizi!=0&&blackleft[is]==0&&blackleft[is-1]==0&&
- ImageBuf2[is][blackleft[is]]==0&&ImageBuf2[is-1][blackleft[is-1]]==0&&(ImageBuf2[is-2][blackleft[is-2]]==1||blackleft[is-2]!=0))
- {
- xieshizi_zuoflag=is-1;//得出结束行
- break;
- }
- }
- for(is=DATALINE-3;is>=0;is--)//十字补线,同正十字
- {
- as=absi(blackleft[is]-blackleft[is-2]);
- bs=absi(blackleft[is+2]-blackleft[is]);
- js=blackleft[is]; //下面
- if((as>5&&bs<=8)&&xieys==0&&(is>=(youxiaozuoxieshizi))&&((ImageBuf2[is-1][js+1]+ImageBuf2[is-1][js]+ImageBuf2[is-1][js-1])<=1))
- xieys=is;
- if((bs>5&&as<=6)&&xieys!=0&&(is<=xieshizi_zuoflag)&&(is>=(xieshizi_zuoflag-12))&&blackleft[is]>=blackleft[xieys]&&(blackleft[is]>1)&&((ImageBuf2[is+1][js+1]+ImageBuf2[is+1][js]+ImageBuf2[is+1][js-1])<=1))
- {
- xiexs=is;//上面
- break;
- }
- }
- if(xieys!=0&&xiexs!=0&&xieys>xiexs)
- {
- for(int iz=xiexs;iz<=xieys;iz++)//只能补一侧
- {
- blackleft[iz+1]=((blackleft[xieys]-blackleft[iz])/(xieys-iz))+blackleft[iz];
- center[iz+1]=(bxiankuan[iz+1]+blackleft[iz+1]);
- zxshizi=1;//左斜十字标志置1
- }
- for(int iz=DATALINE-1;iz>=3;iz--)//把右侧没搜到线的行的中线根据左侧补出来
- {
- if(blackleft[iz]>=1&&blackright[iz]>=(DATACOUNT-1))
- center[iz]=blackleft[iz]+bxiankuan[iz];//
- }
- }
- }
- //右侧 斜十字补线/////
- for(int is=DATALINE-3;is>=5;is--)//斜十字补线 右侧 预判断
- {
- if(blackright[is]<DATACOUNT&&blackright[is-1]<=DATACOUNT&&blackright[is-2]<=DATACOUNT&&(blackright[is]-blackright[is+1])<=0&&
- (blackright[is]-blackright[is+2])<=0&&(blackright[is]-blackright[is-1])<=-1&&(blackright[is]-blackright[is-2])<-3)
- {
- youqishi=is;//右侧的下端拐点
- break;
- }
- }
- for(is=youqishi;is>=5;is--)//得出白色区域
- {
- if(blackright[is]==DATACOUNT&&blackright[is-1]==DATACOUNT&&blackright[is-2]==DATACOUNT&&
- ImageBuf2[is][blackright[is]-1]==0&&ImageBuf2[is-1][blackright[is-1]-1]==0)
- {
- if(youxiaoyouxieshizi==0)//开始记录白点
- youxiaoyouxieshizi=is;
- }
- if(youxiaoyouxieshizi!=0&&xieshizi_youflag==0&&blackright[is]==DATACOUNT&&blackright[is-1]==DATACOUNT&&
- ImageBuf2[is][blackright[is]-1]==0&&ImageBuf2[is-1][blackright[is-1]-1]==0&&(ImageBuf2[is-2][blackright[is-2]-1]==1||blackright[is-2]!=DATACOUNT))
- {
- xieshizi_youflag=is-1;//遇着黑点退出
- break;
- }
- } //右下拐点靠右
- if((youxiaoyouxieshizi-xieshizi_youflag)>1&&(youxiaoyouxieshizi-xieshizi_youflag)<30&&(blackright[youqishi]>(DATACOUNT/2-30))&&
- youqishi!=0&&yupan_fangxiang(youqishi)==2)//左倾较多
- {
- right_xsz=(centerxunizuo[youqishi]-30);//根据得出的虚拟中线,来确定再次搜线的起始列
- for(int ig=youqishi;ig>=0;ig--)//对右线数组重新搜索
- {
- if(right_xsz<=blackleft[ig]) right_xsz=blackleft[ig];
- if(right_xsz<1) right_xsz=1;
-
- for(int jg=right_xsz;jg<=DATACOUNT;jg++)
- {
- if(ImageBuf2[ig][jg-1]==0&&ImageBuf2[ig][jg]==1&&ImageBuf2[ig][jg+1]==1&&jg<=blackright[youqishi]) //在范围内找到黑线
- {
- blackright[ig]=jg;
- tt++;
- break;
- }
- }
- if(tt>2)
- {
- tt=0;
- right_xsz=blackright[ig+1]-bxiankuan[ig+1];
- }
- }
- xieshizi_youflag=0;
- for(is=youqishi;is>=5;is--)//斜十字补线 由于更新了数组,需要再判断
- {
- if(blackright[is]==DATACOUNT&&blackright[is-1]==DATACOUNT&&blackright[is-2]==DATACOUNT&&
- ImageBuf2[is][blackright[is]-1]==0&&ImageBuf2[is-2][blackright[is-2]-1]==0)
- {
- if(youxiaoyouxieshizi==0)
- youxiaoyouxieshizi=is;//得出起始行
- }
- if(youxiaoyouxieshizi!=0&&xieshizi_youflag==0&&blackright[is]==DATACOUNT&&blackright[is-1]==DATACOUNT&&
- ImageBuf2[is][blackright[is]-1]==0&&ImageBuf2[is-1][blackright[is-1]-1]==0&&(blackright[is-2]!=DATACOUNT||ImageBuf2[is-2][blackright[is-2]-1]==1))
- {
- xieshizi_youflag=is-1;//结束行
- break;
- }
- }
- for(is=DATALINE-3;is>=0;is--)//斜十字补线
- {
- as=absi(blackright[is]-blackright[is-2]);
- bs=absi(blackright[is+1]-blackright[is]);
- js=blackright[is]; //下面
- if((as>5&&bs<=6)&&xiefs==0&&(is>=(youxiaoyouxieshizi))&&is<(youqishi+4)&&is>(youqishi-4)&&((ImageBuf2[is-1][js+1]+ImageBuf2[is-1][js]+ImageBuf2[is-1][js-1])<=1))
- xiefs=is;
- if((bs>5&&as<=6)&&xiees==0&&xiefs!=0&&(is<=(xieshizi_youflag))&&(is>=(xieshizi_youflag-18))&&(blackright[is]<=(blackright[xiefs]))&&((ImageBuf2[is+1][js+1]+ImageBuf2[is+1][js]+ImageBuf2[is+1][js-1])<=1))
- xiees=is;//上面(is<=ys)&&(blackleft[i+2]>=2)&&(blackleft[i-3]>=2)youxiao_xieshizi
- }
- if(xiefs!=0&&xiees!=0&&xiefs>xiees)//斜十字畸变较大,前后多找些点进行补
- {
- for(int iz=xiees;iz<(xiefs+3);iz++)//对右侧补完线并求中心值
- {
- blackright[iz+1]=((blackright[xiefs+3]-blackright[iz])/(xiefs+3-iz))+blackright[iz];
- center[iz+1]=(blackright[iz+1]-bxiankuan[iz+1]);
- yxshizi=1;//右斜十字置1
- }
- for(int iz=49;iz>=1;iz--)
- {
- if(blackleft[iz]==0&&blackright[iz]<DATACOUNT)
- center[iz]=blackright[iz]-bxiankuan[iz];
- else if((blackleft[iz]==0&&blackright[iz]>=DATACOUNT))
- center[iz]=DATACOUNT/2;
- }
- }
- }
- }
- /////////////对寻到的边情况分类并处理拟合中线////////
- void nihe_center()
- {
- int i=0;
- youxiaoyou=0,yici_you=0,youxiaozuobian=0,yici_zuo=0,youxiaoyoubian=0,youxiaozuo=0;
- youbian_ysy=0,jinduan_ybx=0,zuobian_ysy=0,jinduan_zbx=0,ztuichu=0;
- for(i=DATALINE-1;i>=0;i--)
- {
- if(center[i]==0)
- {
- if(blackright[i]>=(DATACOUNT-2)&&blackleft[i]<=1&¢er[i]==0)//两边都有取图像中心
- center[i]=DATACOUNT/2;
- else if(blackright[i]>(DATACOUNT-2)&&blackleft[i]!=0&¢er[i]==0&&ImageBuf2[i][blackright[i]-1]==0)//右侧丢线
- {
- if(yici_you==0)//右侧开始丢线处
- yici_you=i;//记录起始行
- if(youxiaoyou==0)
- {
- for(int bs=i;bs>2;bs--)
- {//连续三行的右线为都有值 或连续两行是二值化值是黑的
- if((blackright[bs]!=DATACOUNT&&blackright[bs-1]!=DATACOUNT&&blackright[bs-2]!=DATACOUNT)||
- ImageBuf2[bs][blackright[bs]-1]==1&&ImageBuf2[bs-1][blackright[bs-1]-1]==1)
- {
- youxiaoyou=bs;//结束行
- break;
- }
- }
- }
- if(youxiaozuobian==0)
- {
- for(int bs=i;bs>youxiaoyou-5;bs--)//判断左线连续性,并确定不连续行
- {
- if((blackleft[bs]-blackleft[bs-1])>0||blackleft[bs]>=(DATACOUNT-1)||blackleft[bs-1]>=(DATACOUNT-1))
- {//本来左线是递增向右的,当遇到左线递减了或跑到右边沿了就进入,
- youxiaozuobian=bs;
- break;
- }
- else if((blackleft[bs]-blackleft[bs-1])<=0||blackleft[bs]<(DATACOUNT-1)||blackleft[bs-1]<(DATACOUNT-1))
- youxiaozuobian=bs;//递增时一直更新此值
- }
- }
- if(i==49||i==48||(i==47))//如果靠近车,应该是近端丢线,先判断下
- {
- if(yici_you>=47&&jinduan_ybx==0)
- {
- for(as=(youxiaoyou-2);as>1;as--)
- {
- if((blackright[as]-blackright[as-1])>=-1&&blackright[as]<DATACOUNT)
- {//向上递减
- youbian_ysy=as;
- if(youbian_ysy<39&&(youxiaoyou-youbian_ysy)>6)//验证是否确实是近端丢线 此值应离丢线处不远
- {
- for(int as=youxiaoyou;as<=49;as++)//能进来,可以确定确实近端丢线了
- {
- if(center[as]==0)
- {
- jinduan_ybx=1;//置位标志 //根据前一行的中线求出该行的中线
- center[as]=(blackleft[as-1]+blackright[as-1])/2-blackleft[as-1]+1+blackleft[as];
- }
- }
- }
- if(jinduan_ybx==1) break;//补线完成跳出程序
- }
- else break;//若为进入急弯,则会跳出
- }
- }
- if(jinduan_ybx==0&&yici_you>=46&&youxiaoyou<38&&(youxiaozuobian<=yici_you))//如果不是近端丢线,而是进入急弯 不
- {//建议摄像头的镜头在120度以上,90度的容易进入此处
- for(int as=49;as>youxiaoyou;as--)
- {
- if(center[as]==0&&blackleft[as]!=0)
- {
- center[as]=blackleft[as]+bxiankuan[as]+1;//改变系数1的大小,可改善进入急弯的转向能力
- }
- }
- }
- }
- else if(center[i]==0&&blackleft[i]!=0)//弯道丢线时
- center[i]=center[i+1]-blackleft[i+1]+blackleft[i]+4;//改变系数4的大小,可改善进入急弯的转向能力
- }
- else if(blackright[i]<(DATACOUNT-1)&&blackleft[i]==0&¢er[i]==0)//左侧丢线
- {
- if(yici_zuo==0)//开始丢线处起始
- yici_zuo=i;
- if(youxiaozuo==0)
- {
- for(int ks=i;ks>2;ks--)//重新遍历,确定丢线最上行
- {
- if(blackleft[ks]!=0||ImageBuf2[ks][blackleft[ks]+1]==1)
- {
- youxiaozuo=ks;
- break;
- }
- }
- }
- if(youxiaoyoubian==0)
- {
- for(int ks=i;ks>youxiaozuo-5;ks--)//判断右线连续性,并确定不连续行
- {
- if((blackright[ks]-blackright[ks-1])<0||blackright[ks]<=0||blackright[ks-1]<=0)
- {
- youxiaoyoubian=ks;
- break;
- }
- else if((blackright[ks]-blackright[ks-1])>0||blackright[ks]>0||blackright[ks-1]>0)
- youxiaoyoubian=ks;
-
- }
- }
- //重新遍历最近端的点 判断是否进入急弯,即左侧或右侧一大块没寻到线的地方
- if(i==49||i==48||(i==47))
- {
- if(i>=47&&yici_zuo>=47&&jinduan_zbx==0&&ztuichu==0)
- {
- for(as=(youxiaozuo-2);as>1;as--)
- {
- if((blackleft[as]-blackleft[as-1])<=1&&blackleft[as]>0&&ztuichu==0)
- {
- zuobian_ysy=as;
- if(zuobian_ysy<39&&(youxiaozuo-zuobian_ysy)>6)//验证是否确实是近端丢线
- {
- for(int as=youxiaozuo;as<=49;as++)
- {
- if(center[as]==0)
- {
- jinduan_zbx=1;//置位标志
- center[as]=blackright[as]-(blackright[as-1]-(blackright[as-1]+blackleft[as-1]+1)/2+1);
- }
- }
- }
- if(jinduan_zbx==1) break;//补线完成跳出程序
- }
- else
- break;//若为进入急弯,则会跳出
- }
- }
- if(i>47&&jinduan_zbx==0&&yici_zuo>=48&&youxiaozuo<40&&(youxiaoyoubian<=yici_zuo))//如果不是近端丢线,而是进入急弯
- {
- for(int as=49;as>youxiaozuo;as--)
- if(center[as]==0)
- {
- center[as]=blackright[as]-bxiankuan[as]-4;
- }
- }
- }
- else if(blackright[i]!=DATACOUNT&¢er[i]==0)//进入弯道
- {
- center[i]=blackright[i]-(blackright[i+1]-center[i+1]+3);//改变系数3的大小,可改善进入急弯的转向能力
- }
- }
- else if(center[i]==0)//其他情况,直接取中值
- {
- center[i]=(blackright[i]+blackleft[i])/2;
- }
- }
- }
- }
- void countvaluerow()
- {
- s16 i;
- yx_left=0,yx_right=0;
- value_flag=0,valuerownum=0;
- S_xy=0,S_xx=0,x=0,y=0,S_y=0,S_x=0,slope=0;
- for(i=DATALINE-3;i>=1;i--)
- {
- if(center[i]>=DATACOUNT) center[i]=DATACOUNT;
- else if(center[i]<=0) center[i]=0;
- if(center[i-1]>=DATACOUNT) center[i-1]=DATACOUNT;
- else if(center[i-1]<=0) center[i-1]=0;
- if(center[i-2]>=DATACOUNT) center[i-2]=DATACOUNT;
- else if(center[i-2]<=0) center[i-2]=0;
- if((((absx(center[i]-center[i-1])>5)&&(absx(center[i]-center[i-2])>7))||(center[i]<=0)||(center[i]>=DATACOUNT)||(ImageBuf2[i][center[i]]==1||
- ImageBuf2[i][center[i]+1]==1||ImageBuf2[i][center[i]-1]==1||ImageBuf2[i][center[i]+2]==1||ImageBuf2[i][center[i]-2]==1))&&value_flag==0&&valuerownum==0)
- {
- valuerownum=i;//中心坏行标号
- value_yici=i;
- value_flag=1;
- }
- if((center[i]-center[i-1])<=-1)
- yx_right++;
- else if((center[i]-center[i-1])>=1)
- yx_left++;
- if(value_flag!=0&&valuerownum!=0)
- {
- if((yx_right>(yx_right+yx_left)*3/4)||(i>43&&((center[i]-center[i-1])<0&&(center[i]-center[i-2])<0)))
- {
- if(((center[i]-center[i-1])>0&&(center[i]-center[i-2])>0)||(center[i]<=0)||(center[i]>=DATACOUNT)||(ImageBuf2[i][center[i]]==1||
- ImageBuf2[i][center[i]+1]==1||ImageBuf2[i][center[i]-1]==1||ImageBuf2[i][center[i]+2]==1||ImageBuf2[i][center[i]-2]==1))
- {
- valuerownum=i;
- break;
- }
- }
- else if((yx_left>(yx_right+yx_left)*3/4)||(i>43&&((center[i]-center[i-1])>0&&(center[i]-center[i-2])>0)))
- {
- if(((center[i]-center[i-1])<0&&(center[i]-center[i-2])<0)||(center[i]<=0)||(center[i]>=DATACOUNT)||(ImageBuf2[i][center[i]]==1||
- ImageBuf2[i][center[i]+1]==1||ImageBuf2[i][center[i]-1]==1||ImageBuf2[i][center[i]+2]==1||ImageBuf2[i][center[i]-2]==1))
- {
- valuerownum=i;
- break;
- }
- }
- else break;
- }
- }
- }
- //作用:计算有效行 根据上面黑线的中心偏差来求解有效行
- //改变全局变量: valuerownum
- int wanqishi=0;
- void panduan_youxiao()
- {
- zuobian_youxiao=0,zuobian_stop=0,youwan_youxiao=0,youwan_flag=0,youwan_center=0,youwan_centerstop=0;
- youbian_youxiao=0,youbian_stop=0,zuowan_youxiao=0,zuowan_flag=0,zuowan_center=0,zuowan_centerstop=0;
- wandao_youxiao=0,zuowan=0,youwan=0,youbian_qi=0,zuobian_qi=0;
- for(int i=wanqishi;i>valuerownum;i--)
- {
- if(center[i]<=0||center[i]>=DATACOUNT)
- break;
- if((center[i]-center[i-1])<=-1&¢er[i]!=0&¢er[i]!=DATACOUNT&¢er[i-1]!=0&¢er[i-1]!=DATACOUNT)
- right++;
- else if((center[i]-center[i-1])>=1&¢er[i]!=0&¢er[i]!=DATACOUNT&¢er[i-1]!=0&¢er[i-1]!=DATACOUNT)
- left++;
- }
- if((right>(left+right+1)/2)&&(zshizi==0&&zxshizi==0&&yxshizi==0))//右弯
- {
- for(int xk=wanqishi;xk>=valuerownum;xk--)
- {
- if((blackleft[xk]-blackleft[xk-1])<=0&&(blackleft[xk]-blackleft[xk-2])<=0&&zuobian_qi==0)
- zuobian_qi=xk-2;
- if((blackleft[xk]-blackleft[xk-1])<=0&&(blackleft[xk]-blackleft[xk-2])<=0&&zuobian_stop==0)
- zuobian_youxiao=xk-2; //右弯左侧连续
- else
- zuobian_stop=1;
- if(blackright[xk]==DATACOUNT&&blackright[xk+1]==DATACOUNT&&blackright[xk-1]==DATACOUNT&&youwan_flag==0
- &&ImageBuf2[xk-1][blackright[xk-1]-1]==0&&ImageBuf2[xk+1][blackright[xk+1]-1]==0)
- {
- youwan++;
- if(youwan>5)
- {
- youwan_youxiao=xk;//并且右边有极点
- youwan_flag=1;
- }
- }
- else if(blackright[xk]==DATACOUNT&&blackright[xk+1]==DATACOUNT&&blackright[xk-1]!=DATACOUNT&&youwan_flag==0)
- {
- youwan_youxiao=xk;//并且右边有极点
- youwan_flag=1;
- }
- // if(((center[xk]-center[xk-1])>=0)&&(youwan_centerstop==0)&&xk<43)
- if(((center[xk]-center[xk-1])>0||center[xk-1]>=DATACOUNT)&&(youwan_centerstop==0)&&xk<(wanqishi-4))
- // if(((center[xk]-center[xk-1])<=0&¢er[xk-1]<=DATACOUNT)&&(youwan_centerstop==0)&&xk<(wanqishi-4))
- {
- youwan_center=xk;//并且平滑后的中心线的方向一致
- youwan_centerstop=1;
- }
- // else if(((center[xk]-center[xk-1])>0||center[xk-1]>=DATACOUNT)&&(youwan_centerstop==0)&&xk<(wanqishi-4))
- //if(((center[xk]-center[xk-1])>0||center[xk-1]>=DATACOUNT)&&(youwan_centerstop==0)&&xk<(wanqishi-4))
-
- }
- if(youwan_flag==1&&youwan_centerstop&&zuobian_youxiao>4&&(zuobian_youxiao<=youwan_center))
- {
- value=youwan_center;//符合以上条件,判定为右弯,重新选择有效行youwan_youxiao
- wandao_youxiao=1;
- }
- }
- if((left>(left+right+1)/2)&&(zshizi==0&&zxshizi==0&&yxshizi==0))//左弯
- {
- for(int xk=wanqishi;xk>=valuerownum;xk--)
- {
- if((blackright[xk]-blackright[xk-1])>=0&&(blackright[xk]-blackright[xk-2])>=0&&youbian_qi==0)
- youbian_qi=xk-2;
- if(youbian_qi!=0&&(blackright[xk]-blackright[xk-1])>=0&&(blackright[xk]-blackright[xk-2])>=0&&youbian_stop==0)
- youbian_youxiao=xk-2; //左弯右侧连续
- else
- youbian_stop=1;
- if(blackleft[xk]==0&&blackleft[xk+1]==0&&blackleft[xk-1]==0&&zuowan_flag==0)
- {
- zuowan++;
- if(zuowan>5)
- {
- zuowan_youxiao=xk;//并且左边有极点
- zuowan_flag=1;
- }
- }
- else if(blackleft[xk]==0&&blackleft[xk+1]==0&&blackleft[xk-1]!=0&&zuowan_flag==0
- &&ImageBuf2[xk-1][blackleft[xk-1]]==0&&ImageBuf2[xk+1][blackleft[xk+1]]==0)
- {
- zuowan_youxiao=xk;//并且左边有极点
- zuowan_flag=1;
- }
- // if((((center[xk]-center[xk-1])<=0))&&zuowan_centerstop==0&&(xk<43))
- if((((center[xk]-center[xk-1])<0)||center[xk]<=0)&&zuowan_centerstop==0&&(xk<43))
- // if((((center[xk]-center[xk-1])>=0)&¢er[xk]>=0)&&zuowan_centerstop==0&&(xk<(wanqishi-4)))
- {
- zuowan_center=xk;//并且平滑后的中心线的方向一致
- zuowan_centerstop=1;
- }
- // else //if((((center[xk]-center[xk-1])<0)||center[xk]<0)&&zuowan_centerstop==0&&(xk<(wanqishi-4)))
-
- }
- if(zuowan_flag==1&&zuowan_centerstop&&youbian_youxiao>4&&(youbian_youxiao<=zuowan_center))
- {
-
- value=zuowan_center;//符合以上条件,判定为左弯,重新选择有效行zuowan_youxiao
- wandao_youxiao=1;
- }
- }
- }
- int ii,jj;
- void TurnPWM()
- {
- if(valuerownum>=47)//有效行离车太近,可能冲出赛道了
- {
- wanqishi=45;//虚拟起始点,判断是否有噪点影响了有效行的读取
- valuerownum=valuerownum-13;
- panduan_youxiao();//克服平滑滤波带来的影响,寻找真正有效点
- if(wandao_youxiao==1)//如果是弯道
- valuerownum=46; //这样,数据就不会丢弃了,就会进入下一个if语句里
- else
- badframe=1;//不是弯道,舍弃数据
- }
- if(!badframe)//如果数据有效
- {
- CenterEx[1]=CenterEq;
- sum=0;ii=0;
- if(valuerownum>=35)//最近处,一般是急弯道
- {
-
- wanqishi=valuerownum+5;//虚拟起始点,判断是否有噪点影响了有效行的读取 下同,不做进一步注释
- if(wanqishi>46) wanqishi=46;
- valuerownum=valuerownum-10;
- panduan_youxiao();//克服平滑滤波带来的影响,寻找真正有效点
- if(wandao_youxiao==1)
- valuerownum=value;//有效的话把实际的有效行求出
- else
- valuerownum=valuerownum+10;//无效的话,还原原值
- }
- else if(valuerownum>=17&&valuerownum<35)//有效行在图像中部
- {
- wanqishi=valuerownum+9;
- valuerownum=valuerownum-8;
- panduan_youxiao();
- if(wandao_youxiao==1)
- {
- valuerownum=value;
- }
- else
- valuerownum=valuerownum+8;
- }
- else if(valuerownum>=9&&valuerownum<17)//有效行靠前,离车较远了
- {
- wanqishi=valuerownum+12;
- valuerownum=valuerownum-2;
- if(valuerownum<=0) valuerownum=0;
- panduan_youxiao();
- if(wandao_youxiao==1)
- {
- valuerownum=value;
- }
- else
- {
- valuerownum=valuerownum+2;
- }
- }
- else if(valuerownum>=0&&valuerownum<9)//有效行离车更远了,说明是直道或小s
- {
- zhidao=1;
- wandao=0;
- }
- for(int i=47;i>(valuerownum+1);i--)//五点平滑滤波,使中线更平滑
- center[i]=(center[i+2]+center[i+1]+center[i]+center[i-1]+center[i-2])/5;
- for(jj=valuerownum;jj<DATALINE;jj++)//滤波后进行加权平均,
- {
- sum+=(center[jj]-TurnMidPosition)*CorrectEx[jj];
- ii++;
- }
- CenterEq=(sum/ii); //得到平均值
- }
- else//无效时保持原来的数据
- {
- CenterEq=lasterror;
- lasterror=CenterEq;
- badframe=0;
- }
- if(CenterEq>70)//对加权平均进行限幅,也可不限,数值根据自己的小车定,
- { //一般达不到限幅值,为了防止突发情况
- CenterEq=70;
- }
- else if(CenterEq<-70)
- {
- CenterEq=-70;
- }
- LastTurnPWMOUT=TurnPWMOUT;//新的给旧的
- TurnPWMOUT=(-TurnP*CenterEq-TurnD*lasterror) ; //得出转向PWM,但此时还未加舵机中值
- lasterror=(CenterEq-CenterEx[1]);
-
- }
- /***********************************************************
- 函数名称:TurnPWMOut
- 函数功能:
- 入口参数:NewspeedPWM 当前的电机输出PWM
- LastspeedPWM 上次电机输出PWM
- PeriodCount 平滑周期
- ***********************************************************/
- #define TURNPERIODFAV (30) //摄像头一帧33ms,取30,容易整除,也可不用平滑输出
- s16 TurnPWMOut(s16 NewturnPWM ,s16 LastturnPWM,s16 PeriodCount)
- {
- s16 turnPWMfav ;
- s16 turnOUT ;
- turnPWMfav = NewturnPWM - LastturnPWM ;
- turnOUT = turnPWMfav *(PeriodCount)/TURNPERIODFAV + LastturnPWM ;
- return turnOUT ;
- }
- void fasong_erzhihua_bianxian()//发送到串口调试助手
- {
- int i,j,cha;
- for(i=49;i>=0;i--)
- {
- ImageBuf2[i][center[i]]='*';
- }
- uart_putchar (UART0,'\n' );
- uart_putchar (UART0,'0' );
- uart_putchar (UART0,'0' );
- uart_putchar (UART0,'0' );
- for(i=0;i<13;i++)
- {
- for(j=0;j<10;j++)
- {
- uart_putchar (UART0,j+0x30 );
- }
- }
- uart_sendStr(UART0," ");
- uart_sendStr(UART0,"XL:");
- if(slope<0)
- {
- uart_putchar(UART0,'-');
- slope=-slope;
- }
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
国赛摄像头程序.rar
(12.99 MB, 下载次数: 133)
|