从0开始的智能车代码(3)

环岛是处理起来相对比较困难的一种赛道元素。条条大路通环岛,解决环岛问题也有许多不同的方案。在我参考过环岛的代码时,复杂的代码逻辑和庞大的代码量使我望而却步,见到巨人的肩膀魁梧却布满荆棘,我决定自己动手丰衣足食。我的方法是 MELP 四步过环岛,即遇环(Meet)、入环(Enter)、出环(Leave)、过环(Pass)。

首先,在寻找左右边线时留意边线横坐标(所在列数)突然变化的点,我将这种点称为跳变点。我将跳变点分为两类,赛道交汇形成的跳变点称为 A 字跳变点,赛道分支形成的跳变点称为 V 字跳变点。所有跳变点可以分成左侧 A 字跳变点、左侧 V 字跳变点、右侧 A 字跳变点、右侧 V 字跳变点这4种。

void imageProcess(void){
  uint16 i,j;
  uint16 edgeL[MT9V032_H];
  uint16 edgeR[MT9V032_H];
  uint16 midline[MT9V032_H];
  
  edgeL[MT9V032_H-1]=0;
  edgeR[MT9V032_H-1]=MT9V032_W-1;
  midline[MT9V032_H-1]=MT9V032_W/2;
  
  uint8 jumpFlagL=0;
  uint8 jumpFlagR=0;
  
  uint16 pointX=0;//跳变点X坐标
  uint16 pointY=0;//跳变点Y坐标
  uint8 pointSide=0;//跳变点方向,1表示左,2表示右
  uint8 pointType=0;//跳变点分类,1表示A字跳变点,2表示V字跳变点
  
  for(i=MT9V032_H-2;;i--){
    edgeL[i]=0;
    edgeR[i]=MT9V032_W-1;
    
    for(j=midline[i+1];j>0;j--){
      if(binaryImage[i][j]==0){
        edgeL[i]=j;
        break;
      }
    }
    
    for(j=midline[i+1];j<MT9V032_W-1;j++){
      if(binaryImage[i][j]==0){
        edgeR[i]=j;
        break;
      }
    }
    
    //环岛处理开始(见到巨人的肩膀魁梧却布满荆棘,我决定自己动手丰衣足食)
    //环岛处理所有数都是非负数
    //bingo:和十字区分:扫描到一侧的跳变点后(下半部分),对另一侧的边线进行判断(下3/4部分)
    
    //寻找跳变点
    
    if(i>MT9V032_H*1/3){//只判断下2/3部分图像的跳变点(赛道突然变窄)
      //左侧A字跳变点
      if(edgeL[i+1]-edgeL[i]>20){
        jumpFlagL=1;
        pointX=edgeL[i+1];
        pointY=i+1;
        pointSide=1;
        pointType=1;
      }
      //左侧V字跳变点
      else if(edgeL[i]-edgeL[i+1]>20){
        jumpFlagL=1;
        pointX=edgeL[i];
        pointY=i;
        pointSide=1;
        pointType=2;
      }
      //右侧A字跳变点
      if(edgeR[i]-edgeR[i+1]>20){
        jumpFlagR=1;
        pointX=edgeR[i+1];
        pointY=i+1;
        pointSide=2;
        pointType=1;
      }
      //右侧V字跳变点
      else if(edgeR[i+1]-edgeR[i]>20){
        jumpFlagR=1;
        pointX=edgeR[i];
        pointY=i;
        pointSide=2;
        pointType=2;
      }
    }
    
    midline[i]=(edgeL[i]+edgeR[i])/2;//考虑环岛补线后不能边判断边线边计算中线,这个中线只用来下一步寻找边界
    
    if(i==0){
      break;
    }
  }
  
  //四步过环,遇环、入环、出环、过环
  static uint8 meetRingFlag=0;//遇环标志位
  static uint8 enterRingFlag=0;//入环标志位
  static uint8 exitRingFlag=0;//出环标志位
  static uint8 ringSide=0;//环岛类型,1表示左,2表示右

  uint16 pointLLCX=0;
  uint16 pointLLCY=MT9V032_H-1;
  uint16 pointLRCX=MT9V032_W-1;
  uint16 pointLRCY=MT9V032_H-1;
  
  float stepLength;//横坐标插值步长
  
  if(jumpFlagL^jumpFlagR){//若有一侧出现跳变点
    if(pointType==1){//若为A字跳变点,说明出环或遇环
      if(enterRingFlag==1){//出环
        exitRingFlag=1;
      }
      else if(meetRingFlag==0){//遇环
        meetRingFlag=1;
        ringSide=pointSide;
      }
      //目前A字跳变点可以自动处理,无需补线
    }
    else if(pointType==2){//若为V字跳变点,说明入环或过环
      if(exitRingFlag==1){//过环//与入环相反//须先判断过环
        meetRingFlag=0;
        enterRingFlag=0;
        exitRingFlag=0;
        if(ringSide==2){
          stepLength=(float)(pointLRCX-pointX)/(float)(pointLRCY-pointY);
          for(i=0;i<pointLRCY-pointY;i++){
            edgeR[pointLRCY-i]=pointLRCX-(int)(i*stepLength);
            binaryImage[pointLRCY-i][edgeR[pointLRCY-i]]=binaryImage[pointLRCY-i][edgeR[pointLRCY-i]-1]=binaryImage[pointLRCY-i][edgeR[pointLRCY-i]+1]=0;//粗线
          }
        }
        else if(ringSide==1){
          stepLength=(float)(pointX-pointLLCX)/(float)(pointLLCY-pointY);
          for(i=0;i<pointLLCY-pointY;i++){
            edgeL[pointLLCY-i]=pointLLCX+(int)(i*stepLength);
            binaryImage[pointLLCY-i][edgeL[pointLLCY-i]]=binaryImage[pointLLCY-i][edgeL[pointLLCY-i]-1]=binaryImage[pointLLCY-i][edgeL[pointLLCY-i]+1]=0;//粗线
          }
        }
      }
      else if(meetRingFlag==1){//入环
        enterRingFlag=1;
        //入环补线
        //认为跳变点方向为圆环方向
        //入环标志点(pointAX,pointAY),图像左下角(pointLLCX,pointLLCY),图像右下角(pointLRCX,pointLRCY)
        if(ringSide==1){//入环标志点在左边,从右下角点到入环标志点连线,补右边线
          stepLength=(float)(pointLRCX-pointX)/(float)(pointLRCY-pointY);
          for(i=0;i<pointLRCY-pointY;i++){
            edgeR[pointLRCY-i]=pointLRCX-(int)(i*stepLength);
            binaryImage[pointLRCY-i][edgeR[pointLRCY-i]]=binaryImage[pointLRCY-i][edgeR[pointLRCY-i]-1]=binaryImage[pointLRCY-i][edgeR[pointLRCY-i]+1]=0;//粗线
          }
        }
        else if(ringSide==2){//入环标志点在右边,从左下角点到入环标志点连线,补左边线
          stepLength=(float)(pointX-pointLLCX)/(float)(pointLLCY-pointY);
          for(i=0;i<pointLLCY-pointY;i++){
            edgeL[pointLLCY-i]=pointLLCX+(int)(i*stepLength);
            binaryImage[pointLLCY-i][edgeL[pointLLCY-i]]=binaryImage[pointLLCY-i][edgeL[pointLLCY-i]-1]=binaryImage[pointLLCY-i][edgeL[pointLLCY-i]+1]=0;//粗线
          }
        }
      }
    }
  }
  
  for(i=0;i<MT9V032_H;i++){//重新计算中线
    midline[i]=(edgeL[i]+edgeR[i])/2;
    binaryImage[i][midline[i]]=binaryImage[i][midline[i]-1]=binaryImage[i][midline[i]+1]=0;//粗线
  }

  offset=MT9V032_W/2-midline[98];
}

猜你喜欢

转载自www.cnblogs.com/stephen0829/p/13376834.html