• 全国大学生智能汽车大赛(一):摄像头识别赛道代码


    全国大学生智能汽车大赛(一):摄像头识别赛道代码

    全国大学生智能汽车大赛(二):摄像头识别赛道代码

    全国大学生智能汽车大赛(三):上下位机通信协议及代码

            这些代码是我在大二时参加智能车竞赛时编写的程序,仅供参考。

            代码内容涉及二值化大津法(相关内容可以参考我的另一篇博文)等。

    a087144010ff45f29c28da38181b05da.jpeg

            智能汽车基于先进的自动化控制技术以传感器信号检测处理为指引,驱动电机实现特定轨迹的高速稳定行驶。目前智能汽车技术在交通运输、智能驾驶等方面有着广阔的应用前景与发展空间。智能车的方案设计基本相似,整体的稳定性和高速行驶对控制系统的设计要求很高,尤其是面对复杂路况时赛道的识别、转向控制和车速控制是系统设计的难点。

    1. /**********************************************
    2. * @file 摄像头
    3. * @Target core TC264D
    4. * @date 2021-5-19
    5. * @note
    6. **********************************************/
    7. #include "headfile.h"
    8. double deviation1; //摄像头获得的偏差
    9. /************************************
    10. * 函数名称:otsu(uint16 column, uint16 row)
    11. * 功能说明:求阈值大小
    12. * 参数说明:
    13. * 函数返回:阈值大小
    14. * 修改时间:2021/5/12 Wed
    15. ************************************/
    16. uint16 otsu(uint16 column, uint16 row)
    17. {
    18. uint16 i,j;
    19. uint32 Amount = 0;
    20. uint32 PixelBack = 0;
    21. uint32 PixelIntegralBack = 0;
    22. uint32 PixelIntegral = 0;
    23. int32 PixelIntegralFore = 0;
    24. int32 PixelFore = 0;
    25. float OmegaBack, OmegaFore, MicroBack, MicroFore, SigmaB, Sigma; //类间方差;
    26. uint16 MinValue, MaxValue;
    27. uint16 Threshold = 0;
    28. uint8 HistoGram[256];
    29. for (j = 0; j < 256; j++) HistoGram[j] = 0; //初始化灰度直方图
    30. for (j = 0; j < row; j++)
    31. {
    32. for (i = 0; i < column; i++)
    33. {
    34. HistoGram[mt9v03x_image[j][i]]++; //统计灰度级中每个像素在整幅图像中的个数
    35. }
    36. }
    37. for (MinValue = 0; MinValue < 256 && HistoGram[MinValue] == 0; MinValue++) ; //获取最小灰度的值
    38. for (MaxValue = 255; MaxValue > MinValue && HistoGram[MinValue] == 0; MaxValue--) ; //获取最大灰度的值
    39. for (j = MinValue; j <= MaxValue; j++) Amount += HistoGram[j]; //像素总数
    40. PixelIntegral = 0;
    41. for (j = MinValue; j <= MaxValue; j++)
    42. {
    43. PixelIntegral += HistoGram[j] * j; //灰度值总数
    44. }
    45. SigmaB = -1;
    46. for (j = MinValue; j < MaxValue; j++)
    47. {
    48. PixelBack = PixelBack + HistoGram[j]; //前景像素点数
    49. PixelFore = Amount - PixelBack; //背景像素点数
    50. OmegaBack = (float)PixelBack / Amount; //前景像素百分比
    51. OmegaFore = (float)PixelFore / Amount; //背景像素百分比
    52. PixelIntegralBack += HistoGram[j] * j; //前景灰度值
    53. PixelIntegralFore = PixelIntegral - PixelIntegralBack; //背景灰度值
    54. MicroBack = (float)PixelIntegralBack / PixelBack; //前景灰度百分比
    55. MicroFore = (float)PixelIntegralFore / PixelFore; //背景灰度百分比
    56. Sigma = OmegaBack * OmegaFore * (MicroBack - MicroFore) * (MicroBack - MicroFore); //计算类间方差
    57. if (Sigma > SigmaB) //找出最大类间方差以及对应的阈值
    58. {
    59. SigmaB = Sigma;
    60. Threshold = j;
    61. }
    62. }
    63. return Threshold; //返回最佳阈值;
    64. }
    65. /************************************
    66. * @brief 二值化
    67. * @param mode : 0:大津法阈值 1:平均阈值
    68. * @return
    69. * @note Get_01_Value(0); //使用大津法二值化
    70. * @date 2021/5/12 WED
    71. ************************************/
    72. uint8 Pixle[MT9V03X_H][MT9V03X_W]; //存放二值化后图像
    73. void binaryzation(uint8 mode)
    74. {
    75. int i = 0,j = 0;
    76. uint32 Threshold;
    77. uint32 tv=0;
    78. if(mode)
    79. {
    80. //累加
    81. for(i = 0; i
    82. {
    83. for(j = 0; j
    84. {
    85. tv+=mt9v03x_image[i][j]; //累加
    86. }
    87. }
    88. Threshold=tv/MT9V03X_H/MT9V03X_W; //求平均值,光线越暗越小,全黑约35,对着屏幕约160,一般情况下大约100
    89. Threshold=Threshold*7/10+10; //此处阈值设置,根据环境的光线来设定
    90. }
    91. else
    92. {
    93. Threshold = otsu(MT9V03X_W,MT9V03X_H); //大津法阈值
    94. // Threshold = (uint8_t)(Threshold * 0.5) + 70;
    95. }
    96. for(i = 0; i < MT9V03X_H; i++)
    97. {
    98. for(j = 0; j < MT9V03X_W; j++)
    99. {
    100. if(mt9v03x_image[i][j] >Threshold) //数值越大,显示的内容越多,较浅的图像也能显示出来
    101. Pixle[i][j] =0xff;
    102. else
    103. Pixle[i][j] =0x00;
    104. }
    105. }
    106. }
    107. /************************************
    108. * @brief 过滤噪点
    109. * @param
    110. * @return
    111. * @note
    112. * @date 2021/5/13 Thur
    113. ************************************/
    114. void Pixle_Filter(void)
    115. {
    116. int nr; //行
    117. int nc; //列
    118. for(nr=1; nr-1; nr++)
    119. {
    120. for(nc=1; nc-1; nc=nc+1)
    121. {
    122. 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))))
    123. {
    124. Pixle[nr][nc]=0xff;
    125. }
    126. 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))))
    127. {
    128. Pixle[nr][nc]=0x00;
    129. }
    130. }
    131. }
    132. }
    133. /************************************
    134. * @brief 摄像头获取偏差
    135. * @param start_row开始列,end_row终止列,step检测步值
    136. * @return camera_deviation偏差
    137. * @note
    138. * @date 2021/5/15 Sat
    139. ************************************/
    140. typedef struct //定义一个结构体,用于放置所用点的所在列数以及标志符
    141. {
    142. int16 column;
    143. int16 flag;
    144. }usefulpoint;
    145. usefulpoint jump_left[use_h_max], jump_right[use_h_max], midpoint[use_h_max];//定义每一行左,右跳变点,赛道中点
    146. double camera_deviation(int16 start_row, int16 end_row, int16 step)
    147. {
    148. int16 column, row, num_left = 0, num_right = 0,num_mid = 0; //定义检测偏差中所需的中间变量及标志
    149. double deviation = 0;
    150. //参数初始化
    151. for(row = 0; row>= end_row; row++)
    152. {
    153. jump_left[row].flag = 0;
    154. jump_right[row].flag = 0;
    155. midpoint[row].flag = 0;
    156. }
    157. //跳变点检测
    158. for (row = start_row; row < end_row; row=row+step)
    159. {
    160. //左侧跳变点检测
    161. for (column = 0; column < MT9V03X_W; column++)
    162. {
    163. if ( (Pixle[row-1][column]==0xff) && (Pixle[row][column]==0xff) && (Pixle[row+1][column]==0x00) && (Pixle[row+2][column]==0x00))
    164. {
    165. jump_left[row].column = column; //记录左侧跳变点列数
    166. jump_left[row].flag = 1; //标记为左侧跳变点
    167. num_left++; //左侧跳变点个数增加1
    168. break; //找到左侧跳变点,跳出循环
    169. }
    170. }
    171. //右侧跳变点检测
    172. for (column = MT9V03X_W; column > 0; column++)
    173. {
    174. if ( (Pixle[row-2][column]==0x00) && (Pixle[row-1][column]==0x00) && (Pixle[row][column]==0xff) && (Pixle[row+1][column]==0xff))
    175. {
    176. jump_right[row].column = column; //记录右侧跳变点列数
    177. jump_right[row].flag = 1; //标记为右侧跳变点
    178. num_right++; //右侧跳变点个数增加1
    179. break; //找到右侧跳变点,跳出循环
    180. }
    181. }
    182. }
    183. if(num_left<=4) return -10; //采集到的图像中只有右侧赛道边缘
    184. if(num_right<=4) return 10; //采集到的图像中只有左侧赛道边缘
    185. //计算赛道中点
    186. for (row = start_row; row < end_row; row=row+step)
    187. {
    188. if((jump_left[row].flag)&&(jump_right[row].flag))
    189. {
    190. midpoint[row].column = (jump_left[row].column+jump_right[row].column)/2; //计算赛道中点所在列
    191. if(midpoint[row].column <= MT9V03X_W) midpoint[row].flag = 1; //标记为赛道中点
    192. num_mid++; //赛道中点个数增加1
    193. }
    194. }
    195. //计算偏差1.0
    196. for (row = start_row; row < end_row; row=row+step)
    197. {
    198. if(midpoint[row].flag) deviation = deviation + midpoint[row].column - MT9V03X_W/2;
    199. }
    200. deviation=deviation/num_mid;
    201. return deviation;
    202. }

    二、 推荐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 

     

  • 相关阅读:
    Unity减少发布打包文件的体积(二)——设置WebGL发布时每张图片的压缩方式
    通俗解释魔法命令
    python 数据保存为npy和npz格式并读取
    ROS学习笔记一(安装、节点、发布者和订阅者)
    【运筹优化】求解二维矩形装箱问题的算法合辑(Java代码实现)
    VM虚拟机三种网络配置详解(桥接、NAT、仅主机)
    自动驾驶:Tesla AI DAY 2022
    Go,从命名开始!Go的关键字和标识符全列表手册和代码示例!
    记一次基于开源微信机器人实现的Unity构建完成通知
    Flutter高仿微信-第52篇-群聊-清空聊天记录
  • 原文地址:https://blog.csdn.net/m0_53966219/article/details/126711218