zoukankan      html  css  js  c++  java
  • 【数字图像处理】灰度图像二值化

    灰度图像

    每副图像的每个像素对应二维空间中一个特定的位置,并且有一个或者多个与那个点相关的采样值组成数值。

    灰度图像,也称为灰阶图像,图像中每个像素可以由0(黑)到255(白)的亮度值(Intensity)表示。0-255之间表示不同的灰度级。

    灰度图像二值化

    二值化:以一个值(阈值)为基准,大于(等于)这个值的数全部变为是1(或者0),小于等于这个数的就全部将他们变为0(或1)。

    二值化算法处理飞思卡尔赛道思路:设定一个阈值valve,对于图像矩阵中的每一行,从左至右比较各像素值和阈值的大小,若像素值大于或等于阈值,则判定该像素对应的是白色赛道;反之,则判定对应的是黑色的目标引导线。

    记下第一次和最后一次出现像素值小于阈值时的像素点的列号,算出两者的平均值,以此作为该行上目标引导线的位置。

    摄像头的二值化的代码:

     
    
    Void image_binaryzation()
    
    {
    
    for(int i=0;i
    
    {
    
        for(int j=0;j
    
        {
    
    if(Image[i][j] >= Threshold)
    
           Image_new[i][j]=1;
    
    else
    
        Image_new[i][j]=0;
    
        }
    
    }
    
    }

    Row是对应采集到的行数,Col是列数,Image[i][j]是摄像头采集未二值化的数据存放的数组,Img[i][j]是新建的存放二值化后的数组。

    合适的阈值

    在阈值二值化中,最主要的是选取合适的阈值,这也是二值化的难点所在。常用的二值化阈值选取方法有双峰法、p参数法、大律法(Otsu法)、最大熵阈值法、迭代法等。

    大律法(Otsu法)

    Otsu方法又名最大类间差方法,通过统计整个图像的直方图特性来实现全局阈值T的自动选取,其算法步骤为:
    1) 先计算图像的直方图,即将图像所有的像素点按照0~255共256个bin,统计落在每个bin的像素点数量
    2) 归一化直方图,也即将每个bin中像素点数量除以总的像素点
    3) i表示分类的阈值,也即一个灰度级,从0开始迭代
    4) 通过归一化的直方图,统计0~i 灰度级的像素(假设像素值在此范围的像素叫做前景像素) 所占整幅图像的比例w0,并统计前景像素的平均灰度u0;统计i~255灰度级的像素(假设像素值在此范围的像素叫做背景像素) 所占整幅图像的比例w1,并统计背景像素的平均灰度u1;
    5) 计算前景像素和背景像素的方差 g = w0*w1*(u0-u1) (u0-u1)
    6) i++;转到4),直到i为256时结束迭代
    7)将最大g相应的i值作为图像的全局阈值
    缺陷:OSTU算法在处理光照不均匀的图像的时候,效果会明显不好,因为利用的是全局像素信息。
    解决光照不均匀:https://blog.csdn.net/kk55guang2/article/details/78475414
                  https://blog.csdn.net/kk55guang2/article/details/78490069
                  https://wenku.baidu.com/view/84e5eb271a37f111f0855b2d.html
    ***************************************************************/ 
    int GetOSTU(uint8_t tmImage[Use_ROWS][Use_Line]) 
    { 
    /**
      * @brief    未优化过的大津法
      *
      * @param    运算时间比较长
      *
      * @return   实测120*160的图像
      *
      * @note     K66 220MHz需要9ms
      *
      * @example  
      *
      * @date     2019/4/16 星期二
      */
    //    int width = Use_ROWS;
    //    int height = Use_Line;
    //    int x = 0, y = 0;
    //    int pixelCount[256];
    //    float pixelPro[256];
    //    int i, j, pixelSum = width * height, threshold = 0;
    //    
    //    
    //    //初始化
    //    for (i = 0; i < 256; i++)
    //    {
    //        pixelCount[i] = 0;
    //        pixelPro[i] = 0;
    //    }
    //    
    //    //统计灰度级中每个像素在整幅图像中的个数
    //    for (i = y; i < height; i++)
    //    {
    //        for (j = x; j <width; j++)
    //        {
    //            pixelCount[tmImage[i][j]]++;
    //        }
    //    }
    //    
    //    //计算每个像素在整幅图像中的比例
    //    for (i = 0; i < 256; i++)
    //    {
    //        pixelPro[i] = (float)(pixelCount[i]) / (float)(pixelSum);
    //    }
    //    
    //    //经典ostu算法,得到前景和背景的分割
    //    //遍历灰度级[0,255],计算出方差最大的灰度值,为最佳阈值
    //    float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0;
    //    for (i = 0; i < 256; i++)
    //    {
    //        w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;
    //        
    //        for (j = 0; j < 256; j++)
    //        {
    //            if (j <= i) //背景部分
    //            {
    //                //以i为阈值分类,第一类总的概率
    //                w0 += pixelPro[j];
    //                u0tmp += j * pixelPro[j];
    //            }
    //            else       //前景部分
    //            {
    //                //以i为阈值分类,第二类总的概率
    //                w1 += pixelPro[j];
    //                u1tmp += j * pixelPro[j];
    //            }
    //        }
    //        
    //        u0 = u0tmp / w0;        //第一类的平均灰度
    //        u1 = u1tmp / w1;        //第二类的平均灰度
    //        u = u0tmp + u1tmp;        //整幅图像的平均灰度
    //        //计算类间方差
    //        deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u);
    //        //找出最大类间方差以及对应的阈值
    //        if (deltaTmp > deltaMax)
    //        {
    //            deltaMax = deltaTmp;
    //            threshold = i;
    //        }
    //    }
    //    //返回最佳阈值;
    //    return threshold;
        
    /**
      * @brief    优化过的大津法
      *
      * @param    大大减少运算时间
      *
      * @return   实测K66 220MHz 120*160的图像
      *
      * @note     只需要1.5ms
      *
      * @example  未优化的大津法需要9ms
      *
      * @date     2019/4/16 星期二
      */ 
        int16_t i,j; 
        uint32_t Amount = 0; 
        uint32_t PixelBack = 0; 
        uint32_t PixelIntegralBack = 0; 
        uint32_t PixelIntegral = 0; 
        int32_t PixelIntegralFore = 0; 
        int32_t PixelFore = 0; 
        float OmegaBack, OmegaFore, MicroBack, MicroFore, SigmaB, Sigma; // 类间方差; 
        int16_t MinValue, MaxValue; 
        uint8_t Threshold = 0;
        uint8_t HistoGram[256];              //  
        
        for (j = 0; j < 256; j++)  HistoGram[j] = 0; //初始化灰度直方图 
        
        for (j = 0; j < Use_ROWS; j++) 
        { 
            for (i = 0; i < Use_Line; i++) 
            { 
                HistoGram[tmImage[j][i]]++; //统计灰度级中每个像素在整幅图像中的个数
            } 
        } 
        
        for (MinValue = 0; MinValue < 256 && HistoGram[MinValue] == 0; MinValue++) ;        //获取最小灰度的值
        for (MaxValue = 255; MaxValue > MinValue && HistoGram[MinValue] == 0; MaxValue--) ; //获取最大灰度的值
        
        if (MaxValue == MinValue)      return MaxValue;         // 图像中只有一个颜色    
        if (MinValue + 1 == MaxValue)  return MinValue;         // 图像中只有二个颜色
        
        for (j = MinValue; j <= MaxValue; j++)    Amount += HistoGram[j];        //  像素总数
        
        PixelIntegral = 0;
        for (j = MinValue; j <= MaxValue; j++)
        {
            PixelIntegral += HistoGram[j] * j;//灰度值总数
        }
        SigmaB = -1;
        for (j = MinValue; j < MaxValue; j++)
        {
            PixelBack = PixelBack + HistoGram[j];   //前景像素点数
            PixelFore = Amount - PixelBack;         //背景像素点数
            OmegaBack = (float)PixelBack / Amount;//前景像素百分比
            OmegaFore = (float)PixelFore / Amount;//背景像素百分比
            PixelIntegralBack += HistoGram[j] * j;  //前景灰度值
            PixelIntegralFore = PixelIntegral - PixelIntegralBack;//背景灰度值
            MicroBack = (float)PixelIntegralBack / PixelBack;   //前景灰度百分比
            MicroFore = (float)PixelIntegralFore / PixelFore;   //背景灰度百分比
            Sigma = OmegaBack * OmegaFore * (MicroBack - MicroFore) * (MicroBack - MicroFore);//计算类间方差
            if (Sigma > SigmaB)                    //遍历最大的类间方差g //找出最大类间方差以及对应的阈值
            {
                SigmaB = Sigma;
                Threshold = j;
            }
        }
        return Threshold;                        //返回最佳阈值;
    } 

    可以参考文献

    https://wenku.baidu.com/view/acc24dcf680203d8ce2f2469.html

    https://wenku.baidu.com/view/bb6e38f7c8d376eeaeaa3163.html

    二值化图像去噪

    对于二值化图像而言,去除噪声是很重要的一步。

    思路:对任意像素点判断是否为0,取得该像素点周围8个或者四个像素点相加,总和等于255 * 8或者 255 *4,则说明该像素点为噪声,置为255。

    注意:领域的计算方法是没有边界的,所以通常不计算图像四边。

                int bai;
                        for(int i = 1; i < Use_ROWS-1; i++)   
                        {
                            for(int j =1; j < Use_Line-1; j++)
                            { if(Image_Use[i-1][j] == 255) continue;     
                              bai = Image_Use[i-1][j] + Image_Use[i-1][j-1] + Image_Use[i-1][j+1] +Image_Use[i][j+1] +Image_Use[i][j-1] +Image_Use[i+1][j] +Image_Use[i+1][j-1] +Image_Use[i+1][j+1] ;
                              if(bai == 2040)
                              Image_Use[i][j] = 255;
                              
                            }
                        }
  • 相关阅读:
    oracle中查询表中先排序再取出前10条数据
    oracle中的数据类型
    读取Oracle中的clob字段
    实现json的序列化和反序列化
    在oracle中where 子句和having子句中的区别
    Oracle Clob字段保存时提示字符串过长
    读取文件夹中的文件并修改数据库中的数据
    【转】display:none与visible:hidden的区别
    实现http访问
    动态生成并执行SQL语句
  • 原文地址:https://www.cnblogs.com/-wenli/p/11486877.html
Copyright © 2011-2022 走看看