智能车制作

标题: 关于摄像头斜入十字的一些想法 [打印本页]

作者: 54_刘小威    时间: 2016-2-1 17:49
标题: 关于摄像头斜入十字的一些想法
对于摄像头来说,天然的优势是一次可以扫描很多行,这使得在赛道处理方面要比线性CCD简单得多,其实黑线采集本身是非常简单的,不过感觉对于新手来说,斜入十字或许会有点难,这些天我一直在考虑这个问题,今天终于有了一些想法,我们都知道,斜入十字是一定会有一个突变点的,许多人认为难就难在提取这个突变点上,我认为由于镜头失真,导致摄像头采集的数据是梯形的,也就是左边的那条黑线一般是向右倾斜的,而右边的那条黑线一般是向左倾斜的,那么什么时候会出现异常呢,当然是弯道了,各种弯道都可能,其实斜入十字误判就是当弯道处理,而我们只不过是把弯道在进行判断看是不是十字,那么我正常采集黑线的过程中,当出现左边黑线向左倾斜或者右边黑线向左倾斜的时候我就继续采集三行数据,比较这三行的斜率与前三行,这里的前是指靠近车的部分,当斜率突变,则认为是斜入十字。到这里似乎斜入十字就解决了,可是最重要的是补线,那么怎么补线呢,我的处理方法是当我找到斜入十字的时候,我从突变点的哪一行开始,就突变点所在的那一列开始向上搜线,即远处,当搜到黑线的时候结束,这个时候我在向右寻找,当我找到由黑色向白色的跳变的时候,则认为找到了十字的结束行,通过十字开始行(即突变点所在行)到十字结束行的斜率进行补线即可。

作者: 54_刘小威    时间: 2016-2-1 17:51
打错了,第8行应该是出现左线向左倾斜右线向右倾斜的时候
作者: q15920078530    时间: 2016-2-1 17:58
来点实际实现代码呗
作者: 54_刘小威    时间: 2016-2-1 18:02
q15920078530 发表于 2016-2-1 17:58
来点实际实现代码呗

自己看吧,不想单独写了,直接从我程序中提取的
void search_line(void)
{
  int8 Row_Ptr=0;//行计数参量
  int8 Col_Ptr=0;//列计数参量
  int8 Left_End=0;//寻左线列截止数
  int8 Right_End=0;//寻右线列截止数
  track.Left_Valid_Count=0;//默认左边沿有效连续计数值为0
  track.Right_Valid_Count=0;//默认右边沿有效连续计数值为0
  track.Left_Invalid_Count=0;//默认左边沿无效连续计数值为0
  track.Right_Invalid_Count=0;//默认右边沿无效连续计数值为0
  Cross_Flag=0;//默认无十字
  /*
   *由于最近三行图像非常靠谱,利用从中间向两边分别寻找能找到靠谱的黑线
   */
  for(Row_Ptr=ROW-1;Row_Ptr>ROW-3;Row_Ptr--)
  {
    track.Left_Line[Row_Ptr]=1;//初始化左黑线为1
    track.Right_Line[Row_Ptr]=COLUMN-2;//初始化右黑线为COLUMN-2
    track.Left_Valid[Row_Ptr]=0;//默认左边未找到黑线
    track.Right_Valid[Row_Ptr]=0;//默认右边未找到黑线
    track.Center_Line[Row_Ptr]=COLUMN/2;//默认中线为图像中间
    //从中间开始往左寻线
    for(Col_Ptr=COLUMN/2;Col_Ptr>0;Col_Ptr--)
    {
   if(img[Row_Ptr][Col_Ptr]==0 && img[Row_Ptr][Col_Ptr-1]==1)
   {
    track.Left_Line[Row_Ptr]=Col_Ptr-1;//黑线位置
    track.Left_Valid[Row_Ptr]=1;//此行左黑线有效位置1
    track.Left_Valid_Count++;//连续有效行+1
        track.Left_Invalid_Count=0;
    break;
   }
    }
    if(track.Left_Valid==0)
    {
      track.Left_Valid_Count=0;
      track.Left_Invalid_Count++;
    }
    //从中间开始往右寻线
    for(Col_Ptr=COLUMN/2;Col_Ptr<COLUMN;Col_Ptr++)
    {
   if(img[Row_Ptr][Col_Ptr]==0 && img[Row_Ptr][Col_Ptr+1]==1)
   {
    track.Right_Line[Row_Ptr]=Col_Ptr+1;
    track.Right_Valid[Row_Ptr]=1;
    track.Right_Valid_Count++;
        track.Right_Invalid_Count=0;
    break;
   }
    }
    if(track.Right_Valid==0)
    {
      track.Right_Valid_Count=0;
      track.Right_Invalid_Count++;
    }
  }
  /*
   *由于梯形失真导致左边的黑线是从下往上向右收敛,右边的黑线是从下往上向左收敛(除非
   *弯道,左黑线向左收敛可能是S弯道或者左拐弯还有十字,右黑线向右收敛可能是S弯或者右
   *拐弯还有十字),利用这也特点,当出现相反情况时判断是否是突变点,可以识别斜入十字
   *,而直入十字判断则用连续白行即可
   */
  if(track.Left_Valid_Count==3&&track.Right_Valid_Count==3)//最近三行左右均找到黑线
  {
    for(Row_Ptr=ROW-4;Row_Ptr>Drop_Row;Row_Ptr--)
    {
      track.Left_Line[Row_Ptr]=1;//初始化为1
      track.Left_Valid[Row_Ptr]=0;//初始化每行无效
      Col_Ptr=track.Left_Line[Row_Ptr+1]+6;//具体数值还需视情况而定
      Left_End=track.Left_Line[Row_Ptr+1]-6;
      for(;Col_Ptr>Left_End;Col_Ptr--)
      {
        if(img[Row_Ptr][Col_Ptr]==0 && img[Row_Ptr][Col_Ptr-1]==1)
        {
          track.Left_Line[Row_Ptr]=Col_Ptr-1;//黑线位置
          track.Left_Invalid_Count=0;//左线连续无效值清零
          if(track.Left_Line[Row_Ptr]<track.Left_Line[Row_Ptr+1])//出现左线异常不向右收敛
          {
            Left_Turn_Count++;//左线收敛方向异常连续计数+1
            track.Left_Valid[Row_Ptr]=1;//暂时标记此行左黑线有效位置1
            break;
          }
          else//左线正常向右收敛
          {
            Left_Turn_Count=0;//左线收敛方向异常连续计数值清零
            track.Left_Valid[Row_Ptr]=1;//此行左黑线有效位置1
            break;
          }
        }
      }
      if(track.Left_Valid==0)//此行没有找到左黑线
        track.Left_Invalid_Count++;
      if(Left_Turn_Count==3)//左黑线收敛方向异常进一步判断是否为斜入十字
      {
        if(zxec_slope_calculate(Row_Ptr,Row_Ptr+3,track.Left_Line)*
            zxec_slope_calculate(Row_Ptr+3,Row_Ptr+6,track.Left_Line)<-2)//要改
        {
          //通过此条件进一步确定为斜入十字
          Cross_Flag=2;
          //Left_Turn_Count=0;
          Left_Turn_Row=Row_Ptr+3;
          track.Left_Valid[Row_Ptr]=0;
          track.Left_Valid[Row_Ptr+1]=0;
          track.Left_Valid[Row_Ptr+2]=0;
          //接下来应该利用竖直的线向上搜,找到十字结束行,这里用Left_Turn_End表示
          for(;Row_Ptr>Drop_Row;Row_Ptr--)
          {
            track.Left_Valid[Row_Ptr]=0;
            if(img[Row_Ptr][track.Left_Line[Left_Turn_Row]]==0 && img[Row_Ptr-1][track.Left_Line[Left_Turn_Row]]==1)
            {
              Left_Turn_End=Row_Ptr;
              for(Col_Ptr=track.Left_Line[Left_Turn_Row];Col_Ptr<COLUMN;Col_Ptr++)
              {
                if(img[Row_Ptr][Col_Ptr]==1 && img[Row_Ptr][Col_Ptr+1]==0)
                {
                  track.Left_Line[Left_Turn_End]=Col_Ptr;
                  track.Left_Valid[Row_Ptr]=1;
                }
                break;
              }
              for(Row_Ptr=Left_Turn_Row;Left_Turn_Row<Left_Turn_End;Row_Ptr--)//斜入十字补线
              {
                track.Left_Line[Row_Ptr]=track.Left_Line[Left_Turn_Row]+
                 (track.Left_Line[Left_Turn_End]-track.Left_Line[Left_Turn_Row])/ (Left_Turn_End-Left_Turn_Row)*(Row_Ptr-Left_Turn_Row);
                track.Left_Valid[Row_Ptr]=1;
              }
              break;
            }
          }
          if(Left_Turn_End==0)//向上搜线未找到结束行
          {
            for(Row_Ptr=Left_Turn_Row;Left_Turn_Row<Drop_Row;Row_Ptr--)//斜入十字补线
            {
              track.Left_Line[Row_Ptr]=track.Left_Line[Left_Turn_Row]+
                 (track.Left_Line[Left_Turn_Row]-track.Left_Line[Left_Turn_Row+3])/ (Left_Turn_Row-(Left_Turn_Row+3))*(Row_Ptr-Left_Turn_Row);
              track.Left_Valid[Row_Ptr]=1;
            }
          }
        }        
      }
      if(track.Left_Invalid_Count==3)
      {
        track.Left_Break=Row_Ptr+3;//左边黑线断点行记录
        break;//跳出大循环,停止搜线
      }
    }
  }
}

作者: °Destiny    时间: 2016-2-1 20:18
楼主可以把计算斜率那儿的代码贴一下吗,谢谢
zxec_slope_calculate()
作者: 54_刘小威    时间: 2016-2-1 20:21
°Destiny 发表于 2016-2-1 20:18
楼主可以把计算斜率那儿的代码贴一下吗,谢谢
zxec_slope_calculate()

float zxec_slope_calculate(int8 begin,int8 end,int8 *array)  
{  
  int xsum=0,ysum=0,xysum=0,x2sum=0;
  uint8 i=0;
  float result=0;
  static float result_last;//开辟静态区间,保存上一次的结果
  array=array+begin;//定位开始地址
  for(i=begin;i<=end;i++)
  {
  xsum+=i;
  ysum+=*array;
  xysum+=i*(*array);
  x2sum+=i*i;
  array=array+1;
}
  if((end-begin)*x2sum-xsum*xsum) //除数不为零
  {
    result=(float)((end-begin+1)*xysum-xsum*ysum)/((end-begin+1)*x2sum-xsum*xsum);
    result_last=result;
  }
  else//除数等于零
    result=result_last;//保留上一次不为零时的计算结果
  return result;
}
作者: 从容阳光℡    时间: 2016-2-2 21:54
楼主中石油?青岛还是北京啊
作者: 54_刘小威    时间: 2016-2-2 22:14
从容阳光℡ 发表于 2016-2-2 21:54
楼主中石油?青岛还是北京啊

当然青岛的啊

作者: xiao0101    时间: 2016-2-12 12:30
楼主有试试实际跑起来效果怎么样吗?
作者: sangchaochun    时间: 2016-2-18 13:56
谢谢楼主,楼主好人
作者: 唯忆り    时间: 2016-2-18 15:13
学习了
作者: liusicong    时间: 2016-2-23 10:56
:):):)
作者: 承影    时间: 2016-3-2 16:44
好人

作者: joe230023    时间: 2016-3-28 16:36
科密顶一个
作者: zss123    时间: 2016-3-29 20:57
666666666666
作者: maketuwen    时间: 2016-11-19 21:56
楼主能给下这个完整的巡线的程序吗?谢谢
作者: 墨庄    时间: 2017-3-4 18:13
顶一个
作者: znjqr    时间: 2017-3-4 19:33
楼主可以把计算斜率那儿的代码贴一下吗,谢谢
作者: 猫少    时间: 2017-4-6 21:45
谢谢楼主了
作者: znczz1996    时间: 2017-4-21 09:33
谢谢楼主,感谢分享
作者: 蝶舞明月    时间: 2017-4-22 22:37
突变点说的是十字开始那个点吗?
作者: 蝶舞明月    时间: 2017-5-11 22:38
track.Left_Valid    可以请教这个是干嘛的吗(代码里面都没有地方用到呢),为什么判断等于0  就把有效行计数清零和无效行加1呢




欢迎光临 智能车制作 (http://dns.znczz.com/) Powered by Discuz! X3.2