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)

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM