標(biāo)題:
飛思卡爾智能車國賽CCD攝像頭組源程序
[打印本頁]
作者:
Jonelll
時(shí)間:
2018-3-4 12:58
標(biāo)題:
飛思卡爾智能車國賽CCD攝像頭組源程序
飛思卡爾國賽攝像頭組程序
單片機(jī)源程序如下:
代碼:
#include "include.h"
#include "calculation.h"
#include"VisualScope.h"
#include "CCD.h"
#include "LQ12864.h"
s16 INT_COUNT=100; //LPT 產(chǎn)生中斷的計(jì)數(shù)次數(shù)
extern u32 LPT_INT_count;
s16 count;
#define duoji_center 2400//*舵機(jī)中值,根據(jù)自己的小車自行修改
/* 接口:PWM:PTC1,PTC2,PTC3,PTC4
舵機(jī):PTA8
攝像頭:行中斷:PTD13,場中斷:PTC8,PCLK:PTD12,數(shù)據(jù)端:PTD0~PTD7
帶有//*的是需要修改的參數(shù) 關(guān)于下面的P、I、D最好先清零,即SpeedKP=0,SpeedKI=0,TurnP=0,TurnD=0*/
//PID參數(shù)
float TurnP=4.4,TurnD=0.6;//*轉(zhuǎn)向PD
float SpeedKP =6;//*速度P 過大,車輪旋轉(zhuǎn)一前轉(zhuǎn)一后轉(zhuǎn),表現(xiàn)為走走停停
float SpeedKI =1;//*速度I
float g_Speedgoal=500;//*目標(biāo)速度 即編碼器的目標(biāo)脈沖值
//時(shí)間標(biāo)志位
extern u8 TIME1flag_100ms,flag_1ms ;
extern u8 TIME1flag_1s ; //PT1口1s定時(shí)標(biāo)志位
int start_flag=0,stop_jiasu=0;//開機(jī)靜止跑道2秒標(biāo)志
s32 ATimeCount=0;//100ms進(jìn)入pid標(biāo)志
s32 TimeCount ;//1ms中斷標(biāo)志
//速度變量
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); //程序運(yùn)行燈
// oled_init();
CCD_init (); //攝像頭初始化
pit_init_ms(PIT0, 1); //初始化PIT0,定時(shí)時(shí)間為: 1ms
pit_init_ms(PIT1, 100);//初始化PIT1,定時(shí)時(shí)間為: 100ms
set_irq_priority (90,3);//行中斷
set_irq_priority (89,2);//場中斷
set_irq_priority (84,1);//PIT0中斷 優(yōu)先級(jí)最高
FTM_init() ; //FTM初始化
lptmr_counter_init(LPT0_ALT2,INT_COUNT,2,LPT_Rising);//PTC5腳 脈沖累加計(jì)數(shù)器
EnableInterrupts;//開總中斷
uart_irq_EN(UART0);//開串口0中斷
while(1)
{
if(flag_1ms==1)//運(yùn)行run函數(shù)
{
flag_1ms=0;
run();
}
// display_suducaiji();//速度顯示函數(shù)
}
}
void run()//在isr.c中的1ms中斷中調(diào)用 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);//電機(jī)輸出
}
else if(TimeCount == 2)//速度控制
{
ATimeCount ++ ;
if(ATimeCount >= 20)
{
ATimeCount=0;
sudu_xianshi=1;//采集完速度的標(biāo)志,用于向上位機(jī)發(fā)送速度
count =get_counter_value(); //讀取LPTMR0_CNR之前需要先對(duì)這個(gè)寄存器賦值。!
lptmr_counter_clean(); //清空脈沖計(jì)數(shù)器計(jì)算值(馬上清空,這樣才能保證計(jì)數(shù)值準(zhǔn)確)
g_nLeftMotorPulseSigma=LPT_INT_count*INT_COUNT+count;//每LPT_INT_count個(gè)脈沖產(chǎn)生一次中斷,LPT_INT_count為中斷的次數(shù),
if(PWMout>0)//由于這一路沒有使用正交解碼,因此速度脈沖方向由電機(jī)方向判定
g_nLeftMotorPulseSigma=-g_nLeftMotorPulseSigma;
LPT_INT_count=0;//對(duì)中斷次數(shù)清零 //count為不足產(chǎn)生一次中斷的值
lm=g_nLeftMotorPulseSigma;//獲得左、右輪速度用于上位機(jī)顯示
rm=g_nRightMotorPulseSigma;
SpeedPID() ; //速度PI調(diào)節(jié)
SpeedPeriodCount = 0 ;
}
}
else if(TimeCount == 3)//方向控制
{
FTM_CnV_REG(FTMx[FTM1], CH0) =MotorTurnPWM+duoji_center;//方向控制 要加上舵機(jī)中值
LastTurnPWMOUT = TurnPWMOUT ;
TurnPeriodCount = 0 ;
}
else if(TimeCount == 4)
{
if(TIME1flag_1s == 1)//程序運(yùn)行燈
{
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;//根據(jù)近端中線方向判別斷行處應(yīng)該具有的方向
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;//十字 有點(diǎn)復(fù)雜
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;//斜十字標(biāo)志
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;//轉(zhuǎn)向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;
//加權(quán)平均參數(shù),一般是遠(yuǎn)大近小,間隔均勻,根據(jù)小車情況調(diào)
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()//發(fā)送原始圖像到紅樹偉業(yè)上位機(jī)
{
int i,j;
for(i=0;i<DATALINE;i++)//采樣行數(shù) 50
{
for(j=32;j<lie;j++)//采樣點(diǎn)數(shù) 100
{
if(ImageBuf[i][j]==0xff)
ImageBuf[i][j]=0xfe;
uart_putchar (UART0,ImageBuf[i][j]);
}
}
uart_putchar (UART0,0xff );
}
float absx(float i)//作用: 求絕對(duì)值 浮點(diǎn)型
{
if(i<0) return (-i);
else return i;
}
s32 absi(s32 i)//作用: 求絕對(duì)值 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++)//采樣點(diǎn)數(shù) 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()//作用: 將采集的數(shù)據(jù)二值化
{
u16 i,j;
for(i=0;i<DATALINE;i++)//由于實(shí)驗(yàn)室光線不均勻,近端與遠(yuǎn)端使用不同的閾值
{
if(i>30)//近端
yuzhizhi=yuzhi(i)+12;//加大后黑色變多 根據(jù)場地不同調(diào)參數(shù)
else //遠(yuǎn)端
yuzhizhi=yuzhi(i)+19;//根據(jù)場地不同調(diào)參數(shù)
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)//只是預(yù)判,與最終中線無關(guān)!。
{
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;//中心預(yù)判
else if(blackright[is]>(DATACOUNT-2)&&blackleft[is]!=0&&(is>0))
centerzuoyupan[is]=blackleft[is]+bxiankuan[is];//一端沒線,粗略地根據(jù)賽道進(jìn)行平移
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++)//對(duì)圖像處理參數(shù)初始化
{
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;
}
//計(jì)算前2行的左右邊緣
for(i=DATALINE-1;i>DATALINE-3;i--)
{
for(j=(DATACOUNT/2-10);j<(DATACOUNT-1);j++)//計(jì)算前2行右邊界 起始點(diǎn)靠左一點(diǎn)
{
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--) //計(jì)算前2行左邊界 起始點(diǎn)靠右一點(diǎn)
{
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行循環(huán)
//over
rightstart=blackright[DATALINE-2]-3;//根據(jù)前兩行來確定搜索的起始點(diǎn)
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;
//計(jì)算右邊界的有效行數(shù)和右邊界
for(i=DATALINE-3;i>=0;i--)//
{
for(j=rightstart;j<rightend;j++)//右線用0xx011,比較穩(wěn)定可靠
{
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) //在范圍內(nèi)找到黑線,這個(gè)地方需要注意
{
blackright[i]=j;
rightstart=j-4;//找到黑線,為下一行的起始賦值
rightend=j+4;
if(rightstart<=1)
rightstart=1;
if(rightend>=DATACOUNT)
rightend=DATACOUNT;
m1++;//無用,可刪掉
break;
}
}
if(j==rightend) //在范圍內(nèi)沒有找到黑線
{
rightstart=rightstart-bxiankuan[i];//平移半個(gè)賽道寬重新找黑線 可優(yōu)化
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) //在范圍內(nèi)找到黑線&&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) //在范圍內(nèi)沒有找到黑線
rightstart=rightstart+bxiankuan[i];//還未找到?起始點(diǎn)還原到上次確定的起始點(diǎn)
}
for(m=leftstart;m>leftend;m--)//左線用110xx0 以下有上面對(duì)稱,不再注釋
{
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];
}//右邊界循環(huán)結(jié)束
if(blackleft[i]!=0&&blackright[i]!=DATACOUNT)
centerxunizuo[i]=(blackleft[i]+blackright[i])/2;//計(jì)算虛擬中線
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];
}
}
//十字處理函數(shù),比較麻煩,情況分為正十字(分為遠(yuǎn)處四點(diǎn)都有,近處只有兩點(diǎn)兩種情況),左斜十字和右斜十字,
//在實(shí)際操作時(shí)可能會(huì)發(fā)現(xiàn),各自分類的界限并沒有很明確,可能斜十字的情況在正十字里就補(bǔ)好線了,這是為了
//有交集,這樣不會(huì)丟失各種情況,不會(huì)有“都不管”的情況
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;
/////////////////////////正十字補(bǔ)線///////////////////////
//連續(xù)3行以上都是全白,且中點(diǎn)也是白
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)))
{ //其實(shí)前面兩條就夠了,后面這兩條為了保險(xiǎn)才加的
shizi_flag=is-1; //十字結(jié)束行 在起始行的基礎(chǔ)上繼續(xù)搜索得到
break;//跳出,省時(shí)間
}
}
if((youxiao_shizi-shizi_flag)>=1&&(youxiao_shizi-shizi_flag)<=25)//對(duì)白色縱向?qū)挾茸鱿拗?br />
{
for(is=DATALINE-1;is>youxiao_shizi;is--)
{ //左下端特征:邊線存在且大于0;拐點(diǎn)之下由近端到拐點(diǎn)呈遞增趨勢(且比較陡),之上呈遞減趨勢(且比較緩).
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;//由近到遠(yuǎn) 尋找左下端拐點(diǎn)
zstop=1;
}
//右下端特征:邊線存在且小于DATACOUNT;拐點(diǎn)之下由近端到拐點(diǎn)呈遞減趨勢(且比較陡),之上呈遞增趨勢(且比較緩).
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;//尋找右下端拐點(diǎn)
ystop=1;
}
}
//此處針對(duì)靠下的拐點(diǎn)
if(zzxqishi>=yzxqishi&&(zzxqishi<=47)) zxqishi=zzxqishi;//比較后使用最靠近車的行
else if (zzxqishi<yzxqishi&&(yzxqishi<=47)) zxqishi=yzxqishi;
else if(zzxqishi==0&&yzxqishi!=0) zxqishi=yzxqishi;//一端沒有,用另一端的作為最后的拐點(diǎn)
else if(zzxqishi!=0&&yzxqishi==0) zxqishi=zzxqishi;
else zxqishi=0;//兩端都沒有,即車體進(jìn)入十字中,此時(shí)沒有最下端的拐點(diǎn)
// yupan_fangxiang(zxqishi);//主要為下面服務(wù)的 預(yù)判函數(shù)
}
if((youxiao_shizi-shizi_flag)>=1&&(youxiao_shizi-shizi_flag)<=25)
{//由于存在十字的原因,之前搜到的邊線可能不準(zhǔn),需要重新搜線,需要確定搜線的起始列,即left_sz,right_sz
//最遠(yuǎn)行對(duì)應(yīng)的列坐標(biāo)應(yīng)該位于賽道的中心位置。。
for(int jdf=0;jdf<DATACOUNT;jdf++)
shizibx[jdf]=shizi_flag;//初始化為十字的結(jié)束行
jdt=shizi_flag;//初始化為十字的結(jié)束行
for(jd=0;jd<DATACOUNT;)//縱向搜線,尋找最遠(yuǎn)端
{
for(id=shizi_flag;id>0;id--)//從十字的結(jié)束行往上搜索直到第一行
{
if(ImageBuf2[id+1][jd]==0&&ImageBuf2[id][jd]==1&&ImageBuf2[id-1][jd]==1)
{//由下到上縱向搜索,011成立便找到點(diǎn)了
shizibx[jd]=id;//將第id行存入數(shù)組中
break;
}
}
jd+=10;//此時(shí)只是粗略地找最遠(yuǎn)端,所以不需要每一列都搜索,隔10列可以節(jié)約時(shí)間
}
for(int jdf=0;jdf<DATACOUNT;jdf++)
{//最遠(yuǎn)處的行應(yīng)小于“上一次的最遠(yuǎn)行”。。,且不等于結(jié)束行
if((shizibx[jdf]<shizibx[jdt])&&shizibx[jdf]!=shizi_flag)
jdt=jdf;//獲得最遠(yuǎn)行對(duì)應(yīng)的列坐標(biāo),如此反復(fù)進(jìn)入幾次就能把最遠(yuǎn)行對(duì)應(yīng)的列坐標(biāo)求出
}
left_sz=jdt+10;//有了列坐標(biāo)就能推出左右的起始列了。因?yàn)樽钸h(yuǎn)行對(duì)應(yīng)的列坐標(biāo)應(yīng)該位于賽道的中心位置。。
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,且列大于左下端點(diǎn)的列坐標(biāo)或 其根本沒有下端點(diǎn)
{
if(ImageBuf2[ig][jg-1]==1&&ImageBuf2[ig][jg]==1&&ImageBuf2[ig][jg+1]==0&&(jg>=blackleft[zzxqishi]||zxqishi==0)) //在范圍內(nèi)找到黑線
{
blackleft[ig]=jg;
kk++;
break;
}
}
if(kk>5&&((blackright[ig+1]-blackleft[ig+1])<(2*bxiankuan[ig+1]+10)))//限制條件,求出的賽道寬度小于直道的寬度加一個(gè)允許波動(dòng)值
{//由于賽道不是直線,每5行更新一次left_sz,作為下一次搜線的起始列
kk=0;
left_sz=blackleft[ig+1]+bxiankuan[ig+1];//根據(jù)上一行的左線虛擬出下一次的起始列
}
if(right_sz<blackleft[ig]) right_sz=blackleft[ig];//越界限制
for(int mg=right_sz;mg<=DATACOUNT-1;mg++)//右線是011,且列小于右下端點(diǎn)的列坐標(biāo)或 其根本沒有下端點(diǎn)
{
if(ImageBuf2[ig][mg-1]==0&&ImageBuf2[ig][mg]==1&&ImageBuf2[ig][mg+1]==1&&(mg<=blackright[yzxqishi]||zxqishi==0)) //在范圍內(nèi)找到黑線
{
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];//根據(jù)上一行的右線虛擬出下一次的起始列
}
}
}
for(is=DATALINE-3;is>1;is--)//求出拐點(diǎn)!
{
as=(blackleft[is]-blackleft[is-2]);//與上兩行做一次差
bs=(blackleft[is]-blackleft[is+2]);//與下兩行做一次差
js=blackleft[is]; //為該行的列坐標(biāo)
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;//上面 左上拐點(diǎn)的特征:之下為遞增(或直接增),之上為遞增,之下兩行的絕對(duì)值比較小,左上拐點(diǎn)在十字起始行上面,且在一個(gè)范圍內(nèi),周圍幾個(gè)點(diǎn)的白色多一些
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;//下面 左下拐點(diǎn)的特征:之下為遞增,之上為遞減(或直接減),在十字起始行下面
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;//上面 右上拐點(diǎn)的特征:之下為遞減(或直接減),之上為遞減,。。。
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;//下面 右下拐點(diǎn)的特征:之下為遞減,之上為遞增(或直接增)
}
//有下端拐點(diǎn)的進(jìn)來。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
//下端拐點(diǎn)在十字開始行的下面,且(左線在中線以左 或 下端拐點(diǎn)處的右線在中線以右),
if((zxqishi-12)<youxiao_shizi&&((blackleft[zxqishi]<(DATACOUNT/2-10))||blackright[zxqishi]>(DATACOUNT/2+10))&&
zxqishi!=0&&(zzxqishi!=0||yzxqishi!=0)&&zxqishi<=(DATACOUNT-3)) //有拐點(diǎn)的進(jìn)來
{//且下端拐點(diǎn)的確存在,且左、右拐點(diǎn)至少存在一個(gè);限幅
if(xs!=0&&ys!=0&&ys<=(zxqishi+10)&&ys>=(zxqishi-10)&&blackleft[xs]>=blackleft[ys])//左側(cè)進(jìn)行連線
{//左側(cè)上下拐點(diǎn)都存在,且下拐點(diǎn)在下端點(diǎn)拐點(diǎn)的合理范圍之內(nèi),左上拐點(diǎn)比左下拐點(diǎn)靠右
for(int iz=xs-1;iz<=ys+1;iz++)//一次函數(shù)連線
{//為了更加平滑,各讓一步
blackleft[iz+1]=(blackleft[iz]-blackleft[ys+1])/(iz-ys-1)+blackleft[iz];//注意順序,上面拐點(diǎn)在左還是在右
zshizi=1;//正入十字標(biāo)志置1,為下面使用
}
}//同樣,不作注釋
if(es!=0&&fs!=0&&fs<=(zxqishi+10)&&fs>=(zxqishi-10)&&blackright[fs]>=blackright[es])//右側(cè)進(jìn)行連線
{
for(int iz=es-1;iz<=fs+1;iz++)
{
blackright[iz+1]=((blackright[fs+1]-blackright[iz])/(fs+1-iz))+blackright[iz];
zshizi=1;//正入十字標(biāo)志置1,為下面使用
}
}
//為了下面求中線的起始行和結(jié)束行而使用
if(xs>=es) szq=es;//僅為標(biāo)準(zhǔn)正十字服務(wù)
else szq=xs;//十字起始行以上為主
if(ys>=fs) szs=ys;
else szs=fs;//十字接收行以下為主
if(xs!=0&&ys!=0&&es!=0&&fs!=0)//標(biāo)準(zhǔn)正十字 四拐點(diǎn)都存在
{
for(i=szq-1;i<=szs+1;i++)//為了平滑,各讓一步
if(center[i]==0)//由于前面已經(jīng)補(bǔ)線了,此處只需求中值即可
center[i]=(blackright[i]+blackleft[i])/2;
}
else if(xs!=0&&ys!=0&&(es==0||fs==0))//右側(cè)丟失
{
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))//左側(cè)丟失
{
for(i=es-1;i<=fs+1;i++)
if(center[i]==0)//中線靠右線減賽道寬度而得
center[i]=(blackright[i]-bxiankuan[i]);
}
}
//近端處理 無下拐點(diǎn)的進(jìn)來。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。!
else if(youxiao_shizi>=30&&shizi_flag>=24&&(es!=0&&xs!=0)&&(es>=(xs-13)&&xs>=(es-13)))//如果剛進(jìn)入十字,則只有最上面兩個(gè)拐點(diǎn),
{ //十字比較靠近車 且兩個(gè)上拐點(diǎn)都存在,es與xs在合理的范圍內(nèi)
for(int iz=xs-1;iz<DATALINE-1;iz++)//此時(shí)補(bǔ)線利用左拐點(diǎn)與左下角坐標(biāo)值連線,右拐點(diǎn)與右下角坐標(biāo)值連線
{//一次函數(shù)連線
blackleft[iz+1]=-(blackleft[iz])/(DATALINE-1-iz)+blackleft[iz];//注意順序,上面拐點(diǎn)在左還是在右
zshizi=1;//正入十字標(biāo)志置1,為下面使用
}
for(int iz=es-1;iz<DATALINE-1;iz++)
{
blackright[iz+1]=((DATACOUNT-blackright[iz])/(49-iz))+blackright[iz];
zshizi=1;//正入十字標(biāo)志置1,為下面使用
}
if(xs>=es) szq=es;//選取靠上的拐點(diǎn),作為下面求中線的起始行
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)//給下端補(bǔ)線
center[i]=blackright[i]-(blackright[i-1]-center[i-1]+1);
else if(center[i+1]!=0)//給上端補(bǔ)線
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)//給下端補(bǔ)線
center[i]=blackleft[i]+(center[i-1]-blackleft[i-1]+1);
else if(center[i+1]!=0)//給上端補(bǔ)線
center[i]=blackleft[i]+(center[i+1]-blackleft[i+1]-1);
else
center[i]=blackleft[i]+bxiankuan[i];
}
}
}
}
//左側(cè)斜十字補(bǔ)線 各標(biāo)志位清零
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--)
{//連續(xù)兩行的左線都存在 下增上減
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;//先尋找左下拐點(diǎn)
break;
}
}
if(zuoqishi!=0)//左下拐點(diǎn)存在才能進(jìn)入
{
for(is=zuoqishi;is>2;is--)//從左下拐點(diǎn)向上尋找
{ //連續(xù)三行左端都沒找到線
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)
{//并且連續(xù)兩行左端 二值化圖像 都是白的
if(youxiaozuoxieshizi==0)//進(jìn)行遍歷,尋找起始行
youxiaozuoxieshizi=is;
} //連續(xù)兩行沒找到線,且從下到上是白到黑或左線找到了
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))//一般上側(cè)結(jié)束行都是極值,只有分辨圖像是黑是白
{
xieshizi_zuoflag=is-1;//尋找結(jié)束行
break;//找到就跳出,省時(shí)間
}
}
}
//斜十字補(bǔ)線 左側(cè) 白色區(qū)域在合理范圍內(nèi), 下拐點(diǎn)在白色下面
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;//根據(jù)預(yù)判得出虛擬中線,
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]) //在范圍內(nèi)找到黑線
{
blackleft[ig]=jg; //更新左線數(shù)組
ss++;
break;
}
}
if(ss>4)
{
ss=0;
left_xsz=blackleft[ig+1]+bxiankuan[ig+1];
}
}
xieshizi_zuoflag=0;
for(is=zuoqishi;is>5;is--)//斜十字補(bǔ)線 再判斷 由于前面更新了左線數(shù)組,此時(shí)再次確認(rèn)無誤
{
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;//得出結(jié)束行
break;
}
}
for(is=DATALINE-3;is>=0;is--)//十字補(bǔ)線,同正十字
{
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++)//只能補(bǔ)一側(cè)
{
blackleft[iz+1]=((blackleft[xieys]-blackleft[iz])/(xieys-iz))+blackleft[iz];
center[iz+1]=(bxiankuan[iz+1]+blackleft[iz+1]);
zxshizi=1;//左斜十字標(biāo)志置1
}
for(int iz=DATALINE-1;iz>=3;iz--)//把右側(cè)沒搜到線的行的中線根據(jù)左側(cè)補(bǔ)出來
{
if(blackleft[iz]>=1&&blackright[iz]>=(DATACOUNT-1))
center[iz]=blackleft[iz]+bxiankuan[iz];//
}
}
}
//右側(cè) 斜十字補(bǔ)線/////
for(int is=DATALINE-3;is>=5;is--)//斜十字補(bǔ)線 右側(cè) 預(yù)判斷
{
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;//右側(cè)的下端拐點(diǎn)
break;
}
}
for(is=youqishi;is>=5;is--)//得出白色區(qū)域
{
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)//開始記錄白點(diǎn)
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;//遇著黑點(diǎn)退出
break;
}
} //右下拐點(diǎn)靠右
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);//根據(jù)得出的虛擬中線,來確定再次搜線的起始列
for(int ig=youqishi;ig>=0;ig--)//對(duì)右線數(shù)組重新搜索
{
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]) //在范圍內(nèi)找到黑線
{
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--)//斜十字補(bǔ)線 由于更新了數(shù)組,需要再判斷
{
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;//結(jié)束行
break;
}
}
for(is=DATALINE-3;is>=0;is--)//斜十字補(bǔ)線
{
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)//斜十字畸變較大,前后多找些點(diǎn)進(jìn)行補(bǔ)
{
for(int iz=xiees;iz<(xiefs+3);iz++)//對(duì)右側(cè)補(bǔ)完線并求中心值
{
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;
}
}
}
}
/////////////對(duì)尋到的邊情況分類并處理擬合中線////////
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)//右側(cè)丟線
{
if(yici_you==0)//右側(cè)開始丟線處
yici_you=i;//記錄起始行
if(youxiaoyou==0)
{
for(int bs=i;bs>2;bs--)
{//連續(xù)三行的右線為都有值 或連續(xù)兩行是二值化值是黑的
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;//結(jié)束行
break;
}
}
}
if(youxiaozuobian==0)
{
for(int bs=i;bs>youxiaoyou-5;bs--)//判斷左線連續(xù)性,并確定不連續(xù)行
{
if((blackleft[bs]-blackleft[bs-1])>0||blackleft[bs]>=(DATACOUNT-1)||blackleft[bs-1]>=(DATACOUNT-1))
{//本來左線是遞增向右的,當(dāng)遇到左線遞減了或跑到右邊沿了就進(jìn)入,
youxiaozuobian=bs;
break;
}
else if((blackleft[bs]-blackleft[bs-1])<=0||blackleft[bs]<(DATACOUNT-1)||blackleft[bs-1]<(DATACOUNT-1))
youxiaozuobian=bs;//遞增時(shí)一直更新此值
}
}
if(i==49||i==48||(i==47))//如果靠近車,應(yīng)該是近端丟線,先判斷下
{
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)//驗(yàn)證是否確實(shí)是近端丟線 此值應(yīng)離丟線處不遠(yuǎn)
{
for(int as=youxiaoyou;as<=49;as++)//能進(jìn)來,可以確定確實(shí)近端丟線了
{
if(center[as]==0)
{
jinduan_ybx=1;//置位標(biāo)志 //根據(jù)前一行的中線求出該行的中線
center[as]=(blackleft[as-1]+blackright[as-1])/2-blackleft[as-1]+1+blackleft[as];
}
}
}
if(jinduan_ybx==1) break;//補(bǔ)線完成跳出程序
}
else break;//若為進(jìn)入急彎,則會(huì)跳出
}
}
if(jinduan_ybx==0&&yici_you>=46&&youxiaoyou<38&&(youxiaozuobian<=yici_you))//如果不是近端丟線,而是進(jìn)入急彎 不
{//建議攝像頭的鏡頭在120度以上,90度的容易進(jìn)入此處
for(int as=49;as>youxiaoyou;as--)
{
if(center[as]==0&&blackleft[as]!=0)
{
center[as]=blackleft[as]+bxiankuan[as]+1;//改變系數(shù)1的大小,可改善進(jìn)入急彎的轉(zhuǎn)向能力
}
}
}
}
else if(center[i]==0&&blackleft[i]!=0)//彎道丟線時(shí)
center[i]=center[i+1]-blackleft[i+1]+blackleft[i]+4;//改變系數(shù)4的大小,可改善進(jìn)入急彎的轉(zhuǎn)向能力
}
else if(blackright[i]<(DATACOUNT-1)&&blackleft[i]==0&¢er[i]==0)//左側(cè)丟線
{
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--)//判斷右線連續(xù)性,并確定不連續(xù)行
{
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;
}
}
//重新遍歷最近端的點(diǎn) 判斷是否進(jìn)入急彎,即左側(cè)或右側(cè)一大塊沒尋到線的地方
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)//驗(yàn)證是否確實(shí)是近端丟線
{
for(int as=youxiaozuo;as<=49;as++)
{
if(center[as]==0)
{
jinduan_zbx=1;//置位標(biāo)志
center[as]=blackright[as]-(blackright[as-1]-(blackright[as-1]+blackleft[as-1]+1)/2+1);
}
}
}
if(jinduan_zbx==1) break;//補(bǔ)線完成跳出程序
}
else
break;//若為進(jìn)入急彎,則會(huì)跳出
}
}
if(i>47&&jinduan_zbx==0&&yici_zuo>=48&&youxiaozuo<40&&(youxiaoyoubian<=yici_zuo))//如果不是近端丟線,而是進(jìn)入急彎
{
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)//進(jìn)入彎道
{
center[i]=blackright[i]-(blackright[i+1]-center[i+1]+3);//改變系數(shù)3的大小,可改善進(jìn)入急彎的轉(zhuǎn)向能力
}
}
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;//中心壞行標(biāo)號(hào)
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;
}
}
}
//作用:計(jì)算有效行 根據(jù)上面黑線的中心偏差來求解有效行
//改變?nèi)肿兞浚?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; //右彎左側(cè)連續(xù)
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;//并且右邊有極點(diǎn)
youwan_flag=1;
}
}
else if(blackright[xk]==DATACOUNT&&blackright[xk+1]==DATACOUNT&&blackright[xk-1]!=DATACOUNT&&youwan_flag==0)
{
youwan_youxiao=xk;//并且右邊有極點(diǎn)
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; //左彎右側(cè)連續(xù)
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;//并且左邊有極點(diǎn)
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;//并且左邊有極點(diǎn)
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;//虛擬起始點(diǎn),判斷是否有噪點(diǎn)影響了有效行的讀取
valuerownum=valuerownum-13;
panduan_youxiao();//克服平滑濾波帶來的影響,尋找真正有效點(diǎn)
if(wandao_youxiao==1)//如果是彎道
valuerownum=46; //這樣,數(shù)據(jù)就不會(huì)丟棄了,就會(huì)進(jìn)入下一個(gè)if語句里
else
badframe=1;//不是彎道,舍棄數(shù)據(jù)
}
if(!badframe)//如果數(shù)據(jù)有效
{
CenterEx[1]=CenterEq;
sum=0;ii=0;
if(valuerownum>=35)//最近處,一般是急彎道
{
wanqishi=valuerownum+5;//虛擬起始點(diǎn),判斷是否有噪點(diǎn)影響了有效行的讀取 下同,不做進(jìn)一步注釋
if(wanqishi>46) wanqishi=46;
valuerownum=valuerownum-10;
panduan_youxiao();//克服平滑濾波帶來的影響,尋找真正有效點(diǎn)
if(wandao_youxiao==1)
valuerownum=value;//有效的話把實(shí)際的有效行求出
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)//有效行靠前,離車較遠(yuǎn)了
{
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)//有效行離車更遠(yuǎn)了,說明是直道或小s
{
zhidao=1;
wandao=0;
}
for(int i=47;i>(valuerownum+1);i--)//五點(diǎn)平滑濾波,使中線更平滑
center[i]=(center[i+2]+center[i+1]+center[i]+center[i-1]+center[i-2])/5;
for(jj=valuerownum;jj<DATALINE;jj++)//濾波后進(jìn)行加權(quán)平均,
{
sum+=(center[jj]-TurnMidPosition)*CorrectEx[jj];
ii++;
}
CenterEq=(sum/ii); //得到平均值
}
else//無效時(shí)保持原來的數(shù)據(jù)
{
CenterEq=lasterror;
lasterror=CenterEq;
badframe=0;
}
if(CenterEq>70)//對(duì)加權(quán)平均進(jìn)行限幅,也可不限,數(shù)值根據(jù)自己的小車定,
{ //一般達(dá)不到限幅值,為了防止突發(fā)情況
CenterEq=70;
}
else if(CenterEq<-70)
{
CenterEq=-70;
}
LastTurnPWMOUT=TurnPWMOUT;//新的給舊的
TurnPWMOUT=(-TurnP*CenterEq-TurnD*lasterror) ; //得出轉(zhuǎn)向PWM,但此時(shí)還未加舵機(jī)中值
lasterror=(CenterEq-CenterEx[1]);
}
/***********************************************************
函數(shù)名稱:TurnPWMOut
函數(shù)功能:
入口參數(shù):NewspeedPWM 當(dāng)前的電機(jī)輸出PWM
LastspeedPWM 上次電機(jī)輸出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()//發(fā)送到串口調(diào)試助手
{
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;
}
……………………
…………限于本文篇幅 余下代碼請(qǐng)從51黑下載附件…………
所有資料51hei提供下載:
國賽攝像頭程序.rar
(12.99 MB)
(下載次數(shù): 133, 2018-3-4 12:57 上傳)
下載積分: 黑幣 -5
作者:
dwwd
時(shí)間:
2020-3-6 14:40
你好,我下載了你的程序,但是沒有發(fā)現(xiàn)程序打開的地方啊,是keil還是什么軟件
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1