【DW打卡-计算机视觉基础】05 图像分割/二值化

5.1 简介

图像阈值化的目的是要按照灰度级,对像素集合进行一个划分,得到的每个子集形成一个与现实景物相对应的区域,各个区域内部具有一致的属性,而相邻区域不具有这种一致属性。这样的划分可以通过从灰度级出发选取一个或多个阈值来实现。

5.2 学习目标

  • 了解阈值分割基本概念

  • 理解最大类间方差法(大津法)、自适应阈值分割的原理

  • 掌握OpenCV框架下上述阈值分割算法API的使用

5.4 算法理论介绍

5.4.1 最大类间方差法(大津阈值法)

从大津法的原理上来讲,该方法又称作最大类间方差法,因为按照大津法求得的阈值进行图像二值化分割后,前景与背景图像的类间方差最大。

因方差是灰度分布均匀性的一种度量,背景和前景之间的类间方差越大,说明构成图像的两部分的差别越大,当部分前景错分为背景或部分背景错分为前景都会导致两部分差别变小。因此,使类间方差最大的分割意味着错分概率最小。

应用: 是求图像全局阈值的最佳方法,应用不言而喻,适用于大部分需要求图像全局阈值的场合。

优点: 计算简单快速,不受图像亮度和对比度的影响。

缺点: 对图像噪声敏感;只能针对单一目标分割;当目标和背景大小比例悬殊、类间方差函数可能呈现双峰或者多峰,这个时候效果不好。

5.4.2 自适应阈值

前面介绍了OTSU算法,但这算法属于全局阈值法,所以对于某些光照不均的图像,这种全局阈值分割的方法会显得苍白无力。

这种办法就是自适应阈值法(adaptiveThreshold),它的思想不是计算全局图像的阈值,而是根据图像不同区域亮度分布,计算其局部阈值,所以对于图像不同区域,能够自适应计算不同的阈值,因此被称为自适应阈值法。(其实就是局部阈值法)

如何确定局部阈值呢?可以计算某个邻域(局部)的均值、中值、高斯加权平均(高斯滤波)来确定阈值。值得说明的是:如果用局部的均值作为局部的阈值,就是常说的移动平均法。

opencv代码实现

import cv2
import numpy as np
from matplotlib import pyplot as plt

if __name__ == '__main__':

    img = cv2.imread('./00_dog.jpg', cv2.IMREAD_UNCHANGED)
    """
    @url: https://www.codenong.com/cs105846738/
    
    cv2.threshold 参数:
        * src —	input array (single-channel, 8-bit or 32-bit floating point).
        * thresh —	 threshold value.
        * maxval   —	maximum value to use with the THRESH_BINARY and THRESH_BINARY_INV thresholding types.
        * type	— thresholding type 参考:[thresholdType](
    """
    ret, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
    ret, thresh2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
    ret, thresh3 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
    ret, thresh4 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
    ret, thresh5 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)

    titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
    images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
    for i in range(6):
        plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
        plt.title(titles[i])
        plt.xticks([]), plt.yticks([])
    plt.show()


    # COLOR_RGB2RGBA = 0  这里必不可少
    img_literacy = cv2.imread('./00_dog.jpg', 0)
    """
    @url: https://www.codenong.com/cs105846738/
    
        adaptiveThreshold(src: Any,             #源图像
                          maxValue: Any,        #分配给超过阈值的像素值的最大值
                          adaptiveMethod: Any,  #在一个邻域内计算阈值所采用的算法,有两个取值,分别为 ADAPTIVE_THRESH_MEAN_C 和 ADAPTIVE_THRESH_GAUSSIAN_C
                          thresholdType: Any,   #这是阈值类型,只有两个取值,分别为 THRESH_BINARY 和THRESH_BINARY_INV
                          blockSize: Any,       #adaptiveThreshold的计算单位是像素的邻域块,这是局部邻域大小
                          C: Any,               #这个参数实际上是一个偏移值调整量,用均值和高斯计算阈值后,再减或加这个值就是最终阈值
                          dst: Any = None)      #输出图像
    """

    # adaptive threshold
    thresh1 = cv2.adaptiveThreshold(img_literacy, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 0)
    thresh2 = cv2.adaptiveThreshold(img_literacy, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
    thresh3 = cv2.adaptiveThreshold(img_literacy, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 0)
    thresh4 = cv2.adaptiveThreshold(img_literacy, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)

    # show image 
    plt.figure('adaptive threshold', figsize=(12, 8))
    plt.subplot(231), plt.imshow(img_literacy, cmap='gray'), plt.title('original')
    plt.subplot(232), plt.imshow(thresh1, cmap='gray'), plt.title('adaptive_mean_0')
    plt.subplot(235), plt.imshow(thresh2, cmap='gray'), plt.title('adaptive_mean_2')
    # adaptive_gaussian_0 自适应高斯分布
    plt.subplot(233), plt.imshow(thresh3, cmap='gray'), plt.title('adaptive_gaussian_0')
    plt.subplot(236), plt.imshow(thresh4, cmap='gray'), plt.title('adaptive_gaussian_2')
    plt.show()

输出测试1 - 最大类间方差法

输出测试2 - 自适应阈值法

posted @ 2021-09-22 21:01  山枫叶纷飞  阅读(65)  评论(0编辑  收藏  举报