摄像头赛道处理

1. 得到缩小后的灰度图像

  • 1.1 函数内容:
/*************************************************************************
 *  函数名称:Get_Use_Image
 *  功能说明:把摄像头采集到原始图像,缩放到赛道识别所需大小
 *  参数说明:无
 *  函数返回:无
 *  修改时间:2021年01月08日
 *  备    注:  由于直接设置摄像头分辨率得到的图片是由188*120裁剪而来的,故进行缩小处理
 *       				实际所需大小为94*60
 *							image_col为实际图像的宽度,列,大小为94
 *							image_row为实际图像的高度,行,大小为60
 *************************************************************************/
void Get_Use_Image(void)
{
  int i,j;
  for(i=0;i<image_row;i++)
    for(j=0;j<image_col;j++)
    {
      Image_Use[i][j] = image[i*2][j*2+1];
    }
}
  • 1.2 变量声明:
uint8   image[MT9V032_H][MT9V032_W];      		//图像数组
#define image_row 60 							//图像高度(行)             
#define image_col 94							//图像宽度(列)
uint8 Image_Use[image_row][image_col];          //用于储存缩小后的图像,实际应用的图像

2. 得到二值化后的图像

  • 2.1 模式选择:
  • 0:使用大津法阈值(GetOSTU
  • 1:使用平均阈值
  • 2:sobel 算子改进型 手动阈值,同时输出改为提取边沿的图像(lq_sobel
  • 3:sobel 算子改进型 动态阈值,同时输出改为提取边沿的图像(lq_sobelAutoThreshold
  • 2.2 函数内容:
/*************************************************************************
 *  函数名称:Get_Bin_Image
 *  功能说明:图像二值化到Bin_Image[][]
 *  参数说明:mode  :
 *    0:使用大津法阈值
 *    1:使用平均阈值
 *    2: sobel 算子改进型  手动阈值,同时输出改为提取边沿的图像
 *    3:sobel 算子改进型   动态阈值,同时输出改为提取边沿的图像
 *  函数返回:无
 *  修改时间:2020年10月28日
 *  备    注:  Get_Bin_Image(0); //使用大津法二值化
 *************************************************************************/
void Get_Bin_Image (unsigned char mode)
{
    unsigned short i = 0, j = 0;
    unsigned short Threshold = 0;
    unsigned long tv = 0;
 
    if (mode == 0)
    {
        Threshold = GetOSTU(Image_Use);  //大津法阈值
    }
    if (mode == 1)
    {
        //累加
        for (i = 0; i < image_row; i++)
        {
            for (j = 0; j < image_col; j++)
            {
                tv += Image_Use[i][j];   //累加
            }
        }
        Threshold =(unsigned short)(tv / image_row / image_col);   //求平均值,光线越暗越小,全黑约35,对着屏幕约160,一般情况下大约100
        Threshold = Threshold + 20;      //此处阈值设置,根据环境的光线来设定
    }
    else if (mode == 2)
    {
        Threshold = 80;                          //手动调节阈值
        lq_sobel(Image_Use, Bin_Image, (unsigned char) Threshold);

        return;

    }
    else if (mode == 3)
    {
        lq_sobelAutoThreshold(Image_Use, Bin_Image);  //动态调节阈值
        return;
    }

    /* 二值化 */
    for (i = 0; i < image_row; i++)
    {
        for (j = 0; j < image_col; j++)
        {
            if (Image_Use[i][j] > Threshold) //数值越大,显示的内容越多,较浅的图像也能显示出来
                Bin_Image[i][j] = WHITE_BIN;
            else
                Bin_Image[i][j] = BLACK_BIN;
        }
    }
}
  • 2.3 变量声明:
#define image_row 60 							//图像高度(行)             
#define image_col 94							//图像宽度(列)
#define BLACK_BIN 0								//二值化黑色
#define WHITE_BIN 1								//二值化白色
uint8 Image_Use[image_row][image_col];          //用于储存缩小后的图像,实际应用的图像
uint8 Bin_Image[image_row][image_col];          //二值化图片

3. 过滤噪点

  • 3.1 函数内容:
/*************************************************************************
 *  函数名称:Bin_Image_Filter
 *  功能说明:过滤噪点
 *  参数说明:无
 *  函数返回:无
 *  修改时间:2021年01月08日
 *  备    注:  
*************************************************************************/
void Bin_Image_Filter (void)
{
    int16 nr; //行
    int16 nc; //列

    for (nr = 1; nr < image_row - 1; nr++)
    {
        for (nc = 1; nc < image_col - 1; nc = nc + 1)
        {
            if ((Bin_Image[nr][nc] == 0)
                    && (Bin_Image[nr - 1][nc] + Bin_Image[nr + 1][nc] + Bin_Image[nr][nc + 1] + Bin_Image[nr][nc - 1] > 2))
            {
                Bin_Image[nr][nc] = 1;
            }
            else if ((Bin_Image[nr][nc] == 1)
                    && (Bin_Image[nr - 1][nc] + Bin_Image[nr + 1][nc] + Bin_Image[nr][nc + 1] + Bin_Image[nr][nc - 1] < 2))
            {
                Bin_Image[nr][nc] = 0;
            }
        }
    }
}
  • 3.2 变量声明:
#define image_row 60 							//图像高度(行)             
#define image_col 94							//图像宽度(列)
uint8 Image_Use[image_row][image_col];          //用于储存缩小后的图像,实际应用的图像
uint8 Bin_Image[image_row][image_col];          //二值化图片

4. 获得赛道边界

  • 4.0 函数说明:
    此函数可获得以下数据:
int16 Image_Side[2][image_row];					//边沿数据:第一行——左边界;第二行——右边界;下标——行,值——列
int16 DivLine;									//有效行
int16 Road_Width[image_row];					//路宽
  • 4.1 函数内容:
/*************************************************************************
 *  函数名称:Image_Get_Side
 *  功能说明:获得赛道边界
 *  参数说明:无
 *  函数返回:无
 *  修改时间:2021年01月08日
 *  备    注:  
*************************************************************************/
void Image_Get_Side (void)
{
	int16 x;
	int16 y;
	int16 start_col;		//起始行的起始列,赛道可能完全在屏幕左半面或右半面
	
	//如果起始行中点为不在赛道中点 往右寻找
	for(x=start_col; x <= right_col; x++)			
	{
		if(Bin_Image[start_row][x] == WHITE_BIN)		
			if(Bin_Image[start_row-1][x] == WHITE_BIN)
				if(Bin_Image[start_row-2][x] == WHITE_BIN)
				{
					start_col=x;
					break;
				}
	}
	//如果起始行中点为不在赛道中点 往左寻找
	for(x=start_col; x >= left_col; x--)						
  {
    if(Bin_Image[start_row][x] == WHITE_BIN)
      if(Bin_Image[start_row-1][x] == WHITE_BIN)
        if(Bin_Image[start_row-2][x] == WHITE_BIN)
        {
          start_col=x;
          break;
        }
  }
	
	//寻找起始行右边界
	for(x = start_col; x <= right_col; x++)
  {
    if(Bin_Image[start_row][x] == BLACK_BIN)
    {
      Image_Side[RIGHT][start_row] = x;
      break;
    }
  }
	if(x > right_col)		//没有找到右边界,丢线
  {
    Image_Side[RIGHT][start_row] = LOST_RIGHT_SIDE ;  
  } 
	
	//寻找起始行左边界
	for(x = start_col; x >= left_col; x--)
  {
    if(Bin_Image[start_row][x] == BLACK_BIN)
    {
      Image_Side[LEFT][start_row] = x;
      break;
    }
  }
	if(x < left_col)		//没有找到左边界,丢线
  {
    Image_Side[LEFT][start_row] = LOST_LEFT_SIDE ;  
  }
	
	//起始行宽度
	Road_Width[start_row] = Image_Side[RIGHT][start_row] - Image_Side[LEFT][start_row];
	
	//寻找其他行边界
	for(y=start_row-1;  y>=end_row;  y--)  //由近到远找
  {
    //左边界
    x = Image_Side[LEFT][y+1] + 4;		//从上一行左侧往右4个点开始寻找,如果这个值设置太大会影响远处找中线
    while( (Bin_Image[y][x]==BLACK_BIN) && (x<=right_col) ) 
    {
      x += 4;
    }
    if(x>right_col) //找不到边界(只有两条边界相距太近时,才找不到)(找不到白色)(全都是黑色,才叫无效)
    {
      DivLine = y+1; 
      break;
    }
    for(; x>=left_col; x--)
    {
      if(Bin_Image[y][x] == BLACK_BIN)
      {
        Image_Side[LEFT][y] = x;      
        break;
      }
    }
    if(x < left_col)     //判断是否出了边界
    {
      Image_Side[LEFT][y] = LOST_LEFT_SIDE;  
    }
    
    //右边界
    x = Image_Side[RIGHT][y+1] - 4;	//从上一行左侧往右4个点开始寻找
    while( (Bin_Image[y][x]==BLACK_BIN) && (x>=left_col) )
    {
      x -= 4;
    }
    if(x < 0) //找不到边界
    {
      DivLine = y+1; 
      break;
    }
    for(;x <= right_col; x++)
    {
      if(Bin_Image[y][x] == BLACK_BIN)
      {
        Image_Side[RIGHT][y] = x;
        break;
      }
    }
    if(x > right_col)//判断是否出了边界
    {
      Image_Side[RIGHT][y] = LOST_RIGHT_SIDE;       
    }
		//路宽
		Road_Width[y] = Image_Side[RIGHT][y] - Image_Side[LEFT][y];
		
    /*-------------满足以下情况时停止对这幅图片的处理并寻找有效行--------------*/
    //如果满足 (左右边界靠得太近  或者  左侧边界太靠右  或者  右侧边界太靠左) 则跳出找线
    if(   (Road_Width[y] < 10)  //此处的 10 可以根据需要来改
       || (Image_Side[LEFT][y]  > image_col-5)
       || (Image_Side[RIGHT][y] < 4))
    {
      DivLine = y + 1;//确定该幅图像有效行,便于下面程序算斜率、截距
      break;
    }
    else 
      DivLine=0;			//否则就是直到最远处一行都是有效的
  }	
}
  • 4.2 变量声明:
#define image_row 60 							//图像高度(行)             
#define image_col 94							//图像宽度(列)
#define BLACK_BIN 0								//二值化黑色
#define WHITE_BIN 1								//二值化白色
#define LEFT	  0								//数组变量左
#define RIGHT	  1								//数组变量右
#define LOST_LEFT_SIDE 		-1					//左边界丢失
#define LOST_RIGHT_SIDE		image_col			//右边界丢失
uint8 Image_Use[image_row][image_col];          //用于储存缩小后的图像,实际应用的图像
uint8 Bin_Image[image_row][image_col];          //二值化图片
uint8 left_col 		= 0;						//最左边
uint8 right_col		= image_col-1;				//最右边
uint8 end_row		= 0;						//最远行
uint8 start_row		= image_row-1;				//最近行
int16 Image_Side[2][image_row];					//边沿
int16 DivLine;									//有效行
int16 Road_Width[image_row];					//路宽
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_43964993

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值