zoukankan      html  css  js  c++  java
  • 2. 二值化

    一、 二值化

         二值化就是让图像的像素点矩阵中的每个像素点的灰度值为0(黑色)或者255(白色),也就是让整个图像呈现只有黑和白的效果。在灰度化的图像中灰度值的范围为0~255,在二值化后的图像中的灰度值范围是0或者255。

          黑色:

                   二值化后的R =  0

                   二值化后的G =  0

                   二值化后的B =  0

          白色:

                   二值化后的R =  255

                   二值化后的G =  255

                   二值化后的B =  255

           那么一个像素点在灰度化之后的灰度值怎么转化为0或者255呢?比如灰度值为100,那么在二值化后到底是0还是255?这就涉及到取一个阀值的问题。

    三、阈值求取算法

          1. 傻瓜法

           

          2. 大律二值算法

            将图像理解成255个图层,每一层分布了不同的像素,这些像素垂直叠加合成了一张完整的灰度图。就是找到一个合适的灰度值,大于这个值的我们将它称之为背景(灰度值越大像素越黑),小于这个值的我们

     将它称之为前景(灰度值越小像素越白)。

    h:图像的宽度

    w:图像的高度(h*w 得到图像的像素数量) 

    t :灰度阈值(我们要求的值,大于这个值的像素我们将它的灰度设置为255,小于的设置为0)

    n0:小于阈值的像素,前景

    n1:大于等于阈值的像素,背景

    n0 + n1 == h * w

    w0:前景像素数量占总像素数量的比例

    w0 = n0 / (h * w)

    w1:背景像素数量占总像素数量的比例

    w1 = n1 / (h * w)

    w0 + w1 == 1 

    u0:前景平均灰度

    u0 = n0灰度累加和 / n0

    u1:背景平均灰度

    u1 = n1灰度累加和 / n1 

    u:平均灰度

    u = (n0灰度累加和 + n1灰度累加和) / (h * w) 根据上面的关系

    u = w0 * u0 + w1 * u1

    g:类间方差(那个灰度的g最大,哪个灰度就是需要的阈值t)

    g = w0 * (u0 - u)^2 + w1 * (u1 - u)^2

    根据上面的关系,可以推出:(这个一步一步推导就可以得到)

    g = w0 * w1 * (u0 - u1) ^ 2

    然后,遍历每一个灰度值,找到这个灰度值对应的 g

    找到最大的 g 对应的 t;

     

    算法实现

    Mat Binary_OSTU(Mat img)
    {
        // get height and width
        int width = img.cols;
        int height = img.rows;
        Mat out = Mat::zeros(height, width, CV_8UC1);
        double p0 = 0;
        double u0 = 0;
        double p1 = 0;
        double u1 = 0;
        double n0 = 0;
        double n1 = 0;
        int val;
        double max_sb = 0, sb = 0;
        int threshold = 0;
        for (int k = 0; k < 255; k++)
        {
            p0 = 0;
            u0 = 0;
            p1 = 0;
            u1 = 0;
            n0 = 0;
            n1 = 0;
            //分为两类
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    val = (int)(img.at<uchar>(i, j));
                    if (val < k)
                    {
                        n0++;
                        u0 += val;
                    }
                    else
                    {
                        n1++;
                        u1 += val;
                    }
                }
            }
            //求出概率,均值
            u0 = u0 / n0;  //第一类均值
            u1 = u1 / n1;
    
            p0 = n0 / (width* height);
            p1 = n1 / (width* height);
            sb = p0 * p1*pow((u0 - u1), 2);
    
            if (sb > max_sb)
            {
                max_sb = sb;
                threshold = k;
            }
        }
    
        cout << "threshold:  " << threshold << endl;
    
        for (int i = 0; i < height; i++)
        {
            for (int j = 0; j < width; j++)
            {
                if ((int)img.at<uchar>(i, j) > threshold)
                    out.at<uchar>(i, j) = 255;
                else
                    out.at<uchar>(i, j) = 0;
    
            }
        }
    
        return out;
    }

     参考文献:

                    Otsu N. A threshold selection method from gray-level histogram. IEEE Trans,1979;SMC-9;62-66

                    https://www.cnblogs.com/funfei/p/6943665.html

                    https://zhuanlan.zhihu.com/p/95034826

  • 相关阅读:
    NumPy数组基本的索引和切片
    赫夫曼树编码解码实例(C)
    深度优先迷宫求解实例(C)
    创建ndarray的方法
    【学习笔记】计算机网络-利用TELNET进行SMTP的邮件发送
    【学习笔记】非递归实现先后根遍历二叉树
    【学习笔记】计算机网络-DNS层次查询
    【学习笔记】计算机网络-网络常用命令(一)
    【学习笔记】计算机网络-Ping命令(一)
    Win10下Wireshark找不到接口的解决办法
  • 原文地址:https://www.cnblogs.com/xingyuanzier/p/13246822.html
Copyright © 2011-2022 走看看