全国大学生智能汽车大赛一摄像头识别赛道代码全国大学生智能汽车大赛二摄像头识别赛道代码全国大学生智能汽车大赛三上下位机通信协议及代码这些代码是我在大二时参加智能车竞赛时编写的程序仅供参考。代码内容涉及二值化、大津法相关内容可以参考我的另一篇博文等。智能汽车基于先进的自动化控制技术以传感器信号检测处理为指引驱动电机实现特定轨迹的高速稳定行驶。目前智能汽车技术在交通运输、智能驾驶等方面有着广阔的应用前景与发展空间。智能车的方案设计基本相似整体的稳定性和高速行驶对控制系统的设计要求很高尤其是面对复杂路况时赛道的识别、转向控制和车速控制是系统设计的难点。/********************************************** * 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 tv0; if(mode) { //累加 for(i 0; i MT9V03X_H; i) { for(j 0; j MT9V03X_W; j) { tvmt9v03x_image[i][j]; //累加 } } Thresholdtv/MT9V03X_H/MT9V03X_W; //求平均值,光线越暗越小全黑约35对着屏幕约160一般情况下大约100 ThresholdThreshold*7/1010; //此处阈值设置根据环境的光线来设定 } 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(nr1; nrMT9V03X_H-1; nr) { for(nc1; ncMT9V03X_W-1; ncnc1) { if((Pixle[nr][nc]0xff)(((Pixle[nr-1][nc]0xff)(Pixle[nr1][nc]0xff))||((Pixle[nr][nc1]0xff)(Pixle[nr][nc-1]0xff)))) { Pixle[nr][nc]0xff; } else if((Pixle[nr][nc]0x00)(((Pixle[nr-1][nc]0x00)(Pixle[nr1][nc]0x00))||((Pixle[nr][nc1]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; rowrowstep) { //左侧跳变点检测 for (column 0; column MT9V03X_W; column) { if ( (Pixle[row-1][column]0xff) (Pixle[row][column]0xff) (Pixle[row1][column]0x00) (Pixle[row2][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[row1][column]0xff)) { jump_right[row].column column; //记录右侧跳变点列数 jump_right[row].flag 1; //标记为右侧跳变点 num_right; //右侧跳变点个数增加1 break; //找到右侧跳变点跳出循环 } } } if(num_left4) return -10; //采集到的图像中只有右侧赛道边缘 if(num_right4) return 10; //采集到的图像中只有左侧赛道边缘 //计算赛道中点 for (row start_row; row end_row; rowrowstep) { if((jump_left[row].flag)(jump_right[row].flag)) { midpoint[row].column (jump_left[row].columnjump_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; rowrowstep) { if(midpoint[row].flag) deviation deviation midpoint[row].column - MT9V03X_W/2; } deviationdeviation/num_mid; return deviation; }二、 推荐IO分配摄像头8个数据口一个串口两eru中断数据口00_0 00_1 00_2 00_3 00_4 00_5 00_6 00_7配置串口摄像头RX02_2 摄像头TX02_3VSY02_0HREF程序不需要所以不接PCLK02_1四路运放 A0 A1 A2 A3 等四个编码器LSB33_7 DIR33_6LSB02_8 DIR00_9LSB10_3 DIR10_1LSB20_3 DIR20_08路pwm21_2 21_3 21_4 21_5 02_4 02_5 02_6 02_7ICM20602CLK P20_11MOSI P20_14MISO P20_12CS P20_13SPI0TFT屏幕CLK 15_3MOSI 15_5MISO 15_4 //实际上TFT没有这个引脚 这里仅仅占位而已CS0 15_2BL 15_4 //复用控制背光REST 15_1DC 15_0SPI2舵机P33_9尽量不要使用以下引脚以下引脚属于boot引脚不合理的使用容易导致单片机无法启动等问题因此建议大家尽量不要使用P14_2P14_3P14_4P14_5P14_6P10_5P10_6