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

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

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

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

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

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

a087144010ff45f29c28da38181b05da.jpeg

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

/**********************************************
 * @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 

 

物联沃分享整理
物联沃-IOTWORD物联网 » 全国大学生智能汽车大赛(一):用摄像头识别赛道

发表评论