OpenCV-图像阈值-简单阈值、自适应阈值、Otsu’s 二值化

  • 简单阈值(全局阈值)

  函数:threshold(src, thresh, maxval, type, dst=None),返回两个值retVal(阈值) 和 threshImg(处理后的图像)

    函数中四个参数分别是原图像、阈值、最大值、阈值类型 

  阈值类型一般分为五种: 
    cv2.THRESH_BINARY:大于阈值的部分像素值变为maxval,其他变为0 
    cv2.THRESH_BINARY_INV:大于阈值的部分变为0,其他部分变为最大值 
    cv2.THRESH_TRUNC:大于阈值的部分变为阈值,其余部分不变 
    cv2.THRESH_TOZERO:大于阈值的部分不变,其余部分变为0 
    cv2.THRESH_TOZERO_INV:大于阈值的部分变为0,其余部分不变

 1 import numpy as np
 2 import cv2
 3 from matplotlib import pyplot as plt
 4 
 5 # 读取灰度图
 6 img = cv2.imread("../image/sight.jpg", 0)
 7 
 8 ret1, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
 9 ret2, thresh2=cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
10 ret3, thresh3=cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
11 ret4, thresh4=cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
12 ret5, thresh5=cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)
13 
14 titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
15 images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
16 for i in range(6):
17     plt.subplot(2,3,i + 1),plt.imshow(images[i], 'gray')
18     plt.title(titles[i])
19     plt.xticks([]), plt.yticks([])
20 plt.show()

结果:

  •  自适应阈值

  在前面的部分我们使用是全局阈值,整幅图像采用同一个数作为阈值。当时这种方法并不适应与所有情况,尤其是当同一幅图像上的不同部分的具有不同亮度时。这种情况下我们需要采用自适应阈值。此时的阈值是根据图像上的每一个小区域计算与其对应的阈值。因此在同一幅图像上的不同区域采用的是不同的阈值,从而使我们能在亮度不同的情况下得到更好的结果。

  adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C, dst=None)
  这种方法需要我们指定六个参数,返回值只有一个。

    • Adaptive Method- 指定计算阈值的方法。
      – cv2.ADPTIVE_THRESH_MEAN_C:阈值取自相邻区域的平均值
      – cv2.ADPTIVE_THRESH_GAUSSIAN_C:阈值取值相邻区域的加权和,权重为一个高斯窗口。
    • Block Size - 邻域大小(用来计算阈值的区域大小)。
    • C - 这就是是一个常数,阈值就等于的平均值或者加权平均值减去这个常数。

代码:

 1 import numpy as np
 2 import cv2
 3 from matplotlib import pyplot as plt
 4 
 5 # 读取灰度图
 6 img = cv2.imread("../image/sight.jpg", 0)
 7 
 8 # 中值滤波,用来平滑图像,去除噪声
 9 img = cv2.medianBlur(img, 5)
10 
11 # 简单阈值
12 ret, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
13 
14 # 自适应,阈值取相邻区域的平均值
15 thresh2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
16 
17 # 自适应,阈值取值相邻区域的加权和,权重为一个高斯窗口。
18 thresh3 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
19 
20 
21 titles = ['Original Image', 'Global Thresholding (v = 127)',
22 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
23 images = [img, thresh1, thresh2, thresh3]
24 for i in range(4):
25     plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
26     plt.title(titles[i])
27     plt.xticks([]),plt.yticks([])
28 plt.show()

结果:

如果不进行滤波处理,会出现噪声,如下图所示:

  •  Otsu’s 二值化

  在使用全局阈值时,只能通过不停的尝试来确定一个效果比较好的阈值。如果是一副双峰图像(简单来说双峰图像是指图像直方图中存在两个峰)呢?我们岂不是应该在两个峰之间的峰谷选一个值作为阈值?这就是 Otsu 二值化要做的。简单来说就是对一副双峰图像自动根据其直方图计算出一个阈值。(对于非双峰图像,这种方法得到的结果可能会不理想)。 

  函数还是 cv2.threshold(),但是需要多传入一个参数( flag): cv2.THRESH_OTSU。这时要把阈值设为 0。然后算法会找到最优阈值,这个最优阈值就是返回值 retVal。如果不使用 Otsu 二值化,返回的retVal 值与设定的阈值相等。

  算法分类的原理是让背景和目标之间的类间方差最大,因为背景和目标之间的类间方差越大,说明构成图像的两部分的差别越大,错分的可能性越小。 

代码:

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

# 读取灰度图
img = cv2.imread("../image/girl.jpg", 0)

# 全局阈值
ret1, th_img1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

# Otsu’s 二值化
re2, th_img2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# Otsu’s 二值化之前先对图像进行高斯滤波处理,平滑图像,去除噪声
# (5,5)为高斯核大小,0为标准差
blur = cv2.GaussianBlur(img, (5, 5), 0)
re3, th_img3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)


images = [img, 0, th_img1,
          img, 0, th_img2,
          blur, 0, th_img3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
          'Original Noisy Image','Histogram',"Otsu's Thresholding",
          'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]

for i in range(3):
    plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
    plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
    plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
    plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()

结果: 高斯滤波后在进行二值化处理,会有明显的去除噪声的效果。(打印后看到, Otsu’s 二值化自动选取的阈值为122)

 

posted @ 2019-07-18 22:05  bingma  阅读(15612)  评论(0编辑  收藏  举报