代码从逐飞科技的开源库开始。
想要站在巨人的肩膀上,首先要爬上巨人。在抄别人的代码时,我将会经常发现一些不尽如人意的地方,但是为了使代码顺利运行,我将标记出这些问题而不改善。
在主循环中首先判断摄像头数据是否采集完成,然后使用大津法求阈值,根据阈值对原图像数组进行二值化。
大津法(OTSU)是一种确定图像二值化分割阈值的算法,由日本学者大津于 1979 年提出。从大津法的原理上来讲,该方法又称作最大类间方差法,因为按照大津法求得的阈值进行图像二值化分割后,前景与背景图像的类间方差最大。
void imageBinary(void) { uint16 grayCount[256]={0}; uint32 graySum=0; uint16 pixelSum=0; float graypro[256]; uint8 threshold; uint16 i,j; uint16 step=2;//间隔 for(i=0;i<MT9V032_H;i+=step){ for(j=0;j<MT9V032_W;j+=step){ grayCount[image[i][j]]++; graySum+=image[i][j]; pixelSum++; } } for(i=0;i<256;i++){ graypro[i]=(float)grayCount[i]/pixelSum; } float w0,w1,u0Temp,u1Temp,u0,u1,u,deltaTemp,deltaMax; deltaMax=0; for(i=0;i<256;i++){ w0=w1=u0Temp=u1Temp=u0=u1=u=deltaTemp=0; for(j=0;j<256;j++){ if(j<=i){ w0+=graypro[j]; u0Temp+=j*graypro[j]; } else{ w1+=graypro[j]; u1Temp+=j*graypro[j]; } } u0=u0Temp/w0; u1=u1Temp/w1; u=u0Temp+u1Temp; deltaTemp=w0*(u0-u)*(u0-u)+w1*(u1-u)*(u1-u); if(deltaTemp>deltaMax){ deltaMax=deltaTemp; threshold=i; } } for(i=0;i<MT9V032_H;i++){ for(j=0;j<MT9V032_W;j++){ binaryImage[i][j]=(image[i][j]>threshold)?255:0; } } if(threshold<160){//出界停车 DisableInterrupts; ctimer_pwm_duty(TIMER1_PWMCH0_A18,0); ctimer_pwm_duty(TIMER2_PWMCH1_B4,0); } }
若求得阈值小于某个临界值,则说明摄像头已经几乎看不到白色的赛道了,接下来要停止所有中断并将电机输出 PWM 波的占空比置零将车停下。