智能汽车竞赛摄像头处理(5)——摄像头基本循迹的代码实现:找赛道边线和赛道中线

目录

前言

思路

处理方法

代码

代码分析

使用

注意


前言

(1)我们整个图像处理的步骤如下:

  1. 固定阈值二值化/大津法:灰度图像转为黑白图像
  2. 找边界求赛道中线
  3. 求偏差值(取一行/取多行平均/取多行加权平均)

(2)前一篇文章我们已经对循迹原理进行了分析,找赛道边界就是找黑白跳变点。

思路

我们这篇文章来讲解第二步“找边界求赛道中线”的代码实现,为了避免赛道附近的杂物对二值化产生影响,推荐从中间往两边找赛道中线,适用于中间是白色的情况,能向两边找到两个黑白跳变点;假如遇到中间不是白色的情况,就取1/4中点往两边找黑白跳变点,那么我们就要注意:是图像左边的1/4中点,还是图像右边的1/4中点?我们在代码实现的时候要将这个问题处理好。

处理方法

处理方法就是:采用按“顺序判断“来写:(1)如果图像的二分之一点是白点,那从二分之一点开始找。(2)如果图像的二分之一点是白点,那就分别判断左右两个1/4点哪个为黑点,不可能出现左右两个1/4点均为黑点的情况。

代码

针对以上思想,写出下面伪代码,注释详细,大家可以自行理解,有问题在评论区交流:

/* 名字:Find_Mid_Line
 * 功能:寻找赛道的左右边界
 * 参数:index[MT9V03X_H][MT9V03X_W](为二值化后的数组)
 * 输出:无(会得到左边界线、右边界线、中线)
 */
//找左边界 右边界 需要三个一维数组
uint8 left_line_list[MT9V03X_H];	//高
uint8 right_line_list[MT9V03X_H];	//高
uint8 mid_line_list[MT9V03X_H];		//高
void Find_Mid_Line(uint8 index[MT9V03X_H][MT9V03X_W])	//index指数
{
    //定义左边点与右边点,并赋初值(当下面for循环没有左边点与右边点时用初值)
    uint8 left_point = 1;
    uint8 right_point = MT9V03X_W - 1;	//宽

    left_line_list[0] = 1;
    right_line_list[0] = MT9V03X_W - 1;
    mid_line_list[0] = (left_point + right_point) / 2;

    //从图片底部往上找
    for(uint8 i = MT9V03X_H - 1;i > 0;i--)	//高——行
    {
/**************以下代码是遍历一整个横行找两个黑白跳变点***************/        
        //	如果二分之一点是白点,从二分之一点开始找
        if(index[i][MT9V03X_W/2] == 255)	//255 - 白
        {
            //寻找左边点
            for(uint8 j = MT9V03X_W/2 - 1;j > 0;j--)
            {
                if(index[i][j] == 0 && index[i][j+1] == 255)	//255 - 白
                {
                    left_point = j;
                    break;
                }
            }
            
            //寻找右边点
            for(uint8 j = MT9V03X_W/2 + 1;j < MT9V03X_W;j++)
            {
                if(index[i][j] == 0 && index[i][j-1] == 255)	//255 - 白
                {
                    right_point = j;
                    break;
                }
            }
        }

        //	如果四分之一点是白点,从四分之一点开始找
        else if(index[i][MT9V03X_W/4] == 255)
        {
            //寻找左边点
            for(uint8 j = MT9V03X_W/4 - 1;j > 0;j--)
            {
                if(index[i][j] == 0 && index[i][j+1] == 255)	//255 - 白
                {
                    left_point = j;
                    break;
                }
            }
            
            //寻找右边点
            for(uint8 j = MT9V03X_W/4 + 1;j < MT9V03X_W;j++)
            {
                if(index[i][j] == 0 && index[i][j-1] == 255)	//255 - 白
                {
                    right_point = j;
                    break;
                }
            }
        }

        //	如果四分之三点是白点,从四分之三开始找
        else if(index[i][MT9V03X_W/4*3] == 255)
        {
            //寻找左边点
            for(uint8 j = MT9V03X_W/4*3 - 1;j > 0;j--)
            {
                if(index[i][j] == 0 && index[i][j+1] == 255)	//255 - 白
                {
                    left_point = j;
                    break;
                }
            }
            
            //寻找右边点
            for(uint8 j = MT9V03X_W/4*3 + 1;j < MT9V03X_W;j++)
            {
                if(index[i][j] == 0 && index[i][j-1] == 255)	//255 - 白
                {
                    right_point = j;
                    break;
                }
            }
        }
        else	//1/2点,1/4点,3/4点都是黑色时
        {
            left_point = 1;
            right_point = MT9V03X_W - 1;
        }

        left_line_list[i] = left_point;
        right_line_list[i] = right_point;
        mid_line_list[i] = (left_point + right_point)/2;
    }
}

代码分析

        通过扫线,我们可以找到左边线的横坐标数组left_line_list[i],右边线的横坐标数组right_line_list[i],确定了左边线和右边线上所有点的横坐标,而边线的纵坐标就是是整个图像的高,所以左边线和右边线就确定了。

       对左边线和右边线的横坐标求平均值:mid_line_list[i] = (left_point + right_point)/2, 最后得到的数组mid_line_list[i]为赛道中线的横坐标数组,中线的纵坐标也是整个图像的高,到此赛道边线和中线都确定下来了。

使用

在cpu1.c中添加以下代码:

    while (TRUE)
    {
        // 此处编写需要循环执行的代码

        if(mt9v03x_finish_flag)     //一幅图像完全采集完毕后,再进行图像的显示判断和显示
        {
            //Set_image_towvalues(150); //固定阈值二值化
            BandW_threshold = otsuThreshold_fast(mt9v03x_image[0]);//大津法得到动态阈值
            Set_image_towvalues(BandW_threshold); //动态阈值二值化,得到二值化后的二维数组mt9v03x_image_BandW
            
            Find_Mid_Line(mt9v03x_image_BandW[MT9V03X_H][MT9V03X_W]);//找边线
            
            tft180_displayimage03x(mt9v03x_image_BandW[0],MT9V03X_W,MT9V03X_H);//显示二值化后的图像
            mt9v03x_finish_flag = 0;//图像显示完成后才对标志位清零
        }

        // 此处编写需要循环执行的代码
    }

注意

        tc264对于数组越界,包括循环中遍历时的数组越界是比较严格的,一旦有什么地方有越界产生,工程会运行失败,功能会运行异常,屏幕可能显示不了图像。

下一节介绍,在屏幕中画出所找的边线和中线,直观地体现我们通过算法找的边线和中线是否合适。                

你可能感兴趣的:(智能车竞赛摄像头,汽车,人工智能)