智能车摄像头灰度处理高效算法(上)

本篇文章分享全国大学生智能车竞赛中常用的一些摄像头图像处理算法。

智能车摄像头灰度处理高效算法(下)-CSDN博客

一、大津法 

//-------------------------------------------------------------------------------------------------------------------
//  @brief      快速大津
//  @return     uint8
//  @since      v1.1
//  Sample usage:   OTSU_Threshold = otsuThreshold(mt9v03x_image_dvp[0]);//大津法阈值
//-------------------------------------------------------------------------------------------------------------------
uint8 otsuThreshold(uint8 *image)   //注意计算阈值的一定要是原图像
{
#define GrayScale 256
    int Pixel_Max=0;
    int Pixel_Min=255;
    uint16 width = MT9V03X_W;
    uint16 height = MT9V03X_H;
    int pixelCount[GrayScale];
    float pixelPro[GrayScale];
    int i, j, pixelSum = width * height/4;
    uint8 threshold = 0;
    uint8* data = image;  //指向像素数据的指针
    for (i = 0; i < GrayScale; i++)
    {
        pixelCount[i] = 0;
        pixelPro[i] = 0;
    }

    uint32 gray_sum=0;
    //统计灰度级中每个像素在整幅图像中的个数
    for (i = 0; i < height; i+=2)
    {
        for (j = 0; j < width; j+=2)
        {
            pixelCount[(int)data[i * width + j]]++;  //将当前的点的像素值作为计数数组的下标
            gray_sum+=(int)data[i * width + j];       //灰度值总和
            if(data[i * width + j]>Pixel_Max)   Pixel_Max=data[i * width + j];
            if(data[i * width + j]<Pixel_Min)   Pixel_Min=data[i * width + j];
        }
    }

    //计算每个像素值的点在整幅图像中的比例

    for (i = Pixel_Min; i < Pixel_Max; i++)
    {
        pixelPro[i] = (float)pixelCount[i] / pixelSum;

    }

    //遍历灰度级[0,255]
    float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0;

    w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;
    for (j = Pixel_Min; j < Pixel_Max; j++)
    {

        w0 += pixelPro[j];  //背景部分每个灰度值的像素点所占比例之和   即背景部分的比例
        u0tmp += j * pixelPro[j];  //背景部分 每个灰度值的点的比例 *灰度值

        w1=1-w0;
        u1tmp=gray_sum/pixelSum-u0tmp;

        u0 = u0tmp / w0;              //背景平均灰度
        u1 = u1tmp / w1;              //前景平均灰度
        u = u0tmp + u1tmp;            //全局平均灰度
        deltaTmp = (float)(w0 *w1* (u0 - u1)* (u0 - u1)) ;
        if (deltaTmp > deltaMax)
        {
            deltaMax = deltaTmp;
            threshold = j;
        }
        if (deltaTmp < deltaMax)
        {
            break;
        }

    }

    if(threshold>90 && threshold<130)
        last_threshold = threshold;
    else
        threshold = last_threshold;

    return threshold;
}

二、图像压缩

//-------------------------------------------------------------------------------------------------------------------
//  @brief      图像压缩
//  @return     void
//  @since      v2.0
//  Sample usage:   void compressimage();
//-------------------------------------------------------------------------------------------------------------------
#define IMAGE_H    50//图像高度
#define IMAGE_W    90//图像宽度
uint8 Image_use_zip[IMAGE_H][IMAGE_W];
void compressimage(void)
{
  int i, j, row, line;
  const float div_h = MT9V03X_H / IMAGE_H, div_w = MT9V03X_W / IMAGE_W;
  for (i = 0; i < IMAGE_H; i++)
  {
    row = i * div_h + 0.5;
    for (j = 0; j < IMAGE_W; j++)
    {
      line = j * div_w + 0.5;
      Image_use_zip[i][j] = mt9v03x_image[row][line];
    }
  }
}

三、 Soble固定阈值

//-------------------------------------------------------------------------------------------------------------------
//  @brief      Soble固定阈值
//  @return     void
//  @since      v1.2
//  Sample usage:   sobel(Image_use_zip, Image_use, 60);
//-------------------------------------------------------------------------------------------------------------------
void sobel (uint8 imageIn[IMAGE_H][IMAGE_W], uint8 imageOut[IMAGE_H][IMAGE_W], uint8 Threshold)
{
    /** 卷积核大小 */
    short KERNEL_SIZE = 3;
    short xStart = KERNEL_SIZE / 2;
    short xEnd = IMAGE_W - KERNEL_SIZE / 2;
    short yStart = KERNEL_SIZE / 2;
    short yEnd = IMAGE_H - KERNEL_SIZE / 2;
    short i, j;
    short temp[2];
    for (i = yStart; i < yEnd; i++)
    {
        for (j = xStart; j < xEnd; j++)
        {
            /* 计算不同方向梯度幅值  */
            temp[0] = -(short) imageIn[i - 1][j - 1] + (short) imageIn[i - 1][j + 1]     //{{-1, 0, 1},
            - (short) imageIn[i][j - 1] + (short) imageIn[i][j + 1]                      // {-1, 0, 1},
            - (short) imageIn[i + 1][j - 1] + (short) imageIn[i + 1][j + 1];             // {-1, 0, 1}};

            temp[1] = -(short) imageIn[i - 1][j - 1] + (short) imageIn[i + 1][j - 1]     //{{-1, -1, -1},
            - (short) imageIn[i - 1][j] + (short) imageIn[i + 1][j]                      // { 0,  0,  0},
            - (short) imageIn[i - 1][j + 1] + (short) imageIn[i + 1][j + 1];             // { 1,  1,  1}};

            temp[0] = abs(temp[0]);
            temp[1] = abs(temp[1]);

            /* 找出梯度幅值最大值  */
            if (temp[0] < temp[1])
                temp[0] = temp[1];

            if (temp[0] > Threshold) imageOut[i][j] = 0;
            else    imageOut[i][j] = 255;
        }
    }
}

四、给图像画黑框为八邻域做准备


//-------------------------------------------------------------------------------------------------------------------
//  @brief      给图像画黑框为八邻域做准备
//  @return     void
//  @since      v1.0
//  Sample usage:   image_draw_rectan(Image_use);
//-------------------------------------------------------------------------------------------------------------------
void image_draw_rectan(uint8(*image)[IMAGE_W])
{
    uint8 i = 0;
    for (i = 0; i < IMAGE_H; i++)
    {
        image[i][0] = 0;
        image[i][1] = 0;
        image[i][IMAGE_W - 1] = 0;
        image[i][IMAGE_W - 2] = 0;
    }
    for (i = 0; i < IMAGE_W; i++)
    {
        image[0][i] = 0;
        image[1][i] = 0;
    }
}

五、八邻域找边界

/*---------------------------------------------------------------
 【函    数】search_neighborhood
 【功    能】八邻域找边界
 【参    数】无
 【返 回 值】无
 【注意事项】
 ----------------------------------------------------------------*/
struct LEFT_EDGE
{
    int16 row;  //行坐标
    int16 col;  //列坐标
    uint8 flag; //存在边界的标志
};
struct RIGHT_EDGE
{
    int16 row;  //行坐标
    int16 col;  //列坐标
    uint8 flag; //存在边界的标志
};

struct LEFT_EDGE  L_edge[140];     //左边界结构体
struct RIGHT_EDGE R_edge[140];    //右边界结构体
uint8 L_edge_count=0, R_edge_count = 0;                     //左右边点的个数
uint8 dire_left,dire_right;                                 //记录上一个点的相对位置
uint8 L_search_amount = 140, R_search_amount = 140;  //左右边界搜点时最多允许的点
void search_neighborhood(void)
{
    L_edge_count = 0;//左边点个数清0
    R_edge_count = 0;//右边点个数清0

    if(left_findflag)//如果左边界点存在并找到,则开始爬线
    {
        //变量声明
        L_edge[0].row = L_start_y;
        L_edge[0].col = L_start_x;
        L_edge[0].flag = 1;
        int16 curr_row = L_start_y;//初始化行坐标
        int16 curr_col = L_start_x;//初始化列坐标
        dire_left = 0; //初始化上个边界点的来向
        //开始搜线,最多取150个点,不会往下搜,共7个方位
        for(int i = 1;i < L_search_amount; i++)    //最多搜索150个点
        {
            越界退出 行越界和列越界(向上向下向左向右)
            if(curr_row+1 < Boundary_search_end || curr_row>IMAGE_H-1)  break;
            //搜线过程
            if(dire_left != 2&&image_use[curr_row-1][curr_col-1]==BLACK&&image_use[curr_row-1][curr_col]==WHITE)   //左上黑,2,右边白
            {
                curr_row = curr_row -1;
                curr_col = curr_col -1;
                L_edge_count = L_edge_count +1;
                dire_left = 7;
                L_edge[i].row = curr_row;
                L_edge[i].col = curr_col;
                L_edge[i].flag = 1;
            }
            else if(dire_left!=3&&image_use[curr_row-1][curr_col+1]==BLACK&&image_use[curr_row][curr_col+1]==WHITE)    //右上黑,3,下边白
            {
                curr_row = curr_row -1;
                curr_col = curr_col + 1;
                L_edge_count = L_edge_count + 1;
                dire_left = 6;
                L_edge[i].row = curr_row;
                L_edge[i].col = curr_col;
                L_edge[i].flag = 1;
            }
            else if(image_use[curr_row-1][curr_col]==BLACK&&image_use[curr_row-1][curr_col+1]==WHITE)                  //正上黑,1,右白
            {
                curr_row = curr_row - 1;
                L_edge_count = L_edge_count + 1;
                dire_left = 0;
                L_edge[i].row = curr_row;
                L_edge[i].col = curr_col;
                L_edge[i].flag = 1;
            }
            else if(dire_left!=5&&image_use[curr_row][curr_col-1]==BLACK&&image_use[curr_row-1][curr_col-1]==WHITE)     //正左黑,5,上白
            {
                curr_col = curr_col - 1;
                L_edge_count = L_edge_count +1;
                dire_left = 4;
                L_edge[i].row = curr_row;
                L_edge[i].col = curr_col;
                L_edge[i].flag = 1;
            }
            else if(dire_left!=4&&image_use[curr_row][curr_col+1]==BLACK&&image_use[curr_row+1][curr_col+1]==WHITE)  //正右黑,4,下白
            {
                curr_col = curr_col + 1;
                L_edge_count = L_edge_count +1;
                dire_left = 5;
                L_edge[i].row = curr_row;
                L_edge[i].col = curr_col;
                L_edge[i].flag = 1;
            }
            else if(dire_left!=6&&image_use[curr_row+1][curr_col-1]==BLACK&&image_use[curr_row][curr_col-1]==WHITE)    //左下黑,6,上白
            {
                curr_row = curr_row + 1;
                curr_col = curr_col -1;
                L_edge_count = L_edge_count +1;
                dire_left = 3;
                L_edge[i].row = curr_row;
                L_edge[i].col = curr_col;
                L_edge[i].flag = 1;
            }
            else if(dire_left!=7&&image_use[curr_row+1][curr_col+1]==BLACK&&image_use[curr_row+1][curr_col]==WHITE)    //右下黑,7,左白
            {
                curr_row = curr_row + 1;
                curr_col = curr_col + 1;
                L_edge_count = L_edge_count +1;
                dire_left = 2;
                L_edge[i].row = curr_row;
                L_edge[i].col = curr_col;
                L_edge[i].flag = 1;
            }
            else
                break;
        }
    }

    if(right_findflag)//如果右边界存在并搜到
             {
                 R_edge[0].row = R_start_y;
                 R_edge[0].col = R_start_x;
                 R_edge[0].flag = 1;
                 int16 curr_row = R_start_y;
                 int16 curr_col = R_start_x;
                 dire_right = 0;
                 for(int i = 1;i<R_search_amount;i++)
                 {
		越界退出 行越界和列越界(向上向下向左向右)
                     if(curr_row < Boundary_search_end || curr_row>IMAGE_H-1||curr_row+1<Boundary_search_end)  break;
                     //爬线过程
                     if(curr_col<IMAGE_W&&dire_right!=3&&image_use[curr_row-1][curr_col+1]==BLACK&&image_use[curr_row-1][curr_col]==WHITE)    //右上黑,3,左白
                     {
                         curr_row = curr_row - 1;
                         curr_col = curr_col + 1;
                         R_edge_count = R_edge_count + 1;
                         dire_right = 6;
                         R_edge[i].row = curr_row;
                         R_edge[i].col = curr_col;
                         R_edge[i].flag = 1;
                     }
                     else if(dire_right!=2&&image_use[curr_row-1][curr_col-1]==BLACK&&image_use[curr_row][curr_col-1]==WHITE) //左上黑,2,下白
                     {
                         curr_row = curr_row-1;
                         curr_col = curr_col-1;
                         R_edge_count = R_edge_count + 1;
                         dire_right = 7;
                         R_edge[i].row = curr_row;
                         R_edge[i].col = curr_col;
                         R_edge[i].flag = 1;
                     }
                     else if(image_use[curr_row-1][curr_col]==BLACK&&image_use[curr_row-1][curr_col-1]==WHITE)                  //正上黑,1,左白
                     {
                         curr_row = curr_row - 1;
                         R_edge_count = R_edge_count + 1;
                         dire_right = 0;
                         R_edge[i].row = curr_row;
                         R_edge[i].col = curr_col;
                         R_edge[i].flag = 1;
                     }
                     else if(dire_right!=4&&image_use[curr_row][curr_col+1]==BLACK&&image_use[curr_row-1][curr_col+1]==WHITE)   //正右黑,4,上白
                     {
                         curr_col = curr_col + 1;
                         R_edge_count = R_edge_count + 1;
                         dire_right = 5;
                         R_edge[i].row = curr_row;
                         R_edge[i].col = curr_col;
                         R_edge[i].flag = 1;
                     }
                     else if(dire_right!=5&&image_use[curr_row][curr_col-1]==BLACK&&image_use[curr_row+1][curr_col-1]==WHITE)   //正左黑,5,下白
                     {
                         curr_col = curr_col-1;
                         R_edge_count = R_edge_count + 1;
                         dire_right = 4;
                         R_edge[i].row = curr_row;
                         R_edge[i].col = curr_col;
                         R_edge[i].flag = 1;
                     }


                     else if(dire_right!=6&&image_use[curr_row+1][curr_col-1]==BLACK&&image_use[curr_row+1][curr_col]==WHITE)   //左下黑,6,右白
                     {
                         curr_row = curr_row + 1;
                         curr_col = curr_col - 1;
                         R_edge_count = R_edge_count + 1;
                         dire_right = 3;
                         R_edge[i].row = curr_row;
                         R_edge[i].col = curr_col;
                         R_edge[i].flag = 1;
                     }
                     else if(dire_right!=7&&image_use[curr_row+1][curr_col+1]==BLACK&&image_use[curr_row][curr_col+1]==WHITE)   //右下黑,7,上白
                     {
                         curr_row = curr_row + 1;
                         curr_col = curr_col + 1;
                         R_edge_count = R_edge_count + 1;
                         dire_right = 2;
                         R_edge[i].row = curr_row;
                         R_edge[i].col = curr_col;
                         R_edge[i].flag = 1;
                     }
                     else
                         break;
                 }
             }
}

  • 20
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小_扫地僧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值