精华内容
下载资源
问答
  • 智能车中线
    万次阅读 多人点赞
    2021-08-03 16:24:51

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

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

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

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

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

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

    int leftline[120];  //赛道左边界
    int rightline[120];  //赛道右边界
    int centerline[120]; //赛道中间线
    
    int road_width[120];//道路宽度   这里的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;
      } 
    }
    
    ​

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

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

    更多相关内容
  • K60程序,通过摄像头采集图像,二值化,寻找中线,控制电机舵机,智能车沿中线
  • 适合智能车竞赛入门使用 ov7620经典摄像头 stm32主控 IAR工程 包括图像采集 二值化 中线提取 平滑处理 平均滤波 舵机pid控制 代码很规范适合大一大二同学智能车竞赛入门
  • 智能车图像处理1-中线的提取

    千次阅读 热门讨论 2022-02-03 01:34:09
    这篇文章主要讲述如何实现中线的扫描和二次扫线。 一、代码 void zhongxian() { int hang; int lie; int guixian = 0; int zhongold2 = 0; for (hang = 0; hang < 50; hang++) { for (lie = zhongold; ...

    前言

    这篇文章主要讲述如何实现中线的扫描和二次扫线。
    基础扫线效果图片如下
    在这里插入图片描述

    一、函数主体

    void zhongxian()
    {
    
    
        int hang;
        int lie;
        int guixian = 0;
        int zhongold2 = 0;
        //第一次扫线,获取0-50行左右线的值
        for (hang = 0; hang < 50; hang++)
        {
            for (lie = zhongold; lie >= 1; lie--)
            {
                if (lie >= (int)185) lie = 184;
                if (Pixels[hang][ lie - 1] == 0 && Pixels[hang][ lie] == 0 && Pixels[hang][lie + 1] == 1) //黑白
                {
    
                    R_black[hang] = (unsigned char)(lie + 1);
                    rightold = (int)(lie + 1);
                    rightflag[hang] = 1;
                    break;
                }
                else
                {
    
                    R_black[hang] = 0;
                    rightflag[hang] = 0;
                }
            }
            for (lie = zhongold; lie < 185; lie++)
            {
                if (lie == 0) lie = 1;
                if (Pixels[hang][ lie + 1] == 0 && Pixels[hang][ lie] == 0 && Pixels[hang][ lie - 1] == 1)
                {
    
                    L_black[hang] = (unsigned char)(lie - 1);
                    leftold = (int)(lie - 1);
                    leftflag[hang] = 1;
                    break;
                }
                else
                {
    
                    L_black[hang] = 186;
                    leftflag[hang] = 0;
                }
            }
            //下一行的扫线在上一行的基础上向左右扫
            zhongold = (int)((L_black[hang] + R_black[hang]) / 2);
        }
        for (hang = 0; hang < 50; hang++)
        { LCenter[hang] = (unsigned char)((L_black[hang] + R_black[hang]) / 2); }
        /*二次扫线*/
        duanhang0 = 0;
        duanhang1 = 0;
        for (hang = 1; hang < 50; hang++)  //扫断点0
        {
        /*
        断行0的原理:由于摄像头视角,呈现出的赛道应该是近大远小的,如果远
        处的行 宽度比近处的大,那么认为出现第一个断行。(大家可以想一下十
        字路口的下方 赛道宽度变宽)
        */
            if ((L_black[hang] - R_black[hang]) <= (L_black[hang - 1] - R_black[hang - 1])) { };
            if ((L_black[hang] - R_black[hang]) - (L_black[hang - 1] - R_black[hang - 1]) >= 4&&hang>=13)
            {
                duanhang0 = hang - 1;
                duanhangju = (L_black[hang - 1] - R_black[hang - 1]);
    
                break;
            }
        }
    
        if (duanhang0 > 10)
        {
        /*
        如果扫描到断行0,那么从断行0开始的图像可能有问题,
        所以这里选择固定终止往下扫线,寻找断行1的存在。
        (断行1的原理,当宽度再次变小且小于断行0处的宽度,
        认为是正确的断行1,大家可以想一下十字路口的上半段)
    
    
       */
            advanced_regression(0, duanhang0 - 9, duanhang0 - 7, duanhang0 - 5, duanhang0 - 3); //显示断行处斜率
            zhongold2 = LCenter[duanhang0 - 7];
            for (hang = (int)(duanhang0 + 3); hang < 50; hang++)  //固定中值扫线
            {
                for (lie = (int)zhongold2; lie >= 1; lie--)  //扫右线
                {
                    if (lie >= 185) lie = 184;
                    if (Pixels[hang][ lie - 1] == 0 && Pixels[hang][ lie] == 0 && Pixels[hang][ lie + 1] == 1) //白黑黑
                    {
    
                        R_black[hang] = (unsigned char)(lie + 1);
                        rightold = (int)(lie + 1);
                        rightflag[hang] = 1;
                        break;
                    }
                    else
                    {
    
                        R_black[hang] = 0;
                        rightflag[hang] = 0;
                    }
                }
                for (lie = (int)zhongold2; lie < 185; lie++)  //扫左线
                {
                    if (lie == 0) lie = 1;
                    if (Pixels[hang][ lie + 1] == 0 && Pixels[hang][ lie] == 0 && Pixels[hang][ lie - 1] == 1)
                    {
    
                        L_black[hang] = (unsigned char)(lie - 1);
                        leftold = (int)(lie - 1);
                        leftflag[hang] = 1;
                        break;
                    }
                    else
                    {
    
                        L_black[hang] = 186;
                        leftflag[hang] = 0;
                    }
                }
            }
        }
        for (hang = (int)(duanhang0 + 3); hang < 50; hang++)//扫断点1
        {
         /*
        计算是否存在断行1
        */
            if ((L_black[hang] - R_black[hang]) < duanhangju-15&&L_black[hang]<=180&&R_black[hang]>=5)
            {
                duanhang1 = (signed short int)hang;
              //  SetText("    找到断行1    " + duanhang1);
              //   SetText("    duanhangju1    " + calkuan[duanhang1]);
                break;
            }
        }
        if (duanhang0 > 10 && duanhang1 != 0)
        {
          /*
        找到断行1,开始进入二次扫线模式
        二次扫线思路:从断行1处开始使用断行0的中值进行扫线,动态继承中值往下扫。
         */
            zhongold2 = LCenter[duanhang0 - 7];
    
            int gudingtime = 1;
            for (hang = (int)(duanhang1); hang < 50; hang++)  //二次扫线
            {
                for (lie = (int)zhongold2; lie >= 1; lie--)  //扫右线
                {
                    if (lie >= 185) lie = 184;
                    if (Pixels[hang][ lie - 1] == 0 && Pixels[hang][ lie] == 0 && Pixels[hang][lie + 1] == 1) //白黑黑
                    {
    
                        R_black[hang] = (unsigned char)(lie + 1);
                        rightold = (int)(lie + 1);
                        rightflag[hang] = 1;
                        break;
                    }
                    else
                    {
    
                        R_black[hang] = 0;
                        rightflag[hang] = 0;
                    }
                }
                for (lie = (int)zhongold2; lie < 185; lie++)  //扫左线
                {
                    if (lie == 0) lie = 1;
                    if (Pixels[hang][ lie + 1] == 0 && Pixels[hang][ lie] == 0 && Pixels[hang][lie - 1] == 1)
                    {
    
                        L_black[hang] = (unsigned char)(lie - 1);
                        leftold = (int)(lie - 1);
                        leftflag[hang] = 1;
                        break;
                    }
                    else
                    {
    
                        L_black[hang] = 186;
                        leftflag[hang] = 0;
                    }
                }
                if (gudingtime != 0) gudingtime = gudingtime + 1;
                if (gudingtime == 8) gudingtime = 0;
                if (gudingtime != 0) zhongold2 = LCenter[duanhang0 - 7];
                if (gudingtime == 0) zhongold2 = (L_black[hang] + R_black[hang]) / 2;
    
            }
        }
    
        //  终止
        //存入显示数组中
        for (hang = 0; hang < 69; hang++)  //去掉杂点
        {
            LCenter[hang] = (unsigned char)((L_black[hang] + R_black[hang]) / 2);
            if (hang > 5)
            {
                if (Pixels[hang][ LCenter[hang]] == 0 && Pixels[hang + 1][LCenter[hang]] == 0&&huandao_memory!=4&&huandao_memoryforleft!=4)
                {
    
                    for (guixian = hang; guixian < 70; guixian++)
                    {
                        LCenter[hang] = LCenter[hang - 1];
                        L_black[guixian] = 0;
                        R_black[guixian] = 0;
                    }
                    break;
                }
            }
        }
    
        int j;
    
        break_hangshu = 0;
        for (j = 0; j < 50; j++)
        {
            if ((Pixels[j][ LCenter[j]]) == 0 && (Pixels[j + 1][ LCenter[j]]) == 0&& huandao_memory != 4 && huandao_memoryforleft != 4)
            {
                break_hangshu =  (int16)j;
                //last_break_hangshu = break_hangshu;
                //也就是说二十行一下是不会break的
                if (break_hangshu >= 20)    //防止在一开始就break
                {
                    break;
                }
            }
            if ((Pixels[j][ LCenter[j]]) == 0 && (Pixels[j + 1][ LCenter[j+1]]) == 0 && (Pixels[j + 2][ LCenter[j+2]]) == 0 && (Pixels[j + 3][ LCenter[j+3]]) == 0  && (huandao_memory == 4 || huandao_memoryforleft == 4))
            {
                break_hangshu = (int16)j;
                //last_break_hangshu = break_hangshu;
                //也就是说二十行一下是不会break的
                if (break_hangshu >= 20)    //防止在一开始就break
                {
                    break;
                }
            }
        }
        if (break_hangshu == 0) break_hangshu = 50;
        zhongold = LCenter[4];
        if (break_hangshu >= 4)
        {
            int calendleft =0;
            int calendright = 0;
            int i;
            for (i = break_hangshu - 1; i >= 4; i--)
            {
                if (My_Abs(L_black[i], L_black[i - 1]) <= 4&&L_black[i]!=186)
                {
                //计算左边线的最终有效行数
                    calendleft = i-1;
                 //   SetText("calendleft " + calendleft);
                    break;
                }
            }
            for (i = calendleft; i >= 4; i--)
            {
                if (L_black[i] == L_black[i - 1]) calendleft = i - 1;
                if (L_black[i] != L_black[i - 1]) break;
            }
            for (i = break_hangshu - 1; i >= 4; i--)
            {
                if (My_Abs(R_black[i], R_black[i - 1]) <= 4&&R_black[i]!=0)
                {
                //计算右边线的最终有效行数
                    calendright = i-1;
                  //  SetText("calendright " + calendright);
                    break;
                }
            }
            for (i = calendright; i >= 4; i--)
            {
                if (R_black[i] == R_black[i - 1]) calendright = i - 1;
                if (R_black[i] != R_black[i - 1]) break;
            }
        //    SetText("break_hangshu " + break_hangshu);
         //   SetText("calendleft " + calendleft);
         //   SetText("calendright " + calendright);
            if (calendleft >= 45) calendleft = 45;
            if (calendright >= 45) calendright = 45;
            //求开始点
            //int calbeginleft=0;
            //int calbeginright=0;
            //for (i = 0; i <= 12; i++)
            //{
            //    if (R_black[i] != 0)
            //    {
            //        calbeginright = i;
            //        break;
            //    }
            //}
            //for (i = 0; i <= 12; i++)
            //{
            //    if (L_black[i] != 186)
            //    {
            //        calbeginleft = i;
            //        break;
            //    }
            //}
            //SetText("calbeginleft " + calbeginleft);
          //  SetText("calbeginright " + calbeginright);
           // SetText(" L_black[calbeginleft]  " + L_black[calbeginleft]);
           // SetText("L_black[calendleft]  " + L_black[calendleft]);
            //SetText(" R_black[calbeginright]  " + R_black[calbeginright]);
            //SetText(" R_black[calendright]  " + R_black[calendright]);
            /*
          下面的代码是用来计算环岛的相关参数,进行辅助判断。
           */
            if (calendleft >= 20)
            {
            
                pianfangcal(0, calendleft, 1);
            }
            if (calendleft < 20)
            {
              pianfangcal(0, break_hangshu - 3, 1);
            }
            if (calendright >= 20)
            {
                pianfangcal(0, calendright, 2);
            }
            if (calendright < 20)
            {
                pianfangcal(0, break_hangshu - 3, 2);
            }
        }
        countprotect = 0;
        if (turepodaoflag == 0 && rukuflag == 0)  //坡道不退出  入库刹车10帧后自行退出
        {
            for (j = 0; j <= 185; j++)  //退出
            {
                if ((Pixels[0][ j]) == 0)
                {
                    countprotect = countprotect + 1;
                }
                if (countprotect == 186) { protect = 1; break; }
            }
        }
        rightopen = R_black[0];
        leftend = L_black[0];
    
    }
    

    二、辅助函数

    void advanced_regression(int type, int startline1, int endline1, int startline2, int endline2)
    {
        int i = 0;
        int sumlines1 = endline1 - startline1;
        int sumlines2 = endline2 - startline2;
        int sumX = 0;
        int sumY = 0;
        float averageX = 0;
        float averageY = 0;
        float sumUp = 0;
        float sumDown = 0;
        if (type == 0)  //拟合中线
        {
            /**计算sumX sumY**/
            for (i = startline1; i < endline1; i++)
            {
                sumX += i;
                sumY += LCenter[i];
            }
            for (i = startline2; i < endline2; i++)
            {
                sumX += i;
                sumY += LCenter[i];
            }
            averageX =(float)( sumX / (sumlines1 + sumlines2));     //x的平均值
            averageY = (float)(sumY / (sumlines1 + sumlines2));     //y的平均值
            for (i = startline1; i < endline1; i++)
            {
                sumUp += (LCenter[i] - averageY) * (i - averageX);
                sumDown += (i - averageX) * (i - averageX);
            }
            for (i = startline2; i < endline2; i++)
            {
                sumUp += (LCenter[i] - averageY) * (i - averageX);
                sumDown += (i - averageX) * (i - averageX);
            }
            if (sumDown == 0) parameterB = 0;
            else parameterB = sumUp / sumDown;
            parameterA = averageY - parameterB * averageX;
    
        }
        else if (type == 1)     //拟合左线
        {
            /**计算sumX sumY**/
            for (i = startline1; i < endline1; i++)
            {
                sumX += i;
                sumY += L_black[i];
            }
            for (i = startline2; i < endline2; i++)
            {
                sumX += i;
                sumY += L_black[i];
            }
            averageX =(float)( sumX / (sumlines1 + sumlines2));     //x的平均值
            averageY = (float)(sumY / (sumlines1 + sumlines2));     //y的平均值
            for (i = startline1; i < endline1; i++)
            {
                sumUp += (L_black[i] - averageY) * (i - averageX);
                sumDown += (i - averageX) * (i - averageX);
            }
            for (i = startline2; i < endline2; i++)
            {
                sumUp += (L_black[i] - averageY) * (i - averageX);
                sumDown += (i - averageX) * (i - averageX);
            }
            if (sumDown == 0) parameterB = 0;
            else parameterB = sumUp / sumDown;
            parameterA = averageY - parameterB * averageX;
        }
        else if (type == 2)         //拟合右线
        {
            /**计算sumX sumY**/
            for (i = startline1; i < endline1; i++)
            {
                sumX += i;
                sumY += R_black[i];
            }
            for (i = startline2; i < endline2; i++)
            {
                sumX += i;
                sumY += R_black[i];
            }
            averageX =(float)( sumX / (sumlines1 + sumlines2));     //x的平均值
            averageY = (float)(sumY / (sumlines1 + sumlines2));     //y的平均值
            for (i = startline1; i < endline1; i++)
            {
                sumUp += (R_black[i] - averageY) * (i - averageX);
                sumDown += (i - averageX) * (i - averageX);
            }
            for (i = startline2; i < endline2; i++)
            {
                sumUp += (R_black[i] - averageY) * (i - averageX);
                sumDown += (i - averageX) * (i - averageX);
            }
            if (sumDown == 0) parameterB = 0;
            else parameterB = sumUp / sumDown;
            parameterA = averageY - parameterB * averageX;
        }
    
    }
    
    void regression(int type, int startline, int endline)//最小二乘法拟合曲线,分别拟合中线,左线,右线,type表示拟合哪几条线   xy 颠倒
    {
        int i = 0;
        int sumlines = endline - startline;
        int sumX = 0;
        int sumY = 0;
        float averageX = 0;
        float averageY = 0;
        float sumUp = 0;
        float sumDown = 0;
        if (type == 0)      //拟合中线
        {
            for (i = startline; i < endline; i++)
            {
                sumX += i;
                sumY += LCenter[i];
            }
            if (sumlines != 0)
            {
                averageX = (float)(sumX / sumlines);     //x的平均值
                averageY =(float)( sumY / sumlines);     //y的平均值
            }
            else
            {
                averageX = 0;     //x的平均值
                averageY = 0;     //y的平均值
            }
            for (i = startline; i < endline; i++)
            {
                sumUp += (LCenter[i] - averageY) * (i - averageX);
                sumDown += (i - averageX) * (i - averageX);
            }
            if (sumDown == 0) parameterB = 0;
            else parameterB = sumUp / sumDown;
            parameterA = averageY - parameterB * averageX;
        }
        else if (type == 1)//拟合左线
        {
            for (i = startline; i < endline; i++)
            {
                sumX += i;
                sumY += L_black[i];
            }
            if (sumlines == 0) sumlines = 1;
            averageX = (float)(sumX / sumlines);     //x的平均值
            averageY =(float)( sumY / sumlines);     //y的平均值
            for (i = startline; i < endline; i++)
            {
                sumUp += (L_black[i] - averageY) * (i - averageX);
                sumDown += (i - averageX) * (i - averageX);
            }
            if (sumDown == 0) parameterB = 0;
            else parameterB = sumUp / sumDown;
            parameterA = averageY - parameterB * averageX;
        }
        else if (type == 2)//拟合右线
        {
            for (i = startline; i < endline; i++)
            {
                sumX += i;
                sumY += R_black[i];
            }
            if (sumlines == 0) sumlines = 1;
            averageX = (float)(sumX / sumlines);     //x的平均值
            averageY =(float)( sumY / sumlines);     //y的平均值
            for (i = startline; i < endline; i++)
            {
                sumUp += (R_black[i] - averageY) * (i - averageX);
                sumDown += (i - averageX) * (i - averageX);
            }
            if (sumDown == 0) parameterB = 0;
            else parameterB = sumUp / sumDown;
            parameterA = averageY - parameterB * averageX;
    
        }
    }
    
    //求两数之差绝对值开始
    int My_Abs(int a, int b)
    {
    
                if ((a - b) > 0)
         
                    return ((int)(a - b));
                else return ((int)(b - a));
    }
    
    
    void pianfangcal(int begin, int end, int type)
    {
    
    
        int i = 0;
        if (type == 1)//左线拟合差平方计算
        {
            pianfangleft = 0;
            regression (1, begin, end);
            monileftfuzhi(parameterA, parameterB,(int) begin,(int) end);
            for (i = begin; i <= end; i++)
            {
                pianfangleft = pianfangleft + (L_black[i] - monileft[i]) * (L_black[i] - monileft[i]);
            }
            pianfangleft = pianfangleft / (end - begin + 1);
        }
        if (type == 2)//右线拟合差平方计算
        {
            pianfangright = 0;
            regression(2, begin, end);
            monirightfuzhi(parameterA, parameterB,(int) begin,(int) end);
            for (i = begin; i <= end; i++)
            {
                pianfangright = pianfangright + (R_black[i] - moniright[i]) * (R_black[i] - moniright[i]);
            }
            pianfangright = pianfangright / (end - begin + 1);
        }
        if (type == 0)//右线拟合差平方计算
        {
            pianfangmid = 0;
            regression(0, begin, end);
            monizhongfuzhi(parameterA, parameterB, (int)begin, (int)end);
            int fangjun = 0;
            int junfang = 0;
            for (i = begin; i <= end; i++)
            {
                fangjun = fangjun + (LCenter[i]) * (LCenter[i]);
            }
            fangjun= fangjun / (end - begin + 1);
            for (i = begin; i <= end; i++)
            {
                junfang = junfang + (LCenter[i]);
            }
            junfang = junfang / (end - begin + 1);
            junfang = junfang * junfang;
            pianfangmid = fangjun - junfang;
        }
    
    }
    void monileftfuzhi(float A, float B, int start_point, int end_point)
    {
        int m;
        for (m = start_point; m <= end_point; m++)
        {
            if((B * m + A)>=255) monileft[m]=255;
            if((B * m + A)<=0) monileft[m]=0;
            else if(0<(B * m + A)&&(B * m + A)<255)monileft[m] = (int)(B * m + A);
        }
    }
    void monirightfuzhi(float A, float B, int start_point, int end_point)
    {
        int m;
        for (m = start_point; m <= end_point; m++)
        {
            if((B * m + A)>=255) moniright[m]=255;
            if((B * m + A)<=0) moniright[m]=0;
            else if(0<(B * m + A)&&(B * m + A)<255)moniright[m] = (int)(B * m + A);
        }
    }
    void monizhongfuzhi(float A, float B, int start_point, int end_point)
    {
        int m;
        for (m = start_point; m <= end_point; m++)
        {
            if ((B * m + A) >= 255) monimiddle[m] = 255;
            if ((B * m + A) <= 0) monimiddle[m] = 0;
            else if (0 < (B * m + A) && (B * m + A) < 255) monimiddle[m] = (int)(B * m + A);
        }
    }
    

    总结
    1.配合上辅助函数便是完整代码,如有不懂请留言哦。

    展开全文
  • 智能车中线程序

    千次阅读 多人点赞 2020-03-21 18:55:48
  • 对硬件和软件设计思路的介绍,以及对赛道的类型和赛道的提取都有详细的介绍,适合初学者看,帮助初学者理清思路。
  • 智能车摄像头组怎么在OLED屏画出中线

    千次阅读 多人点赞 2019-11-15 19:12:47
    通常,为了方便我们进行提取中线操作,会继续用数值0表示黑色,而数值255表示白色,再用一个二维数组image[][]表示。(只是种方法而已,不同的程序对摄像头返回数组的处理方法可能不一样。) ...

    首先你要知道二值化这个基本操作,不会的请去看资料。
    假设0 在OLED中代表黑色,1在OLED中代表白色。
    在这里插入图片描述
    首先对摄像头返回的数组进行解压,我这里解压到img[]这个数组,里面的元素要么是1,要么是0.

    在这里插入图片描述
    通常,为了方便我们进行提取中线操作,会继续用数值0表示黑色,而数值255表示白色,再用一个二维数组image[][]表示。(只是种方法而已,不同的程序对摄像头返回数组的处理方法可能不一样。)
    在这里插入图片描述
    定义三个数组,一个放左边沿的列值,一个放右边沿列值,一个放中线列值。
    这里对小白选手详细解释,以60*80像素为例,顾名思义,60行,80列。
    在这里插入图片描述

    这是一幅未拟合中线的二值化图片,上面已经说过在image[][]数组中,0代表黑色,255代表白色,那么在上面这幅图片中,我们随便选一行,假设这一行是25行,绿色标识
    在这里插入图片描述
    那么这一行的信息,在image[25][]中,肯定是000000000…255 255 255 255 255 255 … 00000000这样存储
    什么是跳变沿,跳变沿这个概念是数字电路中的,反映在物理背景上,就是你要找的白色赛道的边界,在程序中就是00 255 255这个交界处,这是左边沿,右边沿肯定是 255 255 00 处。不管你的程序用的什么方法提取边沿值,全行扫描法也好,边沿巡线法也好,rightedge[25]中的数值肯定右跳变沿像素所在的列值,假设是65,即代表第65列,leftedge[25]中的数值是左边沿像素所在的列值,假设是15,及代表是第15列。那么第25行中线列值即middleedge[25]=40,即第40列。
    这样,每一行都取到中线值。
    在这里插入图片描述
    然后呢,为了画中线,找到中线像素所在的位置,将这个位置的像素赋值为0,原像素为1,即白色像素更改为黑色像素。
    最后,调用OLED画图像函数
    在这里插入图片描述
    这样就成功了。

    总的来讲,流程是提取图像信息,寻找左右边沿线,拟合中线,更改中线所在位置各像素数值,调用画图函数。

    请问龙邱的彩色屏咋整,请去仔细学习像素的基本知识,推荐 数字图像处理 这本书。

    展开全文
  • 现有智能车识别算法大多都依赖于中线误差以控制智能汽车行驶,一旦应对无中线或者中线难以获取的道路就束手无策。针对该现状,对智能汽车随动系统进行了鲁棒性分析,在此基础上提出了具体的模糊方向控制策略,并通过...
  • 2010年校内赛CCD摄像头程序,注释详细,简单易懂,此程序经修改可以变得非常强大
  • 智能车摄像头_spiderqoo_摄像头算法处理_赛道识别_摄像头中线_智能车_源码.zip
  • 1、实战项目(找中线) 目标是从面对这种简单环境用opencv画出中线,下面是过程实现 2、opencv-python基于HSV抠图 这种环境看似简单,但是用灰度处理二值化的效果奇差,最后选择用HSV进行分割。 先导入包: ...
  • 本文档叙述了,“恩智浦”智能车大赛对赛道黑线提取的算法,以及去干扰
  • 第十六届全国大学生智能汽车比赛是我大学参加的第一个有意义的比赛,让我在学校实验室SCA打开了进入大学的大门,无数次的包夜和学习让我静下了心,很荣幸参加过这样一次的竞赛,收获颇丰。简单的做一个总结,算是画...
  • 智能车(摄像头)的图像处理主要就是识别出左右边线(一般边线是黑线,外边 是蓝布,中间赛道是白色),然后拟合出中线,让车子沿着中线跑。 ) 简单巡线 这里我使用左右寻线法来拟合中线,至于为什么不用八邻域法我...
  • 包含图像压缩、图像二值化、图像降噪和边界获取,中线补线以及OLED显示,不包含整车控制部分。
  • 参加这次智能车比赛,学到了很多。虽然成绩不是很好(三等奖)但是收获满满。这里特别提醒就是,一定一定一定仔细读比赛规则,今年我们就是规则没有仔细读,到比赛前3天才发现我们摄像头组是往返赛道,但是我们一直...
  • 智能车学习----最小二乘法求拟合曲线(中线)的斜率

    万次阅读 多人点赞 2019-04-18 21:30:03
    智能车为例把,我们平时得到的中线,可以说就是一些离散的点,它不是一条顺滑的曲线,而我们的拟合直线,则使用在中线和各种赛道元素补线上,在用中线做偏差处理时,将中线拟合一下,得到的 斜率偏差则是会更加...
  • 这篇文章主要讲述如何计算中线累积差值。 一、代码 //累差开始 void cumulants() { int i; cumulants1 = 0; cumulants2 = 0; for (i = 6; i <= 25; i++) { cumulants2 = cumulants2 + My_Abs(LCenter[i], ...
  • 首先分析图像,得到每一行上赛道边线或中线的坐标,如此得到一列离散点列 每一个点有一个横纵坐标,单位为像素,根据感光阵列的大小(若干毫米)将坐标变换到实际摄像头上,单位变为米,根据每个点的X、Y坐标计算出Z...
  • 飞思卡尔智能车之舵机算法

    万次阅读 多人点赞 2018-06-18 00:14:19
    恍恍惚惚,将近一年的智能车生涯终于结束了,虽然到目前为止我们的车子还是比不上学长的神车,但是也还算是对的起我们组一年的辛勤与努力了,为了给自己惨败的智能车比赛和还算完整的智能车学习生涯留下点东西。...
  • 智能车十字的识别与循迹过程
  • 带代码编辑器的Qt简单图像智能车上位机 目前还有很多bug,但是准备考研,也没时间继续完善了┭┮﹏┭┮ Content带代码编辑器的Qt简单图像智能车上位机前言一、系统界面二、使用步骤三、其它例子四、BUG总结 前言 ...
  • 外设模块 智能车采用总钻风摄像头对赛道信息检测,根据黑色边线提取赛道中线;通过编码器检测智能车的实时速度;使用 PID 控制算法调节电机的转速,实现智能车在运动过程中速度和方向的闭环控制;为了提高模型车的...
  • 18cm三轮摄像头图像处理前言比赛规则设备简述一、扫线方式(八领域)二级目录二、边线计算及处理方式二...第十五届全国大学生智能汽车竞赛竞速赛规则 可能由于疫情原因,比赛不仅提前了,而且准备时间还相比之前减少了
  • 智能车摄像头基本循迹控制
  • 讲解最基本的智能车图像运用
  • 智能车浅谈——方向控制篇

    千次阅读 多人点赞 2022-01-25 11:29:58
    智能车方向控制浅谈——自动控制原理角度,解析智能车转向控制中的舵机转向原理以及差速原理。
  • 智能车环岛浅析(电磁+摄像头)

    万次阅读 多人点赞 2019-06-19 22:09:16
    补线便是根据1和2点根据斜率连接,最小二乘法拟合得到相应的中线 1点 :右边界为直线,上一次左边界-这次左边界>10(这一行赛道宽度-上一行赛道宽度>10) 并记录下该行左边界位置,即为1点 2点: 前面有提到过,...
  • 智能车浅谈——图像篇

    万次阅读 多人点赞 2022-01-27 10:49:13
    智能车浅谈 ——图像处理篇,解析总钻风和神眼这类灰度摄像头的使用原理,结合OPENCV来梳理整个图像获取、二值化、压缩、巡线原理。
  • 恩智浦小白四轮组中线提取

    千次阅读 多人点赞 2019-04-14 23:17:48
    void get_certerline()//提取中线函数 0表示黑色,255表示白色 { uint8 i = 0,j = 0; uint8 middleline = 0; for (i = 0;i < 60;i ++)//0 - 60行 { //左边界扫描 for (j = 40; j >= 1;j --)//40-0列,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 592
精华内容 236
关键字:

智能车中线