飞思卡尔摄像头算法
1.接脚说明以及与程序的关系
- 左边八个引脚与单片机IO口相连,在某一个时刻,并行向单片机发送八个数据 数值为(0-255)代表某一个点的灰度值
- VS脚 HR脚和CLK脚 其中在摄像头向单片机要发送一张图像时 VS会给一个高脉冲 来表示第一个信号的开始 HR表示行信号 在一张图像的信息传递过程中 会有60个高脉冲来表示60个行(不需要接线) 而CLK表示点信号在每两个HR脉冲之间会有80个高脉冲来表示80个点。这样的话总共有60x80共4800个点 可以通过中断读取VS和CLK来依次获取每个点。
-
DMA模块+外部中断结合,自动读取摄像头数据
unsigned char image[4800];//图像数组
2.双峰法二值化
-
这个算法是通过统计4800个点中不同灰度的数量 获取在第一高峰和第二高峰的峰谷灰度来作为阈值进行二值化
如图上的120就是通过该算法获取的阈值
- 统计直方图
int i;
unsigned char YUZHI;//阈值
unsigned int huidu[256] = {0};//灰度直方图数组for(i=0;i<256;i++)
{huidu[image[i]]++;//统计灰度直方图
}
- 寻找第一和第二高峰以及阈值
/*第一高峰*/
unsigned int H1 = 0;//第一高峰海拔值
unsigned char D1; //第一高峰位置for(i=0;i<255;i++)
{if(huidu[i]>H1){H1 = huidu[i];//记录海拔D1 = i; //记录位置}
}
/*第二高峰*/
unsigned int H2 = 0;//第二高峰海拔值
unsigned char D2; //第二高峰位置for(i=0;i<255;i++)
{if(i==D1) continue;//跳过第一高峰if(huidu[i]==H1) continue;//排除第一高峰有相同的可能性(是平的)if(huidu[i]>H1){H2 = huidu[i];//记录海拔D2 = i; //记录位置}
}
/*找山谷*/
unsigned int H3 = 4800;//山谷海拔值
unsigned char D3; //山谷位置if(D1<D2)
{for(i=D1;i<D2;i++){if(huidu[i]<H3){H3 = huidu[i];//记录海拔D3 = i; //记录位置}}
}
else
{for(i=D2;i<D1;i++){if(huidu[i]<H3){H3 = huidu[i];//记录海拔D3 = i; //记录位置}}
}
YUZHI = D3;
- 图像二值化
unsigned char image1[60][80];//二维图像临时处理数组1
unsigned char image2[60][80];//二维图像临时处理数组2for(i=0;i<4800;i++)
{image1[i/80][i%80] = image[i]>YUZHI?1:0;//1表示黑色 0表示白色
}
3.找中线
- 主要算法思路是每一行中分别从中间向左向右找上升沿 然后将左右的值相加除于2所得的到的值 作为该行的中线
- 程序找中线
unsigned char ZHONGJIAN[60] = {39};//中线位置
unsigned char ZUO;
unsigned char YOU;for(i=59;i>=0;i--)
{for(j=39;j>0;j++)//从中间向左找{if(image1[i][j-1]-image1[i][j]==1)//找到上升沿ZUO = j;}for(j=39;j<79;j++)//从中间向右找{if(image1[i][j+1]-image1[i][j]==1)//找到上升沿YOU = j;}ZHONGJIAN[i] = (ZUO + YOU) / 2;
}
4.求车身偏差
- 前瞻偏差:由于在求车身的偏差时没必要比较太远的值 只需要根据真实情况设计一个前瞻 通过选取不同倍前瞻的三个点作为参考来得到车身的偏差
可以分析这三个点的坐标 来找到由这三点构成的园的曲率(具体实现方式为连接近中和远中两条线段 可以分别获得该两条线段两条垂直平分线 则焦点即是圆心 就由圆心坐标和其中一点坐标得到园的半径即可得到曲率)程序较为复杂 下面可作为一个参考程序
- 由于理想情况下 车本身应该沿着中线走 所以可以根据此来推出车本身的横向偏差 例如当车在现实中间线左侧 从摄像头图像算出的中间线应该相对于真正的中间线右偏,车在右侧同理左偏。
unsigned char QIANZHAN = 15;//摄像头前瞻
unsigned char YUAN,ZHONG,JIN;char ERR_QIAN;//前瞻偏差
char ERR_CHE;//车横向偏差JIN = ZHONGJIN[59];
ZHONG = ZHONGJIN[59-QIANZHAN];
YUAN = ZHONGJIN[59-QIANZHAN*2];
if((YUAN<ZHONG&&ZHONG>=JIN)||(YUAN>=ZHONG&&ZHONG<JIN))
{ERR_QIAN = JIN - ZHONG;
}
else
{ERR_QIAN = ((ZHONG - YUAN) + (JIN - ZHONG)) / 2;
}ERR_CHE = JIN - 39;//获取车身横向偏差
5.方向PD控制
#define DUOJI_ZHONGZHI 2250 //前轮舵机正方向占空比
float KP_QIAN = 1.0;//方向前瞻控制比例系数
float KD_QIAN = 1.0;//方向前瞻控制微分系数
float KP_CHE = 1.0;//方向横向控制比例系数
float GYRO_Z;//车身Z轴角加速度
unsigned int DUOJI_PWM;GYRO_Z = GET_GYRO(Z);//获取Z轴角加速度 函数未定义
DUOJI_PWM = DUOJI_ZHONGZHI + KP_QIAN * ERR_QIAN + KD_QIAN * GYRO_Z + KP_CHE * ERR_CHE;//参数计算
PWM_OUT(DUOJI_PWM);
原视频连接