精华内容
下载资源
问答
  • #include int main() ...int a[5][5],i,j,s=0; for(i=0;i  for(j=0;j if(i==j) a[i][j]=1; else a[i][j]=0; for(i=0;i for(j=0;j { if(j==0) printf("\n"); printf("%d",a[i][j]); } }
    #include<stdio.h>
    
    int main()
    {
    int a[5][5],i,j,s=0;
    for(i=0;i<5;i++)
        for(j=0;j<5;j++)
    if(i==j)
    a[i][j]=1;
    else a[i][j]=0;
    for(i=0;i<5;i++)
    for(j=0;j<5;j++)
    {
    if(j==0) printf("\n");
    printf("%d",a[i][j]);
    }
    }
    展开全文
  • #获取5日10日,20日均线数据 import tushare as ts import talib from matplotlib import pyplot as plt #通过tushare获取股票信息 df=ts.get_k_data('601888',start='2018-01-30',end='2018-10-30') #以股票...
    #获取5日,10日,20日均线数据
    
    import tushare as ts
    import talib
    from matplotlib import pyplot as plt
    
    #通过tushare获取股票信息
    df=ts.get_k_data('601888',start='2018-01-30',end='2018-10-30') #以股票代码[601888]中国国旅为例,提取从2018-01-12到2018-10-30的收盘价
        #提取收盘价
    closed=df['close'].values
        #获取均线的数据,通过timeperiod参数来分别获取 5,10,20 日均线的数据。
    ma5=talib.SMA(closed,timeperiod=5)
    ma10=talib.SMA(closed,timeperiod=10)
    ma20=talib.SMA(closed,timeperiod=20)
    
        #打印出来每一个数据
    print (closed)
    print (ma5)
    print (ma10)
    print (ma20)
    
        #通过plog函数可以很方便的绘制出每一条均线
    plt.plot(closed)
    plt.plot(ma5)
    plt.plot(ma10)
    plt.plot(ma20)
        #添加网格,可有可无,只是让图像好看点
    plt.grid()
        #记得加这一句,不然不会显示图像
    plt.show()
    
    

    展开全文
  • 目录前言基本扫线(除了进入环岛状态或者坡道或者十字路口的普通扫线)基本数据初步特征进一步特征提取1、计算并且显示前n行左右线各丢失数目(不breakbreak的都有)2、计算左右线方差(以右线为例)【a】计算右...

    博主联系方式:
    QQ:1540984562
    微信:wxid_nz49532kbh9u22 QQ交流群:892023501

    目录

    【没事儿可以到我主页看看】https://blog.csdn.net/qq_42604176

    1、系列文章

    【智能车Code review】—曲率计算、最小二乘法拟合
    【智能车Code review】——坡道图像与控制处理
    【智能车Code review】——拐点的寻找
    【智能车Code review】——小S与中S道路判断
    【智能车Code review】——环岛的判定与补线操作
    智能车复工日记【1】——菜单索引回顾
    智能车复工日记【2】——普通PID、变结构PID、微分先行PID、模糊PID、专家PID
    智能车复工日记【3】:图像处理——基本扫线和基本特征提取和十字补线
    智能车复工日记【4】:关于图像的上下位机的调整问题总结
    智能车复工日记【5】:起跑线的识别与车库入库
    智能车复工日记【6】:有bug的模糊PID记录
    智能车复工日记【7】:关于会车的图像问题
    智能车复工日记【N】:图像处理——环岛debug记录(持续更新)

    2、前言

    图像大小185*70,通过扫线获取左右两边数据,然后左加右除以二得到中线值。(降维处理)
    数据

    3、基本扫线(除了进入环岛状态或者坡道或者十字路口的普通扫线)

    基本思路:从下往上扫,从中间往两边扫。上一行的中线值记录下来,作为这一行往两边扫的起始值
    需要注意的点:
    1、判断边界的条件:连续有两个是黑,则判断较远的为边界,此时就需要注意数组越界的问题。
    2、边界数组大小为70,和图像的高一样,意味着,每行只能有一个边界,所以当出现下面情况,边界就会不完整。
    环岛
    3、当这一行的中线是黑的且下一行同一列也是黑的,退出循环,表明后面的数据不进行采集。(这说明已经采集到的赛道外面了)。并且为了防止提前断线,我们限制二十行以下不进行break处理。

    	for (j = 0; j < 70; j++)
    	{
    	 for (i = (byte)old; i >= 0 && i < 184; i++)
    	 {
    	     fiv_width[j]++;
    	     if (Pixels[j, i + 1] == 0 && Pixels[j, i] == 0)
    	     {
    	         leftfindflag[j] = 1;
    	         lefetline[j] = (byte)(i + 1);
    	         break;
    	     }
    	 }
    	 for (i = (byte)old; i <= 185 && i > 1; i--)
    	 {
    	     fiv_width[j]++;
    	     if (Pixels[j, i - 1] == 0 && Pixels[j, i] == 0)
    	     {
    	         rightfindflag[j] = 1;
    	         rightline[j] = (byte)(i - 1);
    	         break;
    	     }
    	 }
    	 if (j <= 50 && leftfindflag[j] == 1 && rightfindflag[j] == 1) flag_s++;
    	 if (j <= 25 && leftfindflag[j] == 0 && rightfindflag[j] == 0) times++;
    	 if (j >= 20 && (lefetline[j] - lefetline[j - 1]) <= -20) leftline_duan_dian = j;
    	 if (j >= 20 && (rightline[j] - rightline[j - 1]) >= 20) rightline_duan_dian = j;             
    	 centerline[j] = (byte)((lefetline[j] + rightline[j]) / 2);
    	 if ((Pixels[j, centerline[j]]) == 0 && (Pixels[j + 1, centerline[j]]) == 0)
    	 {
    	     break_hangshu = j;
    	     //last_break_hangshu = break_hangshu;
    	     //也就是说二十行一下是不会break的
    	     if (break_hangshu >= 20)    //防止在一开始就break
    	     {
    	         break;
    	     }
    	 }
    	 old = centerline[j];
    	}
    	SetText("在多少行break(初次扫线): " + break_hangshu);
    	SetText("rightline_duan_dian" + rightline_duan_dian);
    	SetText("leftline_duan_dian" + leftline_duan_dian);
    	old = centerline[5];    //初次扫线完毕,将old重新赋值
    	
    

    1.基本数据和初步特征

    现在来看看我们初步基本扫线我们收集到的基本数据:

    1、左线值:lefetline
    2、右线值:rightline
    3、中线值:centerline
    4、每行赛道宽度:fiv_width
    5、每行左线点是否扫到:leftfindflag
    6、每行右线点是否扫到:rightfindflag
    7、中线断开的目标行:break_hangshu
    8、50行以内两边都扫到的次数:flag_s
    9、25行以内两边全丢的次数:times
    10、20行以上左线突然性断裂的目标行:leftline_duan_dian
    11、20行以上右线突然性断裂的目标行:rightline_duan_dian

    观察可得,其实最主要的数据藏在三条线数组中,其他的特征都是围绕着三线的,接下来我们进一步提取特征。

    4、进一步特征提取

    1、计算并且显示前n行左右线各丢失数目(不break和break的都有)

    不break的是lost_times,break的是起始空白行r_start(l_start)
    lostleft_times:前n行左线未扫到的次数
    lostright_times:前n行右线未扫到的次数
    (这里和上面的初步提取有些许重复之处)
    l_start:在l_start以下的左线全是未扫到
    r_start:在r_start以下的右线线全是未扫到
    形象看,其实就是这两个点:
    点

    void Cal_losttimes(int times)
    {
        byte i;
        byte flag_of_rightbreak = 0;
        byte flag_of_leftbreak = 0;
        for (i = 0; i < times; i++)
        {
            //左线操作
            if (leftfindflag[i] == 0)       //未扫到线
            {
                lostleft_times++;
                if (flag_of_leftbreak == 0)     //如果在这一行之前没有遭遇断线,则计数
                {
                    l_start++;
                }
            }
            else    //扫到线
            {
                //lostleft_times不继续增加
                flag_of_leftbreak = 1;  //break标志成立
            }
            //右线操作
            if (rightfindflag[i] == 0)       //未扫到线
            {
                lostright_times++;
                if (flag_of_rightbreak == 0)     //如果在这一行之前没有遭遇断线,则计数
                {
                    r_start++;
                }
            }
            else    //扫到线
            {
                //lostright_times不继续增加
                flag_of_rightbreak = 1;  //break标志成立
            }
        }
        SetText(" lostleft_times " + lostleft_times);
        SetText(" lostright_times " + lostright_times);
        SetText("L_start: " + l_start);
        SetText("R_start: " + r_start);
    }
    

    2、计算左右线方差(以右线为例)

    【a】计算右线曲率(选三个点:r_start、中点、break点)

    byte curvity_point1 = (byte)((r_start + break_hangshu) / 2);		//中点
    byte curvity_point2 = 0;
    if (break_hangshu >= 5)
    {
        curvity_point2 = (byte)(break_hangshu - 3);
    }
    else
    {
        curvity_point2 = (byte)(break_hangshu);
    }
    curvity_right = process_curvity(rightline[r_start], r_start, rightline[curvity_point1], curvity_point1, rightline[curvity_point2], curvity_point2);
    

    【b】如果右线曲率在一定的范围,就从空白行开始进行右线拟合,从空白行开始计算斜率,否则则从0行开始拟合和计算

    //曲率接近0说明线挺直的,为了体现直线方差小的特点,从第start行开始计算
     if (curvity_right > -0.4 && curvity_right < 0.1 && r_start <= 32 && (break_hangshu - r_start) >= 7)
     {
         regression(2, r_start, break_hangshu);    //拟合右线
         k_right = parameterB;
         SetText("右线斜率:" + k_right);
         Cal_Line(k_right, parameterA,0, break_hangshu, FORE_RIGHT);
         for (i = r_start; i < break_hangshu - 5; i++)
         {
             rou_of_right += (forecast_rightline[i] - rightline[i]) * (forecast_rightline[i] - rightline[i]);
         }
     }
    //否则说明边界是曲线,此时为了凸显出曲线的方差大的特点,从第0行开始计算
     else
     {
         regression(2, 0, break_hangshu);    //拟合右线
         k_right = parameterB;
         SetText("右线斜率:" + k_right);
         Cal_Line(k_right, parameterA, 0, break_hangshu,FORE_RIGHT);
         for (i = 0; i < break_hangshu - 5; i++)
         {
             rou_of_right += (forecast_rightline[i] - rightline[i]) * (forecast_rightline[i] - rightline[i]);
         }
     }
    

    3、对初步扫出的线进行分析连续性(对左右线)

    参数:起始点,结束点,正阈值。负阈值。

    juge_lineContinuity(10,60,5,-5,LEFT);
    SetText(“左线long_turn_flag:” +long_turn_flag_left);
    //10-60行左线这一行减去上一行在-5到+5范围内则认为是连续,否则记录break的点。

    void juge_lineContinuity(byte start_point, byte end_point,int positive_T,int negatie_T,byte ArryName)
    {
        byte j;
        switch (ArryName)
        {
            case 0:     //CENTER
                {
                    for (j = start_point; j < end_point; j++)//从第10行开始,防止下面提早断掉,影响判断
                    {
                        center_delta = centerline[j + 1] - centerline[j];       //left线的偏差
                        if (center_delta >= positive_T || center_delta <= negatie_T)
                        {
                            long_turn_flag = j;
                            break;
                        }
                        else
                        {
                            if (j >= end_point - 1)
                            {
                                long_turn_flag = end_point;
                            }
                        }
                    }
                }
                break;
            case 1:     //LEFT
                {
                    for (j = start_point; j < end_point; j++)//从第10行开始,防止下面提早断掉,影响判断
                    {
                        left_delta = lefetline[j + 1] - lefetline[j];       //left线的偏差
                        if (left_delta >= positive_T || left_delta <= negatie_T)
                        {
                            long_turn_flag_left = j;
                            break;
                        }
                        else 
                        {
                            if (j>= end_point-1)
                            {
                                long_turn_flag_left = end_point;
                            }   
                        }
                    }
                }
                break;
            case 2:     //RIGHT
                {
                    for (j = start_point; j < end_point; j++)//从第10行开始,防止下面提早断掉,影响判断
                    {
                        right_delta = rightline[j + 1] - rightline[j];       //left线的偏差
                        if (right_delta >= positive_T || right_delta <= negatie_T)
                        {
                            long_turn_flag_right = j;
                            break;
                        }
                        else
                        {
                            if (j >= end_point - 1)
                            {
                                long_turn_flag_right = end_point;
                            }
                        }
                    }
                }
                break;
            default:
                {
                    for (j = start_point; j < end_point; j++)//从第10行开始,防止下面提早断掉,影响判断
                    {
                        center_delta = centerline[j + 1] - centerline[j];       //left线的偏差
                        //大于偏差,break,记录break点
                        if (center_delta >= positive_T || center_delta <= negatie_T)
                        {
                            long_turn_flag = j;
                            break;
                        }
                        //小于偏差,若是大于end点,则记录end点,否则不做操作
                        else
                        {
                            if (j >= end_point - 1)
                            {
                                long_turn_flag = end_point;
                            }
                        }
                    }
                }
                break;
        }
    }
    

    4、计算判断环岛需要的参数(在坡道状态时不进行此部分运算)

    【A1】在2-50行内找右下拐点

    【A2】在2-50行内找左下拐点

    【B1】找右中拐点,分为两种情况,一种右下找到了,一种是右下没找到,右下找到的话就从右下开始往上找,右下没找的话就从8行开始往上找

    【B2】找左中拐点,分为两种情况,一种左下找到了,一种是左下没找到,左下找到的话就从左下开始往上找,左下没找的话就从8行开始往上找

    【C1】找右上拐点。一种右中找到了,一种是右中没找到,右中找到的话就从右中开始往上找,右中没找的话就从25行开始往上找

    【C2】找左上拐点。一种左中找到了,一种是左中没找到,找到的话就从左中开始往上找,左中没找的话就从25行开始往上找

    if (podao_flag == 0)
    {
        /***【A1】找右下拐点***********/
        find_rightdown_point(2, 50, ROUNDISLAND);
        SetText("右下拐点:" + right_turn_down[0] + " " + right_turn_down[1]);
        /***【A2】找左下拐点***********/
        find_leftdown_point(2, 50, ROUNDISLAND);
        SetText("左下拐点:" + left_turn_down[0] + " " + left_turn_down[1]);
        //【B1】找右中拐点,分为两种情况,一种右下找到了,一种是右下没找到,右下找到的话就从右下开始往上找,右下没找的话就从8行开始往上找
        if (flag_find_huan_rightdown_point == 1 && huandao_memory != 5)
        {
            SetText("从右下开始网上找右中");
            find_rightmiddle_point((byte)(right_turn_down[0] + 5), 60);
        }
        else
        {
            SetText("从第八行开始网上找右中");
            find_rightmiddle_point(8,60);
        }
        if (right_turn_middle[0] != 0 && huandao_memory != 4) flag_find_huan_rightmiddle_point = 1;
        SetText("右中拐点:" + right_turn_middle[0] + " " + right_turn_middle[1]);
        //【B2】找左中拐点,分为两种情况,一种左下找到了,一种是左下没找到,左下找到的话就从左下开始往上找,左下没找的话就从8行开始往上找
        if (flag_find_huan_leftdown_point == 1 && huandao_memory != 5 && huandao_memory != 3)
        {
            SetText("从左下开始往上找左中");
            find_leftmiddle_point((byte)(left_turn_down[0] + 5), 60);
        }
        else
        {
            SetText("从第八行开始网上找左中");
            find_leftmiddle_point(8, 60);
        }
        if (left_turn_middle[0] != 0 && huandao_memory != 4) flag_find_huan_leftmiddle_point = 1;
        SetText("左中拐点:" + left_turn_middle[0] + " " + left_turn_middle[1]);
        //【C1】找右上拐点。前提是中拐点一定存在!!
        if (flag_find_huan_rightmiddle_point == 1 && right_turn_middle[0] < 45 && huandao_memory != 4 && huandao_memory != 5 && huandao_memory != 7 && huandao_memory != 8)  //右中拐点存在
        {
            SetText("从右中开始往上找");
            find_rightup_point((byte)(right_turn_middle[0] + 5), 62, ROUNDISLAND);
        }
        else
        {
            SetText("从第25行开始往上找");
            find_rightup_point(25, 62, ROUNDISLAND);
        }
        //【C2】找左上拐点。前提是中拐点一定存在!
        if (flag_find_huan_leftmiddle_point == 1 && left_turn_middle[0] < 45 && huandao_memory != 4 && huandao_memory != 5 && huandao_memory != 7 && huandao_memory != 8)  //左中拐点存在
        {
            SetText("从左中开始往上找");
            find_leftup_point((byte)(left_turn_middle[0] + 5), 62, ROUNDISLAND);
        }
        else
        {
            SetText("从第25行开始往上找");
            find_leftup_point(25, 62, ROUNDISLAND);
        }
        SetText("右上拐点:" + right_turn_up[0] + " " + right_turn_up[1]);
        SetText("左上拐点:" + left_turn_up[0] + " " + left_turn_up[1]);
    
    }
    

    5、计算判断十字需要的参数(在坡道或环岛状态时不进行此部分运算)

    【A】初步找四个拐点(上拐点部分情况下是不准的)

    【B】分情况讨论:1、入十字之前,用下拐点和上拐点拉2、入十字了,用两个上拐点拉下来

    这里将times <6时判断为 入十字前
    将times > 6 && (l_start > 15 && r_start > 15 && My_Abs(l_start - r_start) <= 8时判断为 入十字后

    【C1】入十字之前的操作

    【1】:如果找到两个下拐点,求出两处线的趋势。
    【2】:如果趋势相同说明是弯道,此时将拐点记录为弯道拐点,以后判断问号弯时需要用到。
    【3】:当左下拐点存在且(趋势不同或右边丢失数>25)认为左下拐点是真的拐点。
    【4】:右下拐点同样如此推断。
    【5】:当找到左下或右下拐点后,拟合并预测中线(通过对两个下拐点的确认程度可以判断出是左斜入十字、右斜入十字、正入十字),然后再顺着预测后的中线往两边重新扫线。(此时的扫线不需要对times和flag_s进行计数,只对三线数组和break行数进行覆盖操作,以及边线flag数组的先清零后覆盖的操作,注意如果此时的break行数比原来的低,则原本的高于break行数的三线数据将会保存)
    【6】:对新扫出来的边界进行寻找上拐点操作(由于第一次扫线有误,所以上拐点位置大概率是错误的,需要重新检测)
    【7】:开始补线(由于小s误判原因,这里加入限制:假如小s的flag为1就不进行补线操作,防止出错)
    【8】:直到确认了要补线,我才将十字flag置1,也就是说此时才真正确认是十字状态
    【9】:左右两边同时操作,同时找到上下拐点,用上下拐点附近的值拟合k和b,然后补线。只找到下拐点,则用下拐点的附近的值拟合k和b,然后补线
    【10】:将补完的线存入双线数组,并且求出中线值

    【C2】入十字后的操作

    【1】:因为入十字了有许多空白行,会导致中线不准,沿中线往两边扫描得到的拐点也会不准,所以需要重新扫线,此时选择固定行扫线,且times和flag_s不再计数
    【2】:重新找上拐点,且找到的上拐点必须大于原本的下拐点
    【3】:如果上拐点存在,则进行补线。然后将十字flag置1

    if (huandao_flag == 0 && podao_flag == 0)//不是环岛
    {
        /****【A】初步找拐点(必然是不准的,需要滤波)****/
        /***【a1】找左下拐点***********/
        find_leftdown_point(2,40, CROSSROAD);
        /***【a2】找左上拐点***********/
        find_leftup_point(5, 50, CROSSROAD);
        /***【a3】找右下拐点***********/
        find_rightdown_point(2, 40, CROSSROAD);
        /***【a4】找右上拐点***********/
        find_rightup_point(5, 50, CROSSROAD);
        /**********显示出初步找到的拐点****************/
        SetText("左下拐点         " + "左上拐点         " + "右下拐点         " + "右上拐点         ");
        SetText("          " + left_turn_down[0] + "     " + left_turn_down[1] + "          " + left_turn_up[0] + "     " + left_turn_up[1] + "          " + right_turn_down[0] + "     " + right_turn_down[1] + "          " + right_turn_up[0] + "     " + right_turn_up[1] + "           ");
        /**************【B】分情况讨论*****************/
        /********【b1】入十字之前,用下面的点和上面的点拉************/
        if (times <= 6)
        {
            //如果找到左下或者右下拐点,此时检测左右线趋势
            float trend_of_left = 0;
            float trend_of_right = 0;
            //时时注意拐点坐标第一个是行数+1,处理时要做减一处理
            if (left_turn_down[0] != 0 || right_turn_down[0] != 0)
            {
                if (left_turn_down[0] != 0 && right_turn_down[0] == 0)//左下拐点存在而右下拐点不存在
                {
                    regression(1, left_turn_down[0] - 3, left_turn_down[0] + 2);//左线
                    trend_of_left = parameterB;
                    regression(2, left_turn_down[0] - 3, left_turn_down[0] + 2);//右线
                    trend_of_right = parameterB;
                }
                else if (right_turn_down[0] != 0 && left_turn_down[0] == 0)    //右下拐点存在而左下拐点不存在
                {
                    regression(1, right_turn_down[0] - 3, right_turn_down[0] + 2);//左线
                    trend_of_left = parameterB;
                    regression(2, right_turn_down[0] - 3, right_turn_down[0] + 2);//右线
                    trend_of_right = parameterB;
                }
                else if (left_turn_down[0] != 0 && left_turn_down[0] != 0)   //左右拐点均存在
                {
                    regression(1, left_turn_down[0] - 3, left_turn_down[0] + 2);//左线
                    trend_of_left = parameterB;
                    regression(2, right_turn_down[0] - 3, right_turn_down[0] + 2);//右线
                    trend_of_right = parameterB;
                }
            }
            twolines_trend = juge_if_same_fuhao(trend_of_left, trend_of_right);
            //大弯道拐点
            if (twolines_trend == 0)
            {
                if (left_turn_down[0] != 0 && right_turn_down[0] == 0)//左下拐点存在而右下拐点不存在
                {
                    curve_guai[0] = left_turn_down[0];
                    curve_guai[1] = centerline[left_turn_down[0]];
                }
                else if (right_turn_down[0] != 0 && left_turn_down[0] == 0)    //右下拐点存在而左下拐点不存在
                {
                    curve_guai[0] = right_turn_down[0];
                    curve_guai[1] = centerline[right_turn_down[0]];
                }
                else if (left_turn_down[0] != 0 && left_turn_down[0] != 0)   //左右拐点均存在
                {
                    curve_guai[0] = (right_turn_down[0] + left_turn_down[0]) / 2;
                    curve_guai[1] = centerline[(right_turn_down[0] + left_turn_down[0]) / 2];
                }
                //if (curve_guai[0] != 0) SetText("弯道拐点: " + curve_guai[0] + "  " + curve_guai[1]);
            }
            SetText("trend_of_left:     " + trend_of_left + "         trend_of_right:    " + trend_of_right);
            //经过限制后的下拐点   首先是存在拐点,并且两条线趋势相异,或上相异的线丢失了
            if ((left_turn_down[0] != 0 && twolines_trend == 1) || (lostright_times >= 25 && left_turn_down[0] != 0))
            {
                SetText("新的左下拐点         ");
                SetText("          " + left_turn_down[0] + "     " + left_turn_down[1]);
                findleftdownguai = 1;   //表示找到左下拐点了                
            }
            else findleftdownguai = 0;
            if ((right_turn_down[0] != 0 && twolines_trend == 1) || (lostleft_times >= 25 && right_turn_down[0] != 0))
            {
                SetText("新的右下拐点         ");
                SetText("          " + right_turn_down[0] + "     " + right_turn_down[1]);
                findrightdownguai = 1;//表示找到右下拐点了                
            }
            else findrightdownguai = 0;
            /*************找到左下或右下拐点后,拟合并预测中线,然后再顺着预测后的中线找**************/
            if (findrightdownguai == 1 || findleftdownguai == 1)
            {
                SetText("拟合预测中线   ");
                int start = 0;
                int end = 0;
    
                if (findrightdownguai == 1 && findleftdownguai == 0)//左斜入十字,仅有右下拐点,取右下拐点下的中线行
                {
                    SetText("左斜入十字 ");
                    start = right_turn_down[0] - 12;
                    end = right_turn_down[0] - 1;
                    if (start <= 0) start = 0;
                    if (end <= 1) end = 1;
                    regression(0, start, end);
                    parameterB = parameterB + 0.3f;
                }
                else if (findrightdownguai == 0 && findleftdownguai == 1) //右斜入十字,仅有左下拐点,取左下拐点下的中线行
                {
                    SetText("右斜入十字 ");
                    start = left_turn_down[0] - 12;
                    end = left_turn_down[0] - 1;
                    if (start <= 0) start = 0;
                    if (end <= 1) end = 1;
                    regression(0, start, end);
                    parameterB = parameterB - 0.3f;
                }
                else if (findrightdownguai == 1 && findleftdownguai == 1) //正入十字:用两个下拐点中最小行下的中线行,拟合出k,b,进而拟合出预测中线
                {
                    SetText("正入十字 ");
                    start = My_Min(left_turn_down[0], right_turn_down[0]) - 12;
                    end = My_Min(left_turn_down[0], right_turn_down[0]) - 1;
                    if (start <= 0) start = 0;
                    if (end <= 1) end = 1;
                    regression(0, start, end);       //start是0,end是左下拐点和右下拐点的平均行数
                }
                //这样得出了拟合出的k和b
                //预测新的中线值
                //这时候forecast_centerline
                SetText("拟合出了中线   ");
                for (i = 0; i < 70; i++)
                {
                    forecast_centerline[i] = overflow((int)(parameterB * i + parameterA));
                    if (forecast_centerline[i] >= 185 || forecast_centerline[i] <= 0)
                    {
                        break_hangshu = i;
                        break;
                    }
                    R_Start[i] = forecast_centerline[i];
                    //SetText(forecast_centerline[i]);
                }
                second_scan_flag = 1;
            }
            /********************第二次扫线(顺着预测出来的点往两边扫)********************/
            //这时就不需要计数times和flag_s了
            if (second_scan_flag == 1)
            {
                SetText("顺着预测出来的点往两边扫 ");
                for (j = 0; j < 70; j++)
                {
                    leftfindflag[j] = 0;
                    rightfindflag[j] = 0;
                    for (i = (byte)forecast_centerline[j]; i >= 0 && i < 184; i++)
                    {
                        if (Pixels[j, i + 1] == 0 && Pixels[j, i] == 0)
                        {
                            leftfindflag[j] = 1;
                            lefetline[j] = (byte)(i + 1);
                            break;
                        }
                    }
                    for (i = (byte)forecast_centerline[j]; i <= 185 && i > 1; i--)
                    {
                        if (Pixels[j, i - 1] == 0 && Pixels[j, i] == 0)
                        {
                            rightfindflag[j] = 1;
                            rightline[j] = (byte)(i - 1);
                            break;
                        }
                    }
                    if (leftfindflag[j] == 0 && rightfindflag[j] != 0) lefetline[j] = 185;
                    if (rightfindflag[j] == 0 && leftfindflag[j] != 0) rightline[j] = 0;
                    centerline[j] = (byte)((lefetline[j] + rightline[j]) / 2);
                    if ((Pixels[j, centerline[j]]) == 0 && (Pixels[j + 1, centerline[j]]) == 0)
                    {
                        break_hangshu = j;
                        SetText("补完线的breakhangshu:" + break_hangshu);
                        if (break_hangshu >= 20)    //防止在一开始就break
                        {
                            break;
                        }
                        break;
                    }
    
                }
                //把break行以上的数据清除(也可以选择不清)
                for (j = break_hangshu; j < 70; j++)
                {
                    lefetline[j] = 185;
                    rightline[j] = 0;
                }
                //由于第一次扫线有误,所以上拐点位置大概率是错误的,需要重新检测
                //首先清零(也可以选择不清)
                //left_turn_up[0] = 0;
                //left_turn_up[1] = 0;
                //right_turn_up[0] = 0;
                //right_turn_up[1] = 0;
                /*************扫完第二次线,再找上拐点****************************/
                /***找左上拐点***********/
                for (j = 2; j <= 55; j++)
                {
                    //左上拐点
                    if (((j > (byte)left_turn_down[0]) && lefetline[j] - lefetline[j - 1] <= -3 && My_Abs(lefetline[j + 1] - lefetline[j]) <= 2 && My_Abs(lefetline[j + 2] - lefetline[j + 1]) <= 2)
                        || ((j > (byte)left_turn_down[0]) && lefetline[j - 2] - lefetline[j] >= 50 && lefetline[j - 1] - lefetline[j] >= 50 && My_Abs(lefetline[j + 1] - lefetline[j]) <= 3)
                        && leftfindflag[j] == 1 && leftfindflag[j + 1] == 1 && leftfindflag[j + 2] == 1)
                    {
    
                        left_turn_up[0] = j + 1;//数组里面没有第0行
                        left_turn_up[1] = lefetline[j];
                        //获得的上坐标先确定一下是不是比下坐标小,如果小则说明提前断掉,此时的“上拐点”为假.
                        //如果比下坐标大则此时的“上拐点”为真.
                        if (left_turn_up[0] <= left_turn_down[0])
                        {
                            ;
                        }
                        else break;
                    }
                }
                /***找右上拐点***********/
                for (j = 2; j <= 55; j++)
                {
                    if (((j > (byte)right_turn_down[0]) && (rightline[j] - rightline[j - 1]) >= 3 && My_Abs(rightline[j + 1] - rightline[j]) <= 2 && My_Abs(rightline[j + 2] - rightline[j + 1]) <= 2)
                   || ((j > (byte)right_turn_down[0]) && rightline[j - 2] - rightline[j] <= -50 && rightline[j - 1] - rightline[j] <= -50 && My_Abs(rightline[j + 1] - rightline[j]) <= 3)
                   && (rightfindflag[j] == 1 && rightfindflag[j + 1] == 1 && rightfindflag[j + 2] == 1))
                    {
                        right_turn_up[0] = j + 1;
                        right_turn_up[1] = rightline[j];
                        if (right_turn_up[0] <= right_turn_down[0])
                        {
                            ;
                        }
                        else break;
                    }
                }
                if (right_turn_up[0] > right_turn_down[0] && right_turn_up[0] != 0)
                {
                    SetText("新的右上拐点         ");
                    SetText("          " + right_turn_up[0] + "     " + right_turn_up[1]);
                    findrightupguai = 1;//表示找到右上拐点了                
                }
                if (left_turn_up[0] > left_turn_down[0] && left_turn_up[0] != 0)
                {
                    SetText("新的左上拐点         ");
                    SetText("          " + left_turn_up[0] + "     " + left_turn_up[1]);
                    findleftupguai = 1;//表示找到左上拐点了                
                }
            }
            /*********开始补线(找到左下拐点和左上拐点  或 找到右下拐点和右上拐点)*********/
            if (flag_small_S == 0 && (findleftupguai == 1 && findleftdownguai == 1) || (findrightupguai == 1 && findrightdownguai == 1) || (findrightupguai == 1 && findrightdownguai == 0) || (findleftupguai == 1 && findleftdownguai == 0))
            {
                flag_shizi = 1;
                if (findleftupguai == 1 && findleftdownguai == 1)        //找到左下拐点和左上拐点,拟合所需的点是下拐点下面三个点和上拐点上面三个点
                {
                    int start1 = left_turn_down[0] - 3;
                    if (start1 <= 0) start1 = 0;
                    int end1 = left_turn_down[0] - 1;
                    int start2 = left_turn_up[0];
                    if (start2 <= 0) start2 = 0;
                    int end2 = left_turn_up[0] + 3;
                    advanced_regression(1, start1, end1, start2, end2);
                    /***********需要补的是上下两个拐点之间的点*******************************/
                    for (j = (byte)end1; j < (byte)start2; j++)
                    {
                        byte jicun = lefetline[j];
                        lefetline[j] = overflow((int)(parameterB * j + parameterA));
                        //同时加上限制条件,如果左线在中线的右边,则保留原来的坐标
                        if (lefetline[j] < (rightline[j] + lefetline[j]) / 2) lefetline[j] = jicun;
                    }
                }
                else if (findleftupguai == 1 && findleftdownguai == 0)
                {
                    int start1 = left_turn_up[0];
                    if (start1 <= 0) start1 = 0;
                    int end1 = left_turn_up[0] + 5;
                    regression(1, start1, end1);
                    /***********需要补的是上下两个拐点之间的点*******************************/
                    for (j = 0; j < (byte)start1; j++)
                    {
                        byte jicun = lefetline[j];
                        lefetline[j] = overflow((int)(parameterB * j + parameterA));
                        if (lefetline[j] < (rightline[j] + lefetline[j]) / 2) lefetline[j] = jicun;
                    }
                }
                //并列关系
                if (findrightdownguai == 1 && findrightupguai == 1)        //找到左下拐点和左上拐点,拟合所需的点是下拐点下面三个点和上拐点上面三个点
                {
                    int start1 = right_turn_down[0] - 3;
                    if (start1 <= 0) start1 = 0;
                    int end1 = right_turn_down[0] - 1;
                    int start2 = right_turn_up[0];
                    if (start2 <= 0) start2 = 0;
                    int end2 = right_turn_up[0] + 3;
                    advanced_regression(2, start1, end1, start2, end2);
                    /***********需要补的是上下两个拐点之间的点*******************************/
                    for (j = (byte)end1; j < (byte)start2; j++)
                    {
                        byte jicun = rightline[j];
                        rightline[j] = overflow((int)(parameterB * j + parameterA));
                        if (rightline[j] > (rightline[j] + lefetline[j]) / 2) rightline[j] = jicun;
                    }
                }
                else if (findrightdownguai == 0 && findrightupguai == 1)
                {
                    int start1 = right_turn_up[0];
                    if (start1 <= 0) start1 = 0;
                    int end1 = right_turn_up[0] + 5;
                    regression(2, start1, end1);
                    /***********需要补的是上下两个拐点之间的点*******************************/
                    for (j = 0; j < (byte)start1; j++)
                    {
                        byte jicun = rightline[j];
                        rightline[j] = overflow((int)(parameterB * j + parameterA));
                        if (rightline[j] > (rightline[j] + lefetline[j]) / 2) rightline[j] = jicun;
                    }
                }
            }
            //存入显示数组中
            for (j = 0; j < 70; j++)
            {
                centerline[j] = (byte)((lefetline[j] + rightline[j]) / 2);
                LCenter[j] = centerline[j];
                L_black[j] = lefetline[j];
                R_black[j] = rightline[j];
            }
        }
        /********【b2】入十字了,用上面两个点拉下来************/
        else if ((times > 6 && (l_start > 15 && r_start > 15 && My_Abs(l_start - r_start) <= 8)))
        {
            //因为入十字了有许多空白行,会导致中线不准,沿中线往两边扫描得到的拐点也会不准,所以需要重新扫线,此时选择固定行扫线,且times和flag_s不再计数
            for (j = 0; j < 70; j++)
            {
                leftfindflag[j] = 0;
                rightfindflag[j] = 0;
                for (i = 93; i >= 0 && i < 184; i++)
                {
                    if (Pixels[j, i + 1] == 0 && Pixels[j, i] == 0)
                    {
                        leftfindflag[j] = 1;
                        lefetline[j] = (byte)(i + 1);
                        break;
                    }
                }
                for (i = 93; i <= 185 && i > 1; i--)
                {
                    if (Pixels[j, i - 1] == 0 && Pixels[j, i] == 0)
                    {
                        rightfindflag[j] = 1;
                        rightline[j] = (byte)(i - 1);
                        break;
                    }
                }
                if (leftfindflag[j] == 0 && rightfindflag[j] != 0) lefetline[j] = 185;
                if (rightfindflag[j] == 0 && leftfindflag[j] != 0) rightline[j] = 0;
                centerline[j] = (byte)((lefetline[j] + rightline[j]) / 2);
                if ((Pixels[j, centerline[j]]) == 0 && (Pixels[j + 1, centerline[j]]) == 0)
                {
                    break_hangshu = j;
                    if (break_hangshu >= 20)    //防止在一开始就break
                    {
                        break;
                    }
                }
            }
            //breakhang以上的清数据
            for (j = break_hangshu; j < 70; j++)
            {
                lefetline[j] = 185;
                rightline[j] = 0;
            }
            /*************扫完第二次线,再找上拐点****************************/
            /***找左上拐点***********/
            for (j = 2; j <= 55; j++)
            {
                //左上拐点
                if (((j > (byte)left_turn_down[0]) && lefetline[j] - lefetline[j - 1] <= -3 && My_Abs(lefetline[j + 1] - lefetline[j]) <= 2 && My_Abs(lefetline[j + 2] - lefetline[j + 1]) <= 2)
                    || ((j > (byte)left_turn_down[0]) && lefetline[j - 2] - lefetline[j] >= 50 && lefetline[j - 1] - lefetline[j] >= 50 && My_Abs(lefetline[j + 1] - lefetline[j]) <= 3)
                    && leftfindflag[j] == 1 && leftfindflag[j + 1] == 1 && leftfindflag[j + 2] == 1)
                {
    
                    left_turn_up[0] = j + 1;//数组里面没有第0行
                    left_turn_up[1] = lefetline[j];
                    if (left_turn_up[0] <= left_turn_down[0])
                    {
                        ;
                    }
                    else break;
                }
            }
            /***找右上拐点***********/
            for (j = 2; j <= 55; j++)
            {
                //右上拐点
                if (((j > (byte)right_turn_down[0]) && (rightline[j] - rightline[j - 1]) >= 3 && My_Abs(rightline[j + 1] - rightline[j]) <= 2 && My_Abs(rightline[j + 2] - rightline[j + 1]) <= 2)
                    || ((j > (byte)right_turn_down[0]) && rightline[j - 2] - rightline[j] <= -50 && rightline[j - 1] - rightline[j] <= -50 && My_Abs(rightline[j + 1] - rightline[j]) <= 3)
                    && (rightfindflag[j] == 1 && rightfindflag[j + 1] == 1 && rightfindflag[j + 2] == 1))
                {
                    right_turn_up[0] = j + 1;
                    right_turn_up[1] = rightline[j];
                    if (right_turn_up[0] <= right_turn_down[0])
                    {
                        ;
                    }
                    else break;
                }
            }
            if (right_turn_up[0] > right_turn_down[0] && right_turn_up[0] != 0)
            {
                SetText("新的右上拐点         ");
                SetText("          " + right_turn_up[0] + "     " + right_turn_up[1]);
                findrightupguai = 1;//表示找到右上拐点了                
            }
            if (left_turn_up[0] > left_turn_down[0] && left_turn_up[0] != 0)
            {
                SetText("新的左上拐点         ");
                SetText("          " + left_turn_up[0] + "     " + left_turn_up[1]);
                findleftupguai = 1;//表示找到左上拐点了                
            }
            SetText("拉线   ");
            //if (flag_small_S == 0)
            //{
            if (right_turn_up[0] != 0)
            {
            	flag_shizi = 1;
                SetText("拉右线  ");
                int start1 = right_turn_up[0];
                if (start1 <= 0) start1 = 0;
                int end1 = right_turn_up[0] + 5;
                regression(2, start1, end1);
                int jicun1;
                /***********需要补的是上下两个拐点之间的点*******************************/
                for (j = 0; j < (byte)start1; j++)
                {
                    jicun1 = (int)(parameterB * j + parameterA);
                    if (jicun1 >= 185) jicun1 = 185;
                    else if (jicun1 <= 0) jicun1 = 0;
                    //if (rightline[j] > (rightline[j] + lefetline[j]) / 2)
                    rightline[j] = (byte)jicun1;
                }
                SetText("拉右线结束");
            }
            if (left_turn_up[0] != 0)
            {
            	flag_shizi = 1;
                int start1 = left_turn_up[0];
                if (start1 <= 0) start1 = 0;
                int end1 = left_turn_up[0] + 5;
                regression(1, start1, end1);
                int jicun2;
                /***********需要补的是上下两个拐点之间的点*******************************/
                for (j = 0; j < (byte)start1; j++)
                {
                    //if (lefetline[j] < (rightline[j] + lefetline[j]) / 2)
                    jicun2 = (int)(parameterB * j + parameterA);
                    if (jicun2 >= 185) jicun2 = 185;
                    else if (jicun2 <= 0) jicun2 = 0;
                    lefetline[j] = (byte)jicun2;
                }
            }
    
            //}
            for (j = 0; j < 70; j++)
            {
                centerline[j] = (byte)((lefetline[j] + rightline[j]) / 2);
                LCenter[j] = centerline[j];
                L_black[j] = lefetline[j];
                R_black[j] = rightline[j];
            }
        }
    }
    SetText("breakhangshu" + break_hangshu);
    SetText("last_break_hangshu" + last_break_hangshu);
    

    十字补线后,将十字就相当于直道。(十字不涉及道路判断)

    6、中线断线补线(补breakhang之后的线,防止breakhang过低,取PID得点取到虚空处)

    bu_breakhang(2, 15, break_hangshu);
    void bu_breakhang(int c1, int c2, byte j)
    {
    
        int k = centerline[c2] - centerline[c1];
        //SetText("kkkkkk" + k);
        if (k > 10) //入左弯
        {
            for (byte i = j; i < 70; i++)
            {
                centerline[i] = 185;
                LCenter[i] = centerline[i];
                //SetText("  da");
    
            }
        }
        else if (k < -10)  //入右弯
        {
            for (byte i = j; i < 70; i++)
            {
                centerline[i] = 0;
            }
        }
        else//          直到置0
        {
            for (byte i = j; i < 70; i++)
            {
                centerline[i] = 93;
            }
        }
    }
    

    7、计算40行以内的中线的偏差和

    for (j = 1; j < 40; j++)
    {
         center_delta = centerline[j + 1] - centerline[j];       //中线的偏差                
         sumofcenter += center_delta;
     }
     //然后结果取个绝对值
     sumofcenter = My_Abs(sumofcenter);
    

    8、计算40行以内的中线的最大值和最小值并且计算出两者之差

    注意:每帧图像的max和min预先置为93(即图像最中间)

    //计算40行以内的中线的最大值和最小值并且计算出两者之差
    for (j = 0; j < 40; j++)
    {
        if (centerline[j] >= max) max = centerline[j];
        if (centerline[j] <= min) min = centerline[j];
    }
    center_max_min_delta = max - min;
    

    9、对初步扫出的线进行分析连续性(对中线)

    juge_lineContinuity(10, 60, 3, -3, CENTER);
    SetText("中线long_turn_flag:" + long_turn_flag);
    

    10、保存三线值,并将这一帧的第6行中线值保存为old,用到下一帧。

     for (j = 0; j < 70; j++)
     {
          R_Start[j] = forecast_centerline[j];
          LCenter[j] = centerline[j];
          L_black[j] = lefetline[j];
          R_black[j] = rightline[j];
      }
      old = centerline[5];
    

    总结

    至此,初步的扫线和基本特征已经完成,下面就是利用我们所提取的特征进行判断道路类型了,在环岛道路时还需要重新扫线。
    【没事儿可以到我主页看看】https://blog.csdn.net/qq_42604176

    展开全文
  • 智能车复工日记【5】:起跑线的识别与车库入库

    千次阅读 多人点赞 2020-05-09 21:20:41
    起跑线的图: 思路: 1、设置一个栈,用来存储黑色元素。 ...5、遍历18——23行,如果,times在4个左右,则确定为起跑线。 这里我们只需要使用栈的游标,不需要建立完整的栈。 #region[起跑线]

    博主联系方式:
    QQ:1540984562
    微信:wxid_nz49532kbh9u22 QQ交流群:892023501

    系列文章

    【智能车Code review】—曲率计算、最小二乘法拟合
    【智能车Code review】——坡道图像与控制处理
    【智能车Code review】——拐点的寻找
    【智能车Code review】——小S与中S道路判断
    【智能车Code review】——环岛的判定与补线操作
    智能车复工日记【1】——菜单索引回顾
    智能车复工日记【2】——普通PID、变结构PID、微分先行PID、模糊PID、专家PID
    智能车复工日记【3】:图像处理——基本扫线和基本特征提取和十字补线
    智能车复工日记【4】:关于图像的上下位机的调整问题总结
    智能车复工日记【5】:起跑线的识别与车库入库
    智能车复工日记【6】:有bug的模糊PID记录
    智能车复工日记【7】:关于会车的图像问题
    智能车复工日记【N】:图像处理——环岛debug记录(持续更新)

    起跑线识别

    起跑线的图:
    起点
    思路:

    1、设置一个栈,用来存储黑色元素。
    2、从此行的第0列开始往左扫,如果遇到黑色元素,入栈,
    3、如果遇到白色元素,出栈,出栈的同时统计栈中元素个数,如果栈中元素为4—8个(也就是黑胶的宽度),black_blocks++,否则不加。然后将栈中元素清掉
    4、如果此行的black_blocks在8个左右,times++
    5、遍历18——23行,如果,times在4个左右,则确定为起跑线。

    这里我们只需要使用栈的游标,不需要建立完整的栈。

            #region[起跑线]
            //> 1、设置一个栈,用来存储黑色元素。
            //> 、从此行的第0行开始往左扫
            //> 2、如果遇到黑色元素,入栈,
            //> 3、如果遇到白色元素,出栈,出栈的同时统计栈中元素个数,如果栈中元素为4—8个(也就是黑胶的宽度),black_blocks++,否则不加。然后将栈中元素清掉
            //> 4、如果此行的black_blocks在8个左右,times++
            //> 5、遍历18——23行,如果,times在4个左右,则确定为起跑线。
            byte flag_starting_line = 0;
            void check_starting_line()
            {
                //int[] black_nums_stack = new int[20];
                byte times = 0;
                for (byte y = 18; y <= 23; y++)
                {
                    byte black_blocks = 0;
                    byte cursor = 0;    //指向栈顶的游标
                    for (byte x = 0; x <= 185; x++)
                    {
                        if (Pixels[y,x] == 0)
                        {
                            if (cursor >= 20)
                            {
                                //当黑色元素超过栈长度的操作   break;    
                            }
                            else 
                            {
                                cursor++;
                            }
                        }
                        else 
                        {
                            if (cursor >= 4 && cursor <= 8)
                            {
                                black_blocks++;
                                cursor = 0;
                            }
                            else 
                            {
                                cursor = 0;
                            }
                        }
                    }
                    if (black_blocks >= 6 && black_blocks <= 9) times++;
                }
                if (times >= 3 && times <= 5)
                {
                    flag_starting_line = 1;
                    SetText("进入起跑线状态");
                }
                else 
                {
                    flag_starting_line = 0;
                }
            }
            #endregion
    

    效果:
    效果
    进入起跑线状态之后可以进行下一步的特殊操作,如入车库等操作。
    这里的行数确定了我们距离起跑线多少能识别出起跑线。当距离较远时,可以发现由于反光,起跑线并不明显。

    车库补线

    识别车库方向

    如何识别车库方位:
    我们不是从第0列开始扫的吗?
    设此时已判断为起跑线,我们所扫的那几行的第0列都是黑色,那就是车库在左边。
    反之,如果都是白色,那就是车库在右边

    车库补线

    在这里插入图片描述
    如果是检测到为右边车库(已实现),寻找两个端点,然后连接两个端点。
    1、 右上拐点
    2、 左下拐点

    左下拐点:
    1、 如果pixels[0,185]为白,往上找,直到pixels[y1,185]为黑(防止姿态的原因导致车偏向道路左边)
    2、 从上面确定的第y1行开始往右边扫,扫到的第一个不为黑的点视为左下拐点。

    右上拐点:
    1、 从第0行往上找,直到pixels[y2,0]为黑
    2、 从上面确定的第y2行开始往左边扫,记录下扫到的第一个为白的点的列坐标
    3、 遍历[y2, y2+5],选出6行中列坐标最大(最靠左)的列坐标以及那时的行坐标,作为左上拐点

    #region[右车库]
    //前一个是行坐标,后一个是列坐标
    int[] right_garage_left_turn_down = new int[2];
    int[] right_garage_right_turn_up = new int[2];
    void check_guaidian()
    {
        //首先找左下拐点
        byte y1 = 0;
        byte x1 = 0;
        byte x = 0;
        byte y = 0;
        // 1、	如果pixels[0, 185]为白,往上找,直到pixels[y1, 185]为黑(防止姿态的原因导致车偏向道路左边)
        if (Pixels[0, 185] != 0)   //不为黑,即为白
        {
            
            for (y = 1; y < 70; y++)
            {
                if (Pixels[y, 185] == 0)
                {
                    y1 = y;
                    break;
                }
            }
        }
        else
        {
            y1 = 0;
        }
        //2、	从上面确定的第y1行开始往右边扫,扫到的第一个不为黑的点视为左下拐点。
       
        for (x = 185;x>1;x--)
        {
            if (Pixels[y1, x] != 0)
            {
                x1 = x;
                break;
            }
        }
        //赋值操作
        right_garage_left_turn_down[0] = y1;
        right_garage_left_turn_down[1] = x1;
        //然后找右上拐点
        //1、	从第0行往上找,直到pixels[y1,0]为黑
        for (y = 0; y < 70; y++)
        {
            if (Pixels[y, 0] == 0)
            {
                y1 = y;
                break;
            }
        }
        //2、	从上面确定的第y1行开始往左边扫,记录下扫到的第一个为白的点的列坐标
        for (x = 0; x < 185; x++)
        {
            if (Pixels[y1, x] != 0)
            {
                x1 = x;
                break;
            }
        }
        //3、	遍历[y2, y2 + 2],选出6行中列坐标最大(最靠左)的列坐标以及那时的行坐标,作为左上拐点
        for (y = (byte)(y1 + 1); y <= y1 + 2; y++)
        {
            byte X=0;
            for (x = 0; x < 185; x++)
            {
                if (Pixels[y1, x] != 0)
                {
                    X = x;
                    break;
                }
            }
            if (X >= x1)
            {
                x1 = X;
                y1 = y;
            }
        }
        //赋值操作
        right_garage_right_turn_up[0] = y1;
        right_garage_right_turn_up[1] = x1;
    
        //展示
        SetText("车库右上角"+ right_garage_right_turn_up[0]+"  "+ right_garage_right_turn_up[1]);
        SetText("车库左下角" + right_garage_left_turn_down[0] + "  " + right_garage_left_turn_down[1]);
        //补线程序
        byte j = 0;
        int delta = right_garage_right_turn_up[0] - right_garage_left_turn_down[0];
        if (delta == 0) delta = 1;
        float k = (right_garage_right_turn_up[1] - right_garage_left_turn_down[1]) * 1.0f / delta;
        float b = right_garage_left_turn_down[1];
        for (j = (byte)right_garage_left_turn_down[0]; j <= (byte)right_garage_right_turn_up[0]; j++)
        {
            int jicun = ((int)(k * j + b));
            if (jicun >= 185) jicun = 185;
            else if (jicun <= 0) jicun = 0;
            lefetline[j] = (byte)jicun;
        }
    }
    #endregion
    

    5.11修改

    这几天的一些更加完善的代码,不过还是有许多问题:

    #region[起跑线]
    //> 1、设置一个栈,用来存储黑色元素。
    //> 、从此行的第0行开始往左扫
    //> 2、如果遇到黑色元素,入栈,
    //> 3、如果遇到白色元素,出栈,出栈的同时统计栈中元素个数,如果栈中元素为4—8个(也就是黑胶的宽度),black_blocks++,否则不加。然后将栈中元素清掉
    //> 4、如果此行的black_blocks在8个左右,times++
    //> 5、遍历18——23行,如果,times在4个左右,则确定为起跑线。
    byte flag_starting_line = 0;
    byte garage_direction = 0;      //1为左边,2位右边
    void check_starting_line(byte start_point, byte end_point)
    {
        //int[] black_nums_stack = new int[20];
        byte times = 0;
        for (byte y = start_point; y <= end_point; y++)
        {
            byte black_blocks = 0;
            byte cursor = 0;    //指向栈顶的游标
            for (byte x = 0; x <= 185; x++)
            {
                if (Pixels[y,x] == 0)
                {
                    if (cursor >= 20)
                    {
                        //当黑色元素超过栈长度的操作   break;    
                    }
                    else 
                    {
                        cursor++;
                    }
                }
                else 
                {
                    if (cursor >= 4 && cursor <= 8)
                    {
                        black_blocks++;
                        cursor = 0;
                    }
                    else 
                    {
                        cursor = 0;
                    }
                }
            }
            if (black_blocks >= 6 && black_blocks <= 9) times++;
        }
        if (times >= 1)
        {
            flag_starting_line = 1;
            SetText("进入起跑线状态");
        }
        else 
        {
            flag_starting_line = 0;
        }
    }
    void check_garage_direction(byte start_point, byte end_point)
    {
        byte times = 0;
        if (flag_starting_line == 1)
        {
            for (int y = start_point; y <= end_point; y++)
            {
                if (Pixels[y, 0] == 0)
                {
                    times++;
                }
            }
            if (times >= 3 && times <= 7)
            {
                garage_direction = 1;   //车库在左边
                //SetText("车库在左边");
            }
            else if (times <= 2)
            {
                garage_direction = 2;   //车库在右边
                //SetText("车库在右边");
            }
        }
        SetText("times"+ times);
    }
    #endregion
    #region[右车库]
    //前一个是行坐标,后一个是列坐标
    int[] right_garage_left_turn_down = new int[2];
    int[] right_garage_right_turn_up = new int[2];
    void check_guaidian()
    {
        //首先找左下拐点
        byte y1 = 0;
        byte x1 = 0;
        byte x = 0;
        byte y = 0;
        // 1、	如果pixels[0, 185]为白,往上找(不超过5行),直到pixels[y1, 185]为黑(防止姿态的原因导致车偏向道路左边)
        if (Pixels[0, 185] != 0)   //不为黑,即为白
        {
            
            for (y = 1; y < 5; y++)
            {
                if (Pixels[y, 185] == 0)
                {
                    y1 = y;
                    break;
                }
            }
        }
        else
        {
            y1 = 0;
        }
        //2、	从上面确定的第y1行开始往右边扫,扫到的第一个不为黑的点视为左下拐点。
       
        for (x = 185;x>1;x--)
        {
            if (Pixels[y1, x] != 0)
            {
                x1 = x;
                break;
            }
        }
        //赋值操作
        right_garage_left_turn_down[0] = y1;
        right_garage_left_turn_down[1] = x1;
        //然后找右上拐点
       
        if (Pixels[0, 0] == 0 && Pixels[1, 0] == 0 && Pixels[2, 0] == 0 && Pixels[3, 0] == 0 && Pixels[4, 0] == 0)
        {
            for (y = 5; y < 70; y++)
            {
                if (Pixels[y, 0] != 0)//为白
                {
                    y1 = y;
                    break;
                }
    
            }
            for (y = y1; y < 70; y++)
            {
                if (Pixels[y, 0] == 0)
                {
                    y1 = y;
                    break;
                }
    
            }
        }
        else
        {
            for (y = 10; y < 70; y++)
            {
                if (Pixels[y, 0] == 0)
                {
                    y1 = y;
                    break;
                }
            }
        }
        //2、	从上面确定的第y1行开始往左边扫,记录下扫到的第一个为白的点的列坐标
        for (x = 0; x < 185; x++)
        {
            if (Pixels[y1, x] != 0)
            {
                x1 = x;
                break;
            }
        }
        byte y_zhengque = 0;
        //3、	遍历[y2, y2 + 2],选出6行中列坐标最大(最靠左)的列坐标以及那时的行坐标,作为左上拐点
        for (y = (byte)(y1 + 1); y <= y1 + 2; y++)
        {
            byte X=0;
            for (x = 0; x < 185; x++)
            {
                if (Pixels[y1, x] != 0)
                {
                    X = x;
                    break;
                }
            }
            if (X >= x1)
            {
                x1 = X;
                y_zhengque = y;
            }
        }
        y1 = y_zhengque;
        //赋值操作
        right_garage_right_turn_up[0] = y1;
        right_garage_right_turn_up[1] = x1;
    
        //展示
        SetText("车库右上角"+ right_garage_right_turn_up[0]+"  "+ right_garage_right_turn_up[1]);
        SetText("车库左下角" + right_garage_left_turn_down[0] + "  " + right_garage_left_turn_down[1]);
        //补线程序
        byte j = 0;
        int delta = right_garage_right_turn_up[0] - right_garage_left_turn_down[0];
        if (delta == 0) delta = 1;
        float k = (right_garage_right_turn_up[1] - right_garage_left_turn_down[1]) * 1.0f / delta;
        float b = right_garage_left_turn_down[1];
        for (j = (byte)right_garage_left_turn_down[0]; j <= (byte)right_garage_right_turn_up[0]; j++)
        {
            int jicun = ((int)(k * j + b));
            if (jicun >= 185) jicun = 185;
            else if (jicun <= 0) jicun = 0;
            lefetline[j] = (byte)jicun;
        }
    }
    #endregion
    #region[左车库]
    //前一个是行坐标,后一个是列坐标
    int[] left_garage_left_turn_up = new int[2];
    int[] left_garage_right_turn_down = new int[2];
    void check_guaidian1()
    {
        //首先找右下拐点
        byte y1 = 0;
        byte x1 = 0;
        byte x = 0;
        byte y = 0;
        // 1、	如果pixels[0, 0]为白,往上找(不可超过5),直到pixels[y1, 0]为黑(防止姿态的原因导致车偏向道路右边)
        if (Pixels[0, 0] != 0)   //不为黑,即为白
        {
    
            for (y = 1; y < 5; y++)
            {
                if (Pixels[y, 0] == 0)
                {
                    y1 = y;
                    break;
                }
            }
        }
        else
        {
            y1 = 0;
        }
        //2、	从上面确定的第y1行开始往左边扫,扫到的第一个不为黑的点视为右下拐点。
    
        for (x = 0; x <185; x++)
        {
            if (Pixels[y1, x] != 0)
            {
                x1 = x;
                break;
            }
        }
        //赋值操作
        left_garage_right_turn_down[0] = y1;
        left_garage_right_turn_down[1] = x1;
        //然后找左上拐点
        //如果前5行为黑,则第二次为黑的行数
    
        //否则从第10行往上找
        //1、	从第10行往上找,直到pixels[y1,185]为黑
        if (Pixels[0, 185] == 0 && Pixels[1, 185] == 0 && Pixels[2, 185] == 0 && Pixels[3, 185] == 0 && Pixels[4, 185] == 0)
        {
            for (y = 5; y < 70; y++)
            {
                if (Pixels[y, 185] != 0)//为白
                {
                    y1 = y;
                    break;
                }
                
            }
            for (y = y1; y < 70; y++)
            {
                if (Pixels[y, 185] == 0)
                {
                    y1 = y;
                    break;
                }
                
            }
        }
        else 
        {
            for (y = 10; y < 70; y++)
            {
                if (Pixels[y, 185] == 0)
                {
                    y1 = y;
                    break;
                }
            }
        }
        SetText("左上行:"+y1);
        //2、	从上面确定的第y1行开始往右边扫,记录下扫到的第一个为白的点的列坐标
        for (x = 185; x > 1; x--)
        {
            if (Pixels[y1, x] != 0)
            {
                x1 = x;
                break;
            }
        }
        SetText("y1是" + y1);
        //3、	遍历[y2, y2 + 2],选出3行中列坐标最大(最靠左)的列坐标以及那时的行坐标,作为左上拐点
        byte y_zhengque = 0;
        for (y = (byte)(y1 + 1); y <= (byte)(y1 + 3); y++)
        {
            byte X = 0;
            for (x = 185; x > 1; x--)
            {
                if (Pixels[y1, x] != 0)
                {
                    X = x;
                    break;
                }
            }
            if (X <= x1)
            {
                x1 = X;
                y_zhengque = y;
            }
        }
        y1 = y_zhengque;
        SetText("y1是"+y1);
        //赋值操作
        left_garage_left_turn_up[0] = y1;
        left_garage_left_turn_up[1] = x1;
    
        //展示
        SetText("车库左上角" + left_garage_left_turn_up[0] + "  " + left_garage_left_turn_up[1]);
        SetText("车库右下角" + left_garage_right_turn_down[0] + "  " + left_garage_right_turn_down[1]);
        //补线程序
        byte j = 0;
        int delta = left_garage_left_turn_up[0] - left_garage_right_turn_down[0];
        if (delta == 0) delta = 1;
        float k = (left_garage_left_turn_up[1] - left_garage_right_turn_down[1]) * 1.0f / delta;
        float b = left_garage_right_turn_down[1];
        for (j = (byte)left_garage_right_turn_down[0]; j <= (byte)left_garage_left_turn_up[0]; j++)
        {
            int jicun = ((int)(k * j + b));
            if (jicun >= 185) jicun = 185;
            else if (jicun <= 0) jicun = 0;
            rightline[j] = (byte)jicun;
        }
    }
    #endregion
    
    展开全文
  • 近日有很多新入市的朋友,很多对基础知识不太了解,因为手中个股操作主要还是自己,因为时机很重要,在此发些基础知识,供新朋友们学习参考!当然还需要多方面综合运用!  均线  均线指标实际上是移动平均线指标...
  • 5日均线和10日均线相交叉常常成为我们选股判断一只股票上涨的依据,但是在实际的应用中,大 家发现往往不是很准确,经常通过该依据买入就被套住,然后刚刚一卖出,就上涨,其实5日均线金叉10 日均线需要其他...
  • 画K线图、画N日均线 python3

    千次阅读 2017-07-12 09:29:24
    记下自己的研究成果是件开心的事情,本文介绍用Python3将股票历史行情画成K线图,以及添加5日10日,N日均线。  首先,是获取数据源,一般分两种,一是直接从财经类网站读取;二是读取本地数据文件。我是先从财经...
  • 什么是K线图,怎么K线

    千次阅读 2007-05-28 12:08:00
    它是以每个交易(或每个分析周期)的开盘价、最高键、最低价、收盘价绘制而成,K线的结构可分为上影线、下影线及中间实体三部分。K线将买卖双方力量的增减与转变过程及实战结果用图形表示出来。经过近百年来的...
  • 在三线城市工作爽吗?

    万次阅读 多人点赞 2020-02-15 10:08:14
    一不小心又暴露了自己的实际年龄,但老读者都知道,我驻颜有术,上次去房子,业务员肯定地说:“小哥肯定比我小,我今年还不到 24。”我只好强颜欢笑:“你说得对。” 从我拥有记忆到现在进入而立之年,我觉得,我...
  • K线图如何对接第3方数据2-K数据协议名称-多日分时数据协议日志截图Request 字段说明countsymbolfield返回json数据结构数据截图namesymbolcountstart, enddata数据截图 协议名称-多日分时数据 对应代码的类名函数...
  • 资本市场上,每天都在演绎着转瞬即逝的遗憾,曙光来临的...要弄清楚金叉死叉哪几条线,必须要先了解其基本含义。 金叉 当短周期均线由下向上突破长周期均价线时,形成的交点即为金叉。金叉是市场由空头转为...
  • 而立之年——三线城市程序员的年终告白

    万次阅读 多人点赞 2016-12-23 20:49:54
    在《于丹的〈论语心得〉》里,“立”是内心的的立,是内在心灵的独立,而不是十岁的无知,二十岁的愤青,三十真正追求的是心灵的自信坚定,在你的生命里树立清楚的自省,从容不迫的生活态度,忠于自己的心灵。...
  • 日线图: 是以每个交易日一根K线,组成的K线图 周线,月线,年线: 是以1周, 1月,1年做成一根K线,组成的K线图 分钟K线: 一般有1分钟, 5分钟 10分钟, 自定义分钟数,是以1分钟,5分钟 10分钟,作为一根K线,...
  • 说说 iphone 数据线(充电线) 原装正品...但前几自己的iphone数据线外皮不幸让我挤搓破裂了,恰巧另一根已经完全坏掉的不能用的ipad的数据线作了下比较,没想到差距还是不小的。 如上图所示: [1]最外面是
  • 分享Silverlight/Windows8/WPF/WP7/HTML5周学习导读(6月4日-6月10日) 本周Silverlight学习资源更新 Silverlight的一个简单加载标志Loading... 温度 无法启动调试--未安装 Silverlight Developer ...
  • 目录talib提供给我们的K线形态pyqt5绘制K线图 talib提供给我们的K线形态 在前面的博文中,我们介绍了talib提供给我们的6种K形态。不过,那只是博主通过讲解一部分,让大家认识如何使用talib区分K线,其实talib提供给...
  •  并行口与串行口的区别是交换信息的方式不同,并行口能同时通过8条数据线传输信息,一次传输一个字节;而串行口只能用1条线传输一位数据,每次传输一个字节的一位。并行口由于同时传输更多的信息,速度明显高于串行...
  • 用Python的PandasMatplotlib绘制股票KDJ指标线

    千次阅读 多人点赞 2020-08-28 07:13:28
    我最近出了一本书,《基于股票大数据分析的Python入门实战 视频教学版》,京东链接:...该指标集中包含了强弱指标、动量概念移动平均线的优点,可以用来衡量股价脱离正常价格范围的偏离程度。 KDJ指标的计算过程...
  • 在三年多前,师父第一次把我独立地扔到一条座椅装配的生产线上去审核。些十几道工序,几十台设备在那有条不紊的运转着。款式各异的条码,测量设备上花花绿绿的信号得我眼花缭乱,丝毫不知道该从...
  • 使用Python对股票数据进行数据分析(一)-计算日线行情、5日均线、10日均线行情并显示 各种炒股软件上可以显示各种技术指标,可以帮助投资者进行技术分析。这些股市中的这些指标都是怎么计算出来的呢?这里使用...
  • 在这些文章里,将用Python工具绘制各种股票指标,在讲述各股票指标的含义以及计算方式的同时,验证基于各种指标的交易策略,本文是第一篇,通过K线和均线案例讲述Numpy,Maplotlib等相关库的用法,并且还用代码案例...
  • 学习曲线遗忘曲线

    千次阅读 2015-08-13 01:51:59
    人们为了知道学习进程中的现象进步的快慢的详情,作为以后努力的指针,应用统计图的方法作一条线,把它表示出来。它源于“二战”时期的飞机工业,当产量上升时,生产每架飞机的劳动时间会极大地下降。随后的研究...
  • 使用pandas的rolling.mean函数自定义移动平均线
  • 最近我出了一本书,《基于股票大数据分析的Python入门... 在本文里,将给出若干精彩范例,包括用爬虫获取股市数据,用matplotlib可视化控件绘制K线和均线,以及用sklean库里的方法,通过机器学习预测股价的走势。 ...
  • 智能车打工日记(二):关于起跑线与出入车库

    千次阅读 多人点赞 2020-08-14 15:19:51
    赛道上的斑马线和斑马线下的磁铁放置与往届规则相同。 车库应用于“基础四轮组”,“直立节能组”,“双车接力组”。 入车库 20cm摄像头拍下的车库图 起跑线的识别 因为时间紧迫,这里采用最简单的入车库(左入)...
  • pyecharts绘制K线

    万次阅读 热门讨论 2018-12-23 20:07:15
    vnpy原生的回测结果没有绘制k线,所以也就没有指标的可视化开仓平仓的可视化,只有随后交易结果的可视化。笔者自己其实有点点不习惯,没有看到策略的可视化回测结果,有点点不开心,所以打算自己做一下。首先...
  • MPAndroidChart的K线图上添加均线

    千次阅读 热门讨论 2015-12-01 13:13:02
    通常说的5日均线,10日均线,其实就是根据当前K线节点的时间维度来说的,当前每个节点代表一天,那么上面的均线就叫做日均线(几日均线),下面就统一说成几节点均线 那么5节点均线,10节点均线等等,是怎么计算...
  • 一、热点事件概述 二、热点事件的挖掘可行性 三、热点事件的挖掘方法 四、热点事件演化分析 五、热点事件的时间线timeline及故事线Storyline生成 六、总结 ...
  • Android分割线divider(内含Android虚线分割线失效成实线解决方案) 1,最简单最常见的Android分割线android:attr/listDivider。 最简单最常见的是把Android原生的Android ListView的分割线divider直接拿来...
  • 快速创建一个K线图页面HQChart介绍demo页面代码Option的配置项说明 效果图 HQChart介绍 功能: 提供K线,走势图, 支持通达信语法指标(麦语法), 画图工具,等等… 支持PC端页面, 小程序,手机端页面。 地址...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 168,058
精华内容 67,223
关键字:

如何看5日线和10日线