【OpenCV 学习笔记】第六章: 阈值处理

第六章: 阈值处理

  • 为什么要对图像进行阈值处理?
    当同一幅图像不同部分具有不同的亮度时,对其进行阈值处理后,我们可以得到一张对比度不同的图片。图像阈值处理也是图像分割操作的一个环节。

一、简单阈值处理(全局阈值处理)
二、自适应阈值处理(采取局部阈值的方式进行处理)
三、Otsu阈值处理(自动寻找最佳的全局阈值)

一、简单阈值处理

  • 阈值处理函数:cv2.threshold(src, thresh, maxval, type, dst=None)
    Argument:
        src: 原图像,就是要进行阈值处理的原图对象。
        thresh: 阈值,就是进行分类的阈值。
        maxval: 当type指定为THRESH_BINARY或THRESH_BINARY_INV时,才需要设置该值。指的是高于(低于)阈值时赋予的新值。
        type: 指定阈值处理的方法,常用的有:
           • cv2.THRESH_BINARY(黑白二值)
           • cv2.THRESH_BINARY_INV(黑白二值反转)
           • cv2.THRESH_TRUNC (截断阈值化处理)
           • cv2.THRESH_TOZERO
           • cv2.THRESH_TOZERO_INV
        dst: 目标图像
    该函数有两个返回值,第一个retVal(得到的阈值值,因为有时要自动找阈值),第二个就是阈值化后的图像。
    # 例6.1 观察cv2.THRESH_BINARY 二值化阈值处理方法的效果  
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img = np.random.randint(0, 256, (4,5), np.uint8)
    t, dst = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)  #大于127的像素点都处理成第三个参数值,小于127的像素点都处理成0
    
    lena = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp')
    t1, dst1 = cv2.threshold(lena, 127, 255, cv2.THRESH_BINARY)
    
    plt.subplot(121), plt.imshow(dst)
    plt.subplot(122), plt.imshow(dst1)
    plt.show()

     说明:
    对于一幅色彩均衡的图像,我们一般直接将阈值设为127,这个阈值是经验获得的,设置这个阈值是比较合适的。所以一般我们进行阈值处理的时候都那127这个数试。
    但是,当有的图像色彩分布不均衡时,我们再那127这个阈值,效果就会很差,此时我们就要考虑别的阈值处理方法,比如自适应阈值处理方法或者Otsu方法。

    # 例6.2 观察cv2.THRESH_BINARY_INV 反二值化阈值处理方法的效果 
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img = np.random.randint(0, 256, (4,5), np.uint8)
    t, dst = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)  #大于127的像素点都处理成0,小于127的像素点都处理成第三个像素值
    
    lena = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp')
    t1, dst1 = cv2.threshold(lena, 127, 255, cv2.THRESH_BINARY_INV)
    
    plt.subplot(121), plt.imshow(dst)
    plt.subplot(122), plt.imshow(dst1)
    plt.show()

    # 例6.3 观察cv2.HTRESH_TRUNC 截断阈值处理方法的效果 
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img = np.random.randint(0, 256, (4,5), np.uint8)
    t, dst = cv2.threshold(img, 127, -6, type=cv2.THRESH_TRUNC)  #将大于127的像素点都设置为127,将小于等于127的像素点都保持不变。
    
    lena = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp')
    t1, dst1 = cv2.threshold(lena, 127, 127, cv2.THRESH_TRUNC)   #此时第三个参数是没有意义的。
    
    plt.subplot(121), plt.imshow(dst)
    plt.subplot(122), plt.imshow(dst1)
    plt.show()

    # 例6.4 观察cv2.HTRESH_TOZERO_INV 超阈值零处理方法的效果 
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img = np.random.randint(0, 256, (4,5), np.uint8)
    t, dst = cv2.threshold(img, 127, -6, type=cv2.THRESH_TOZERO_INV)  #将大于阈值127的像素点都设置为0,将小于等于127的像素点都保持不变。
    
    lena = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp')
    t1, dst1 = cv2.threshold(lena, 127, 0, cv2.THRESH_TOZERO_INV)   #此时第三个参数是没有意义的。
    
    plt.subplot(121), plt.imshow(dst)
    plt.subplot(122), plt.imshow(dst1)
    plt.show()

    # 例6.5 观察cv2.HTRESH_TOZERO 低阈值零处理方法的效果 
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img = np.random.randint(0, 256, (4,5), np.uint8)
    t, dst = cv2.threshold(img, 127, -6, type=cv2.THRESH_TOZERO)  #将大于阈值127的像素点都保持不变,将小于等于127的像素点都设置为0。
    
    lena = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp')
    t1, dst1 = cv2.threshold(lena, 127, 0, cv2.THRESH_TOZERO)   #此时第三个参数是没有意义的。
    
    plt.subplot(121), plt.imshow(dst)
    plt.subplot(122), plt.imshow(dst1)
    plt.show()

    二、自适应阈值处理

    全局阈值简单粗暴,当一幅图像的色彩不均衡时,用全局阈值分割图像效果就不会很好,此时我们要采用自适应阈值来处理图像。
    自适应阈值就是在图像上每一个小区域计算与其对应的阈值。

  • 自适应阈值处理API:
    cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)
    src: 要进行处理的原始图像
    maxValue: 当参数thresholdType为cv2.THRESH_BINARY或者cv2.THRESH_BINARY_INV时,该参数表示高于(低于)阈值时赋予的新值。
    adaptiveMethod: 计算自适应阈值的方法。这里有2种方法,也就是这个参数有2个可选值。
           第一种方法是:adaptiveMethod=cv2.ADAPTIVE_THRESH_MEAN_C, 这种方法是将邻域所有像素点的权重值都取一样。
           第二种方法是:adaptiveMethod=cv2.ADAPTIVE_THRESH_GAUSSIAN_C, 这种方法是通过高斯公式获得邻域所有像素点的权重值。这种权重值的选取就跟各邻域像素点到目标像素点的距离有关,距离越近权重越高,距离越远权重越低。
    thresholdType: 表示阈值处理方式,这个参数是和maxValue一起搭配使用的。这个参数只能选择cv2.THRESH_BINARY或者cv2.THRESH_BINARY_INV中的一个。
    blockSize:表示邻域尺寸的大小,一般取3,5,7等。
    C: 是常量,阈值等于平均值或者加权平均值减去这个常数。
    # 例6.6 观察cv2.threshold() 和 cv2.adaptiveThreshold()处理效果的差异  
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    computer = cv2.imread(r'C:\Users\25584\Desktop\computer.jpg', 0)
    t1, thresh_127 = cv2.threshold(computer, 127, 255, cv2.THRESH_BINARY)
    adap_mean = cv2.adaptiveThreshold(computer, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 5, 3)
    adap_gaussian = cv2.adaptiveThreshold(computer, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 5, 3)  
    
    plt.subplot(141), plt.imshow(computer)
    plt.subplot(142), plt.imshow(thresh_127)
    plt.subplot(143), plt.imshow(adap_mean)
    plt.subplot(144), plt.imshow(adap_gaussian)
    plt.show()

    三、Otsu阈值处理(自动寻找最佳的全局阈值)

    我们在使用cv2.threshold()进行阈值处理的时候,要传入一个参数就是阈值这个值,这个值我们是凭经验,凭概率,设定了一个127这个值作为阈值。但是有的图像它可能不适合这个阈值,如果我们手动一个个阈值去试就非常费劲,Otusu方法可以帮助我们自动遍历所有可能的阈值,并找出最佳的那个阈值。

    普通的阈值处理函数:cv2.threshold(src, thresh, maxval, type, dst=None)
    Argument:
        src: 原图像,就是要进行阈值处理的原图对象。
        thresh: 阈值,就是进行分类的阈值。
        maxval: 当type指定为THRESH_BINARY或THRESH_BINARY_INV时,才需要设置该值。指的是高于(低于)阈值时赋予的新值。
        type: 指定阈值处理的方法,常用的有:
           • cv2.THRESH_BINARY(黑白二值)
           • cv2.THRESH_BINARY_INV(黑白二值反转)
           • cv2.THRESH_TRUNC (截断阈值化处理)
           • cv2.THRESH_TOZERO
           • cv2.THRESH_TOZERO_INV
        dst: 目标图像
    该函数有两个返回值,第一个retVal(得到的阈值值,因为有时要自动找阈值),第二个就是阈值化后的图像。

    Otsu阈值处理就是把上面的函数的参数type多传入一个参数cv2.THRESH_OTSU就可实现Otsu阈值分割:
    t, otsu = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

    这里就要把thresh参数设为0 , type参数设为cv2.THRESH_BINARY+cv2.THRESH_OTSU

    # 例6.7 实验Otsu阈值处理  
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img = np.zeros((5,5), np.uint8)+123
    img[2:6, 2:6]=126
    t1, result_127 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
    t2, result_otsu = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
    
    img, result_127, result_otsu, t1, t2
    (array([[123, 123, 123, 123, 123],
            [123, 123, 123, 123, 123],
            [123, 123, 126, 126, 126],
            [123, 123, 126, 126, 126],
            [123, 123, 126, 126, 126]], dtype=uint8),
     array([[0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0]], dtype=uint8),
     array([[  0,   0,   0,   0,   0],
            [  0,   0,   0,   0,   0],
            [  0,   0, 255, 255, 255],
            [  0,   0, 255, 255, 255],
            [  0,   0, 255, 255, 255]], dtype=uint8),
     127.0,
     123.0)
    # 例6.8 观察一幅图像使用普通二值化处理和Otsu阈值处理的效果差异   
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    tiffany = cv2.imread(r'C:\Users\25584\Desktop\tiffany.bmp')
    t1, result_127 = cv2.threshold(tiffany, 127, 255, cv2.THRESH_BINARY)  #普通二值化处理
    tiffany_gray = cv2.cvtColor(tiffany, cv2.COLOR_BGR2GRAY)  #把3通道图像先转换为二维图像,这样才能用自动阈值搜索
    t2, result_otsu = cv2.threshold(tiffany_gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)  #Otsu阈值处理,注意Otsu阈值处理只能处理二维图像,所以三维要转换一下
    result_otsu1 = cv2.cvtColor(result_otsu, cv2.COLOR_GRAY2RGB)  #为了matplotlib显示得好看,就把色彩空间再转换一下
    
    plt.subplot(131), plt.imshow(tiffany[:,:,::-1])
    plt.subplot(132), plt.imshow(result_127)
    plt.subplot(133), plt.imshow(result_otsu1)
    plt.show()

     说明:在本例中,由于原图整体的亮度就非常高,所以很多像素的值都大于127,此时我们还用127作为阈值,就得到了大量的白色区域。如果我们用otsu方法处理,就会得到较好的效果。

猜你喜欢

转载自blog.csdn.net/friday1203/article/details/125064675