【进阶】Otsu处理
Otsu算法是由日本学者OTSU于1979年提出的一种对图像进行二值化的高效算法。
1. 引入
在使用函数cv2.threshold()进行阈值处理时,需要自定义一个阈值,并以此阈值作为图像阈值处理的依据。通常情况下处理的图像都是色彩均衡的,这时直接将阈值设为127是比较合适的。**但是,有时图像灰度级的分布是不均衡的,如果此时还将阈值设置为127,那么阈值处理的结果就是失败的。**例如,有一个图像img,其像素值为:
[[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]]
此时,如果仍然以127作为阈值,那么阈值处理结果是:
[[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]]
可以看出这不是我们想要的结果。通过观察,我们可以发现如果以125为阈值进行分割,可以得到比较好的结果:
[[0 0 0 0 0]
[0 0 0 0 0]
[0 0 255 255 255]
[255 255 255 255 255]
[255 255 255 255 255]]
上图只是一个5x5的图像,非常非常小,现实中的图像都是很大、很复杂的,不可能通过肉眼找到合适的分割阈值。因此,日本学者OTSU找到了一种能够根据当前图像给出最佳的类间分割阈值的方法,叫做Otsu方法,其思想是,Otsu方法会遍历所有可能阈值,从而找到最佳的阈值。
2. Otsu阈值分割实现
通过在函数cv2.threshold()中对参数type的类型多传递一个参数cv2.THRESH_OTSU,即可实现Otsu方式的阈值分割。需要注意的是,在使用Otsu方法时,要把阈值设为0(thresh = 0)。其函数格式为:
retval, otsu = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
注意以上代码与普通阈值分割的三点不同之处:
参数
type新增一个参数cv2.THRESH_OTSU。设定的阈值为0。
返回值
retval是Otsu方法计算得到并使用的最佳阈值。
测试
"""
Author: Will Wang
Email: WillWang1998@163.com
"""
import cv2
import numpy as np
image = np.zeros((5, 5), dtype=np.uint8) # uint8:unsigned int 8bit 无符号整型 范围[0:255]
image[0:6, 0:6] = 123
image[2:6, 2:6] = 126
print(f'origin image = \n{image}')
retval1, threshold1 = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)
print(f'retval1={retval1}, threshold1 = \n {threshold1}')
retval2, otsu = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
print(f'retval2={retval2}, otsu = \n{otsu}')
结果如下:

如果对图像进行处理,对比效果如何?

左图为原始图像;中间为进行普通二值化阈值处理,以127为阈值的处理结果;右图是采用采用cv2.THRESH_OTSU的处理结果。可以看到,原始图像整体的亮度比较高,即像素点的值>127的占比较大,所以,采用Otsu可以得到更好的阈值处理结果。