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

前言

这篇文章主要讲述如何实现中线的扫描和二次扫线。
基础扫线效果图片如下
智能车图像处理1-中线的提取_第1张图片

一、变量声明

图像处理专栏中所使用的各种变量定义如下

//各种定义开始
//拟合
float parameterB; //斜率
float parameterA; //截距

//模拟赋值
int monileft[70];
int moniright[70];

//偏方左右
int pianfangleft = 0;
int pianfangright = 0;

//左右双断点
int16 leftduan1 = 0;
int16 leftduan2 = 0;
int16 newopenleft = 0;
int16 truedoubleleft = 0;

int16 rightduan1 = 0;
int16 rightduan2 = 0;
int16 newopen = 0;
int16 truedoubleright = 0;

//偏方满足
int16 truepianfangflag = 0;
int16 truepianfangflagforleft=0;

//扫中线
int16 zhongold=93;
int16 leftold=0;
int16 rightold=0;
int16 rightflag[70]={0,};
int16 leftflag[70]={0,};
int16 duanhang0=0;
int16 duanhang1=0;
int16 duanhangju=0;
int16 break_hangshu=0;
int16 countprotect=0;
int16 turepodaoflag = 0;
int16 rukuflag = 0;
int16 protect=0;

//左右线连续
int16 continueleft = 0;
int16 continueright = 0;

//坡道
float LK0end = 0;
float LK020 = 0;
float RK0end = 0;
float RKB020 = 0;
int16 podaoflag = 0;
int16 podaoflag2=0;
int16 kuandubreak = 0;
int16 podaotype2 = 0;
int16 lasttruepodaoflag = 0;
int16 countpodao = 0;
int16 truelongflag=0;

//入库
int16 type=0;
int firstku=0;
int haveleftku = 0;
int leftkuhang = 0;

int lastduanhang1 = 0;
int Llastduanhang1 = 0;

int countruku = 0;
int stopruku = 0;
int count3=0;

//宽度计算
int calkuan[70];

//环岛右
int flag_find_huan_leftdown_point = 0;
int flag_find_huan_rightdown_point = 0;
int flag_find_huan_leftmiddle_point = 0;
int flag_find_huan_rightmiddle_point = 0;
int flag_find_huan_rightup_point = 0;
int flag_find_huan_leftup_point = 0;
int ROUNDISLAND = 1;   //识别十字
int huandao_memory=0;
int Rhave0=0;
int right_turn_down[2]={0,};
int right_turn_up[2]={0,};
int left_turn_down[2]={0,};
int left_turn_up[2]={0,};
int right_turn_middle[2];
int left_turn_middle[2];
int huandao_flag_R_L=0;
int huandao_flag = 0;
int huandao_procedure_variable = 0;
int huandao_memoryforleft=0;
int flag_rukou2 = 0;
int flag_rukou = 0;
int last_memory=0;

//右环岛左线
int jiansu_flag = 0;
int flag_blank_out_huandao = 0;

//右环岛右线

//左环岛主体
int lcenter_5=0;
int last_memoryforleft=0;

//斜入十字
int rightdownflag3=0;
int leftdownflag3=0;
int rightupflag3=0;
int leftupflag3=0;
int firstmid=0;
int8 CROSSROAD = 0;

//正入十字
int rightdownflag=0;
int rightupflag=0;
int leftdownflag=0;
int leftupflag=0;
int secondmid=0;
int buzhongxianmax = 0;
int buzhongxianmin = 0;

//小s

int turesmallsflag=0;
int countstoplongg = 0;
int flag_centre_right_point = 0;
int flag_centre_left_point = 0;
int centre_left_point[2];
int centre_right_point[2];
int swrong = 0;
int overflag = 0;
int flag_middle_S=0;
int flag_small_S=0;
int findturn = 0;
int finddirection = 0;//1左转弯 2右转弯
int min;
int max;
int LongLCenter[70]={0,};

//中s
int trueflag_middle_S = 0;
int last1trueflag_middle_S=0;
int last2trueflag_middle_S=0;

//长直道


int countstoplong = 0;

int stoplong= 0;
int overlong=0;
int overlongwrong=0;
int changzhenshu=24;
int lastturesmallsflag=0;
int stopsmalls=0;
int countstopsmalls=0;
int truelong1=0;
int truelong2=0;
int turedian=0;
int kthird=0;
int lasttruelong2 = 0;
int longflag=0;
int thirdmid=0;
int trueshortflag=0;

//环岛快速进入
float R020K = 0;
float L020K=0;

//十字防断
int bannothing=0;
int LCenterrecord[70];
int leftrecord[70];
int rightrecord[70];
int countbannothing = 0;

//二次十字
int se_thrmid = 0;


//三岔路口
int16 threemode=0;

//各种计数
int huandaotype=0;

//累差
int16 cumulants1;
int16  cumulants2;
int16 openright;
int16 endright;

二、函数主体

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

你可能感兴趣的:(智能车图像处理,图像处理,动态规划,人工智能)