In [1]:
import numpy as np
import matplotlib.pyplot as plt
import cv2 as cv
def show(img):
# 判断图片的维度
img = img.astype(np.uint8)
if img.ndim == 2: # 说明是灰度图读取
plt.imshow(img, cmap='gray')
elif img.ndim == 3: # 彩色图片
img2 = cv.cvtColor(img, cv.COLOR_BGR2RGB)
plt.imshow(img2)
else:
print('不知道是什么图!')
return
plt.show()
直方图阈值¶
In [2]:
img = cv.imread("../pic/2color.png")
show(img)
In [3]:
plt.hist(img.ravel(), 256, [0, 256])
plt.show()
In [4]:
plt.hist(img.flatten(), np.arange(-0.5, 256, 1), color='g')
plt.show()
In [5]:
_, img_bin = cv.threshold(img, 125, 255, cv.THRESH_BINARY)
show(img_bin)
三角法阈值¶
三角法求阈值最早见于Zack的论文《Automatic measurement of sister chromatid exchange frequency》主要是用于染色体的研究,该方法是使用直方图数据,基于纯几何方法来寻找最佳阈值,它的成立条件是假设直方图最大波峰在靠近最亮的一侧,然后通过三角形求得最大直线距离,根据最大直线距离对应的直方图灰度等级即为分割阈值,图示如下:
对上图的详细解释: 在直方图上从最高峰处bmx到最暗对应直方图bmin(p=0)%构造一条直线,从bmin处开始计算每个对应的直方图b到直线的垂直距离,知道bmax为止,其中最大距离对应的直方图位置即为图像二值化对应的阈值T。
扩展情况: 有时候最大波峰对应位置不在直方图最亮一侧,而在暗的一侧,这样就需要翻转直方图,翻转之后求得值,用255减去即得到为阈值T。扩展情况的直方图表示如下:
In [6]:
img = cv.imread("../pic/yuzhi.png", 0)
# img = cv.imread("../pic/1png_add.png", 0)
show(img)
In [7]:
plt.hist(img.flatten(), np.arange(-0.5, 256, 1), color='g')
plt.show()
In [8]:
# 返回阈值: th
# error: (-215:Assertion failed) src.type() == CV_8UC1 in function 'threshold'
# 将其转换为灰度图
# img1 = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 转换为灰度图像
th, img_bin = cv.threshold(img, 0, 255, cv.THRESH_TRIANGLE)
print(th)
show(np.hstack([img, img_bin]))
208.0
迭代法阈值分割¶
In [9]:
a = np.random.randint(0, 10, (4, 4))
a
Out[9]:
array([[2, 1, 9, 5], [0, 6, 3, 9], [3, 5, 5, 8], [5, 6, 5, 0]])
In [10]:
a[a > 5]
Out[10]:
array([9, 6, 9, 8, 6])
In [11]:
a[a > 5].mean()
Out[11]:
7.6
In [12]:
img = cv.imread("../pic/yuzhi.png", 0)
show(img)
In [13]:
T = img.mean()
# 0是黑色,255是白色
while True:
# 背景
t0 = img[img < T].mean()
# 前景
t1 = img[img >= T].mean()
t = (t0 + t1) / 2
if T == t:
break
T = t
_, img_bin = cv.threshold(img, T, 255, cv.THRESH_BINARY)
print(T)
show(np.hstack([img, img_bin]))
161.1841846696025
大津法(OTSU)阈值¶
大津法(OTSU)是一种确定图像二值化分割阈值的算法,由日本学者大津于1979年提出。从大津法的原理上来讲,该方法又称作最大类间方差法,因为按照大津法求得的阈值进行图像二值化分割后,前景与背景图像的类间方差最大。
大津法(OTSU)是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响,因此在数字图像处理上得到了广泛的应用。它是按图像的灰度特性,将图像分成背景和前景两部分。因方差是灰度分布均匀性的一种度量,背景和前景之间的类间方差越大,说明构成图像的两部分的差别越大,当部分前景错分为背景或部分背景错分为前景都会导致两部分差别变小。因此,使类间方差最大的分割意味着错分概率最小。
- 应用:是求图像全局阈值的最佳方法,应用不言而喻,适用于大部分需要求图像全局阈值的场合。
- 优点:计算简单快速,不受图像亮度和对比度的影响。
- 缺点:对图像噪声敏感;只能针对单一目标分割;当目标和背景大小比例悬殊、类间方差函数可能呈现双峰或者多峰,这个时候效果不好。
In [14]:
img = cv.imread("../pic/yuzhi.png", 0)
th, img_bin = cv.threshold(img, -1, 255, cv.THRESH_OTSU)
print(th)
show(img_bin)
160.0
自适应阈值¶
In [15]:
img = cv.imread('../pic/text.png', 0)
img_bin = cv.adaptiveThreshold(img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 21, 2)
show(img_bin)
In [ ]: