全国大学生智能汽车大赛(一):摄像头识别赛道代码
全国大学生智能汽车大赛(二):摄像头识别赛道代码
全国大学生智能汽车大赛(三):上下位机通信协议及代码
这些代码是我在大二时参加智能车竞赛时编写的程序,仅供参考。
代码内容涉及二值化、大津法(相关内容可以参考我的另一篇博文)等。
智能汽车基于先进的自动化控制技术以传感器信号检测处理为指引,驱动电机实现特定轨迹的高速稳定行驶。目前智能汽车技术在交通运输、智能驾驶等方面有着广阔的应用前景与发展空间。智能车的方案设计基本相似,整体的稳定性和高速行驶对控制系统的设计要求很高,尤其是面对复杂路况时赛道的识别、转向控制和车速控制是系统设计的难点。
/**********************************************
* @file 摄像头
* @Target core TC264D
* @date 2021-5-19
* @note
**********************************************/
#include "headfile.h"
double deviation1; //摄像头获得的偏差
/************************************
* 函数名称:otsu(uint16 column, uint16 row)
* 功能说明:求阈值大小
* 参数说明:
* 函数返回:阈值大小
* 修改时间:2021/5/12 Wed
************************************/
uint16 otsu(uint16 column, uint16 row)
{
uint16 i,j;
uint32 Amount = 0;
uint32 PixelBack = 0;
uint32 PixelIntegralBack = 0;
uint32 PixelIntegral = 0;
int32 PixelIntegralFore = 0;
int32 PixelFore = 0;
float OmegaBack, OmegaFore, MicroBack, MicroFore, SigmaB, Sigma; //类间方差;
uint16 MinValue, MaxValue;
uint16 Threshold = 0;
uint8 HistoGram[256];
for (j = 0; j < 256; j++) HistoGram[j] = 0; //初始化灰度直方图
for (j = 0; j < row; j++)
{
for (i = 0; i < column; i++)
{
HistoGram[mt9v03x_image[j][i]]++; //统计灰度级中每个像素在整幅图像中的个数
}
}
for (MinValue = 0; MinValue < 256 && HistoGram[MinValue] == 0; MinValue++) ; //获取最小灰度的值
for (MaxValue = 255; MaxValue > MinValue && HistoGram[MinValue] == 0; MaxValue--) ; //获取最大灰度的值
for (j = MinValue; j <= MaxValue; j++) Amount += HistoGram[j]; //像素总数
PixelIntegral = 0;
for (j = MinValue; j <= MaxValue; j++)
{
PixelIntegral += HistoGram[j] * j; //灰度值总数
}
SigmaB = -1;
for (j = MinValue; j < MaxValue; j++)
{
PixelBack = PixelBack + HistoGram[j]; //前景像素点数
PixelFore = Amount - PixelBack; //背景像素点数
OmegaBack = (float)PixelBack / Amount; //前景像素百分比
OmegaFore = (float)PixelFore / Amount; //背景像素百分比
PixelIntegralBack += HistoGram[j] * j; //前景灰度值
PixelIntegralFore = PixelIntegral - PixelIntegralBack; //背景灰度值
MicroBack = (float)PixelIntegralBack / PixelBack; //前景灰度百分比
MicroFore = (float)PixelIntegralFore / PixelFore; //背景灰度百分比
Sigma = OmegaBack * OmegaFore * (MicroBack - MicroFore) * (MicroBack - MicroFore); //计算类间方差
if (Sigma > SigmaB) //找出最大类间方差以及对应的阈值
{
SigmaB = Sigma;
Threshold = j;
}
}
return Threshold; //返回最佳阈值;
}
/************************************
* @brief 二值化
* @param mode : 0:大津法阈值 1:平均阈值
* @return
* @note Get_01_Value(0); //使用大津法二值化
* @date 2021/5/12 WED
************************************/
uint8 Pixle[MT9V03X_H][MT9V03X_W]; //存放二值化后图像
void binaryzation(uint8 mode)
{
int i = 0,j = 0;
uint32 Threshold;
uint32 tv=0;
if(mode)
{
//累加
for(i = 0; i <MT9V03X_H; i++)
{
for(j = 0; j <MT9V03X_W; j++)
{
tv+=mt9v03x_image[i][j]; //累加
}
}
Threshold=tv/MT9V03X_H/MT9V03X_W; //求平均值,光线越暗越小,全黑约35,对着屏幕约160,一般情况下大约100
Threshold=Threshold*7/10+10; //此处阈值设置,根据环境的光线来设定
}
else
{
Threshold = otsu(MT9V03X_W,MT9V03X_H); //大津法阈值
// Threshold = (uint8_t)(Threshold * 0.5) + 70;
}
for(i = 0; i < MT9V03X_H; i++)
{
for(j = 0; j < MT9V03X_W; j++)
{
if(mt9v03x_image[i][j] >Threshold) //数值越大,显示的内容越多,较浅的图像也能显示出来
Pixle[i][j] =0xff;
else
Pixle[i][j] =0x00;
}
}
}
/************************************
* @brief 过滤噪点
* @param
* @return
* @note
* @date 2021/5/13 Thur
************************************/
void Pixle_Filter(void)
{
int nr; //行
int nc; //列
for(nr=1; nr<MT9V03X_H-1; nr++)
{
for(nc=1; nc<MT9V03X_W-1; nc=nc+1)
{
if((Pixle[nr][nc]==0xff)&&(((Pixle[nr-1][nc]==0xff)&&(Pixle[nr+1][nc]==0xff))||((Pixle[nr][nc+1]==0xff)&&(Pixle[nr][nc-1]==0xff))))
{
Pixle[nr][nc]=0xff;
}
else if((Pixle[nr][nc]==0x00)&&(((Pixle[nr-1][nc]==0x00)&&(Pixle[nr+1][nc]==0x00))||((Pixle[nr][nc+1]==0x00)&&(Pixle[nr][nc-1]==0x00))))
{
Pixle[nr][nc]=0x00;
}
}
}
}
/************************************
* @brief 摄像头获取偏差
* @param start_row开始列,end_row终止列,step检测步值
* @return camera_deviation偏差
* @note
* @date 2021/5/15 Sat
************************************/
typedef struct //定义一个结构体,用于放置所用点的所在列数以及标志符
{
int16 column;
int16 flag;
}usefulpoint;
usefulpoint jump_left[use_h_max], jump_right[use_h_max], midpoint[use_h_max];//定义每一行左,右跳变点,赛道中点
double camera_deviation(int16 start_row, int16 end_row, int16 step)
{
int16 column, row, num_left = 0, num_right = 0,num_mid = 0; //定义检测偏差中所需的中间变量及标志
double deviation = 0;
//参数初始化
for(row = 0; row>= end_row; row++)
{
jump_left[row].flag = 0;
jump_right[row].flag = 0;
midpoint[row].flag = 0;
}
//跳变点检测
for (row = start_row; row < end_row; row=row+step)
{
//左侧跳变点检测
for (column = 0; column < MT9V03X_W; column++)
{
if ( (Pixle[row-1][column]==0xff) && (Pixle[row][column]==0xff) && (Pixle[row+1][column]==0x00) && (Pixle[row+2][column]==0x00))
{
jump_left[row].column = column; //记录左侧跳变点列数
jump_left[row].flag = 1; //标记为左侧跳变点
num_left++; //左侧跳变点个数增加1
break; //找到左侧跳变点,跳出循环
}
}
//右侧跳变点检测
for (column = MT9V03X_W; column > 0; column++)
{
if ( (Pixle[row-2][column]==0x00) && (Pixle[row-1][column]==0x00) && (Pixle[row][column]==0xff) && (Pixle[row+1][column]==0xff))
{
jump_right[row].column = column; //记录右侧跳变点列数
jump_right[row].flag = 1; //标记为右侧跳变点
num_right++; //右侧跳变点个数增加1
break; //找到右侧跳变点,跳出循环
}
}
}
if(num_left<=4) return -10; //采集到的图像中只有右侧赛道边缘
if(num_right<=4) return 10; //采集到的图像中只有左侧赛道边缘
//计算赛道中点
for (row = start_row; row < end_row; row=row+step)
{
if((jump_left[row].flag)&&(jump_right[row].flag))
{
midpoint[row].column = (jump_left[row].column+jump_right[row].column)/2; //计算赛道中点所在列
if(midpoint[row].column <= MT9V03X_W) midpoint[row].flag = 1; //标记为赛道中点
num_mid++; //赛道中点个数增加1
}
}
//计算偏差1.0
for (row = start_row; row < end_row; row=row+step)
{
if(midpoint[row].flag) deviation = deviation + midpoint[row].column - MT9V03X_W/2;
}
deviation=deviation/num_mid;
return deviation;
}
二、 推荐IO分配
摄像头:8个数据口,一个串口,两eru中断
数据口:00_0 00_1 00_2 00_3 00_4 00_5 00_6 00_7
配置串口:摄像头RX:02_2 摄像头TX:02_3
VSY:02_0
HREF:程序不需要,所以不接
PCLK:02_1
四路运放 A0 A1 A2 A3 等
四个编码器:
LSB:33_7 DIR:33_6
LSB:02_8 DIR:00_9
LSB:10_3 DIR:10_1
LSB:20_3 DIR:20_0
8路pwm:
21_2 21_3 21_4 21_5 02_4 02_5 02_6 02_7
ICM20602:
CLK: P20_11
MOSI: P20_14
MISO: P20_12
CS: P20_13
SPI0
TFT屏幕:
CLK 15_3
MOSI 15_5
MISO 15_4 //实际上TFT没有这个引脚 这里仅仅占位而已
CS0 15_2
BL 15_4 //复用控制背光
REST 15_1
DC 15_0
SPI2
舵机:
P33_9
尽量不要使用以下引脚,以下引脚属于boot引脚,不合理的使用容易导致单片机无法启动等问题,因此建议大家尽量不要使用:
P14_2
P14_3
P14_4
P14_5
P14_6
P10_5
P10_6