• OpenCV3入门(五)图像的阈值


    1、图像阈值与二值化

    阈值是一种简单的图像分割方法,一幅图像包括目标物体(前景)、背景还有噪声,要想从数字图像中直接提取出目标物体,可以设定一个像素值即阈值,然后用图像的每一个像素点和阈值做比较,给出判定结果。

    二值化是特殊的阈值分割方法,把图像分为两部分,以阈值T为分割线,大于T的像素群和小于T的像素群,这样图像就变为黑白二色图像。通过设定一个标准如果大于这个标准就设为白,如果小于这个标准就设为黑,而这个标准就是阈值。

    2、OpenCV阈值threshold

    double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type);

    (1)第一个参数,InputArray 类型的 src,源图像。单通道,8 或 32位浮点数类型的深度。

    (2)第二个参数,OutputArray 类型的 dst,输出图像。

    (3)第三个参数,double 类型的 thresh,选取的阈值。

    (4)第四个参数,double 类型的 maxval。

    (5)第五个参数,int 类型的 type。阈值类型。如下所示:

    type类型如下:

    enum  cv::ThresholdTypes { 
      cv::THRESH_BINARY = 0, 
      cv::THRESH_BINARY_INV = 1, 
      cv::THRESH_TRUNC = 2, 
      cv::THRESH_TOZERO = 3, 
      cv::THRESH_TOZERO_INV = 4, 
      cv::THRESH_MASK = 7, 
      cv::THRESH_OTSU = 8, 
      cv::THRESH_TRIANGLE = 16 
    }

    不同的阈值方法生成关系如下图。

    Mat img = Mat::zeros(6, 6, CV_8UC1);
    randu(img, 0, 255);
    
    int th = 100;
    Mat threshold1, threshold2, threshold3, threshold4, threshold5, threshold6, threshold7, threshold8;
    threshold(img, threshold1, th, 200, THRESH_BINARY);
    threshold(img, threshold2, th, 200, THRESH_BINARY_INV);
    threshold(img, threshold3, th, 200, THRESH_TRUNC);
    
    cout << "raw=
    "<<img << "
    " << endl;
    cout << "THRESH_BINARY=
    " << threshold1 << "
    " << endl;
    cout << "THRESH_BINARY_INV=
    " << threshold2 << "
    " << endl;
    cout << "THRESH_TRUNC=
    " << threshold3 << "
    " << endl;

    上面代码中randu(img, 0, 255)作用是产出随机数填充img矩阵。输出结果如下。

    raw=
    [ 91,   2,  79, 179,  52, 205;
     236,   8, 181, 239,  26, 248;
     207, 218,  45, 183, 158, 101;
     102,  18, 118,  68, 210, 139;
     198, 207, 211, 181, 162, 197;
     191, 196,  40,   7, 243, 230]
    
    THRESH_BINARY=
    [  0,   0,   0, 200,   0, 200;
     200,   0, 200, 200,   0, 200;
     200, 200,   0, 200, 200, 200;
     200,   0, 200,   0, 200, 200;
     200, 200, 200, 200, 200, 200;
     200, 200,   0,   0, 200, 200]
    
    THRESH_BINARY_INV=
    [200, 200, 200,   0, 200,   0;
       0, 200,   0,   0, 200,   0;
       0,   0, 200,   0,   0,   0;
       0, 200,   0, 200,   0,   0;
       0,   0,   0,   0,   0,   0;
       0,   0, 200, 200,   0,   0]
    
    THRESH_TRUNC=
    [ 91,   2,  79, 100,  52, 100;
     100,   8, 100, 100,  26, 100;
     100, 100,  45, 100, 100, 100;
     100,  18, 100,  68, 100, 100;
     100, 100, 100, 100, 100, 100;
     100, 100,  40,   7, 100, 100]

    THRESH_BINARY,thresh=100,maxval=200,大于阈值限定为200,小于阈值清零。

    THRESH_BINARY_INV的作用和THRESH_BINARY 相反,小于阈值置200,大于阈值清。

    THRESH_TRUNC的作用是对大于阈值的数据进行截断,其余值保留原值不变。

    图像阈值例子如下。

    Mat img = imread("D:/WORK/5.OpenCV/LeanOpenCV/pic_src/pic6.bmp", IMREAD_GRAYSCALE);
    int th = 100;
    Mat threshold1, threshold2, threshold3, threshold4, threshold5, threshold6, threshold7, threshold8;
    threshold(img, threshold1, th, 200, THRESH_BINARY);
    threshold(img, threshold2, th, 200, THRESH_BINARY_INV);
    threshold(img, threshold3, th, 200, THRESH_TRUNC);
    
    imshow("raw pic",img);
    imshow("THRESH_BINARY", threshold1);
    imshow("THRESH_BINARY_INV", threshold2);
    imshow("THRESH_TRUNC", threshold3);

    3、自动阈值—大津法OTSU

    最大类间方差是由日本学者大津(Nobuyuki Otsu)于1979年提出,是一种自适应的阈值确定方法。算法假设图像像素能够根据阈值,被分成背景[background]和目标[objects]两部分。然后,计算该最佳阈值来区分这两类像素,使得两类像素区分度最大。

    算法原理为:

    设图像Img长宽尺寸为M*N, T为二值化的阈值;

    N0为灰度小于T的像素的个数,N0的平均灰度为μ0。

    N1 为灰度大于T的像素的个数,N1的平均灰度为μ1。

    ω0=N0/ M×N                   (1)   //落在N0的概率

    ω1=N1/ M×N                   (2)  //落在N1的概率

    N0+N1=M×N                    (3)  

    ω0+ω1=1                        (4)       

    μ=ω0*μ0+ω1*μ1              (5)  //平均灰度乘以概率 再相加

    g=ω0(μ0-μ)^2+ω1(μ1-μ)^2     (6)   //类间方差

    将式(5)代入式(6),得到等价公式: g=ω0ω1(μ0-μ1)^2    (7)     

    OpenCV自带了OSTU算法。

    Mat img = imread("D:/WORK/5.OpenCV/LeanOpenCV/pic_src/pic2.bmp", IMREAD_GRAYSCALE);
    int th = 100;
    Mat threshold1, threshold2, threshold3;
    threshold(img, threshold1, th, 255, THRESH_BINARY);
    threshold(img, threshold2, th, 255, THRESH_TRUNC);
    threshold(img, threshold3, th, 255, THRESH_OTSU); // 阈值随意设置即可
    
    imshow("raw pic",img);
    imshow("THRESH_BINARY", threshold1);
    imshow("THRESH_TRUNC",  threshold2);
    imshow("THRESH_OTSU",   threshold3);

    使用大津法时阈值可以不设置或随意设置,函数会自动计算最合适的阈值,输出图像如下。

    大津法相比其他二值化方法,能很好的筛选出前景图和背景图,让图像分类后黑白区分度最大。

    4、参考文献

    1、《学习OpenCV》,清华大学出版社,Gary Bradski, Adrian kaehler著

    2、Miscellaneous Image Transformations

    https://docs.opencv.org/3.1.0/d7/d1b/group__imgproc__misc.html#gae8a4a146d1ca78c626a53577199e9c57

    3、OpenCV threshold函数详解

    https://blog.csdn.net/weixin_42296411/article/details/80901080

    4、详细及易读懂的 大津法(OTSU)原理 和 算法实现

    https://blog.csdn.net/u012198575/article/details/81128799

    尊重原创技术文章,转载请注明。

    https://www.cnblogs.com/pingwen/p/12300590.html

  • 相关阅读:
    uva 11080(二分图染色)
    poj 3255(次短路)
    uva 707(记忆化搜索)
    uva 436(floyd变形)
    uva 11748(求可达矩阵)
    uva 11573(bfs)
    Codeforces Round #226 (Div. 2) 解题报告
    uva 11354(最小瓶颈路--多组询问 MST+LCA倍增)
    uva 534(最小瓶颈路)
    uva 538(简单图论 入度出度)
  • 原文地址:https://www.cnblogs.com/pingwen/p/12300590.html
Copyright © 2020-2023  润新知