在我们得到一张稳定的二值化图像后,就可以对图像进行一些寻线的处理,在这里简单提一下,那就是图像第一行所在的位置,作为初学者的我刚开始就曾搞错,摄像头第一行所在的位置取决于你摄像头是正装还是反装,如果是正装那么对应远离车身所对应的是第一行,靠近的为最大行。反装则相反,但是还需注意的是正装和反装所对应的左右行数也是不同的,在存放左右边界时需要注意,两者是相反的。关于摄像头是如何放置的问题,其实两者并没有太大的区别,如何放置根据个人的考虑决定了。

个人认为摄像头的巡线可以分为3类:

一类是最基础,也是最简单的,由中线分别往左右两边扫,寻找黑白的跳变点,存放到左右边界数组中。

二是对固定对靠近车身的一行或是5行进行扫描,确定左右边界后,根据上一个左右边界所在列数的周围进行之后行数的扫描,这也是我比赛所用到的寻线方式。

三就是所谓的种子生长法,其初始方向和第二种方式一样,对最靠近车身的一行进行扫描,得到左右边界,以寻到的两个点为基础,框出一个3*3的矩形框,分别对左右两个点所在的矩阵框内进行顺时针和逆时针扫描,找到跳变点,依次往下扫描,这样就可以寻出一条完整的边线,只不过当时时间比较短,所以没有继续往下深究。

首先我们需要定义几个数组来存放我们之后得到的一些数据

int leftline[80];  //赛道左边界
int rightline[80];  //赛道右边界
int centerline[80]; //赛道中间线
 
int road_width[80];//道路宽度   这里的80是我只扫描了80行

下面先给出第一种的寻线,可以让小车早点的跑起来:

int line=0;
int list=0;
void image_scan()
{
 for(line=120;line>=40;line--)
 {
   for(list=93;list<188;list++)
   {
    if((image_deal[line][list-2]==white)&&(image_deal[line][list-1]==black) 
       &&(image_deal[line][list]==black))
     {
       rightline[line]=list;
       	break;
     }
   }
 
   for(list=93;list>1;list--)
   {
    if((image_deal[line][list]==black)&&(image_deal[line][list+1]==black)
        &&(image_deal[line][list+2]==white)) 
     {
       leftline[line]=list;
      break;
     }
   }
	road_width[line]=my_abs(leftline[line],rightline[line]);
	centerline[line]=(rightline[line]+leftline[line])/2;
  }
}

第二种寻线法:

​
uint8 first_scan()
{
   int line=(MT9V03X_CSI_H-1);     
   int list=0;  
   uint8 start_list = 0;
   uint8 Find_Left=0;  //寻到左线标志位
   uint8 Find_Right=0; //寻到右线标志位
 
  if (image_deal[line][center] == white) //开始扫描第一行的左右边界
  {
    for (list = center; list >= 3; list--)
    {
      if ((image_deal[line][list - 1] == black) && (image_deal[line][list] == black) 
           &&(image_deal[line][list + 1] == white)) //黑白白
      {
        leftline[line] = list + 1; //左边界数组
        Find_Left = 1;             //找到了左线
        break;
      }
    }
    if (Find_Left == 0) //没找到 以最左边为边界
    {
      leftline[line] = 1;
    }
    //-----------左边界完成-------------
    for (list = center; list <= cutCOL - 2; list++)
    {
      if ((image_deal[line][list - 1] == white) && (image_deal[line][list] == black) 
           && (image_deal[line][list + 1] == black)) //白嘿嘿。。黑尼玛
      {
        rightline[line] = list - 1;
        Find_Right = 1;
        break;
      }
    }
    if (Find_Right == 0) //    没找到右边界
    {
      rightline[line] = (cutCOL - 1); //以扫描图像的最右边一列-1为边界
    } //-------------右边界完成----------
  }
  road_width[line] = my_abs(leftline[line], rightline[line]);
  centerline[line] = (rightline[line] + leftline[line]) / 2;
  last_left_line = leftline[line];
  last_right_line = rightline[line];
  return start_list;
}
 
void Follow_scan()
{
  for (line = MT9V03X_CSI_H - 1 - 1; line >= 40; line--)
  {
    Find_left = 0;
    Find_right = 0;
    if ((last_left_line - follow_can - flag_cross) < 0)
      scan_start_left = 0;
    else
      scan_start_left = (last_left_line - follow_can - flag_cross);
 
    if ((last_left_line + follow_can * 3 + flag_cross) >= (cutCOL - 2))
      scan_end_left = (cutCOL - 3);
    else
      scan_end_left = (last_left_line + follow_can * 3 + flag_cross);
 
    for (list = scan_start_left; list <= scan_end_left; list++)
    {
      if ((image_deal[line][list] == black) && (image_deal[line][list + 1] == white)
           &&(image_deal[line][list + 2] == white))
      {
        leftline[line] = list;
        Find_left = 1;
        break;
      }
    }
    if (Find_left == 0)
    {
      // leftline[line]=0;
      left_lost_flag[line] = 1;
      left_lost_count++;
      if (flag_of_leftbreak == 0)
      {
        l_start++;
      }
    }
    else
    {
      flag_of_leftbreak = 1; //break标志成立
    }
    //---------------------------------------------------------左线完毕------------------
    if ((last_right_line + follow_can + flag_cross) >= (cutCOL))
      scan_start_right = (cutCOL - 2);
    else
      scan_start_right = (last_right_line + follow_can + flag_cross);
 
    if ((last_right_line - follow_can * 3 + flag_cross) <= 2)
      scan_end_right = 2;
    else
      scan_end_right = (last_right_line - follow_can * 3 + flag_cross);
 
    for (list = scan_start_right; list >= scan_end_right; list--) //-------右边界开始寻线-
    {
      if ((image_deal[line][list - 2] == white) && (image_deal[line][list - 1] == white) 
           &&(image_deal[line][list] == black))
      {
        rightline[line] = list;
        Find_right = 1;
        break;
      }
    }
 
    if (Find_right == 0)
    {
      // rightline[line]=(cutCOL-1);
      right_lost_flag[line] = 1;
      right_lost_count++;
      if (flag_of_rightbreak == 0) //如果在这一行之前没有遭遇断线,则计数
      {
        r_start++;
      }
    }
    else //扫到线
    {
      //lostright_times不继续增加
      flag_of_rightbreak = 1; //break标志成立
    }
    //-------------------------------------------------------右边界结束-------------------
    road_width[line] = (rightline[line] - leftline[line]); 初步计算赛道宽度
    centerline[line] = (leftline[line] + rightline[line]) / 2;
  } 
}
 
​

第三种巡线方式之后如果能够写出来,可能会添上。

至此对于图像的基本寻线就结束了,下一章就是对一些元素进行特征提取