智能车图像处理1-中线的提取

前言

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

一、函数主体

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.配合上辅助函数便是完整代码,如有不懂请留言哦。

猜你喜欢

转载自blog.csdn.net/taiyuezyh/article/details/122773779#comments_20975587