数字图像处理_06_(阈值分割——直方图阈值、三角法阈值,迭代法阈值,大津法阈值和自适应阈值)
本章将学习阈值分割,即找到一个合适的阈值实现数字图像的二值化。阈值分割有很多种方法,本章学习直方图阈值、三角法阈值,迭代法阈值,大律法阈值,和自适应阈值。1.直方图阈值图像直方图阈值分割法:算法描述:根据图像的灰度直方图寻找阈值。算法特点:适应于于直方图为双峰的图像。绘制直方图代码:plt.hist(img.ravel(),256,[0,256])或者plt.hist(img.flatten(),
本章将学习阈值分割,即找到一个合适的阈值实现数字图像的二值化。阈值分割有很多种方法,本章学习直方图阈值、三角法阈值,迭代法阈值,大律法阈值,和自适应阈值。
1.直方图阈值
图像直方图阈值分割法:
算法描述:根据图像的灰度直方图寻找阈值。
算法特点:适应于于直方图为双峰的图像。
绘制直方图代码:
plt.hist(img.ravel(),256,[0,256])
或者
plt.hist(img.flatten(),np.arange(-0.5,256,1),color='g')
绘制二值图:
_,img_bin = cv.threshold(img,125,255,cv.THRESH_BINARY)
cv.threshold(img,125,255,cv.THRESH_BINARY)
参数说明:
img:原始图像,
阈值:125
最大值:255
二值化方式:cv.THRESH_BINARY
cv.THRESH_BINARY_INV(反转)
输出图像:
2.三角阈值
算法描述:三角几何化的过程。首先找到直方图中灰度值最高的一点并判别亮暗,然后找到最左边点,两点连接一条直线,求直方图上离直线最远的点,设置该点的灰度值为阈值。
算法特点:适用于单峰。
代码:
_,img_bin = cv.threshold(img,125,255,cv.THRESH_TRIANGLE)
3.迭代法阈值
算法步骤:
- step1:选取初试分割阈值,一般初始为图像灰度值的平均值T
- step2:根据阈值T将图像分割为前景和背景(大于阈值为前景,小于为背景),分别求出两者的平均值 T 0 T_0 T0和 T 1 T_1 T1
- step3:计算新阈值 T ′ = ( T 0 + T 1 ) / 2 T^{'}=(T_0+T_1)/2 T′=(T0+T1)/2
- step4:若 T = = T ′ T==T^{'} T==T′,则 T T T为最终阈值,否则另 T = T ′ T=T^{'} T=T′,执行step2.
实现代码:
T=img.mean()
def ThresholdIteration(T,img):
while True:
T0=img[img>T].mean()
T1=img[img<=T].mean()
t=(T0+T1)/2
if T==t:
return T
else:
T=t
T=int(ThresholdIteration(T,img))
th,img_bin = cv.threshold(img,T,255,cv.THRESH_BINARY)
print(f'Thrshold is {th}')
show(np.hstack([img,img_bin]))
输出为:
4.大津法阈值(OTSU)
算法描述:
对于给定阈值
T
T
T,将图像分为前景和背景。其中背景点数占图像比例为
p
0
p_0
p0,平均灰度值为
m
0
m_0
m0,而目标点数占图像比例为
p
1
p_1
p1,平均灰度值为
m
1
m_1
m1。
整幅图的灰度平均值为:
m
m
m,有:
m
=
p
0
m
0
+
p
1
m
1
m=p_0m_0+p_1m_1
m=p0m0+p1m1
方差为:
σ
2
=
p
0
(
m
0
−
m
)
2
+
p
1
(
m
1
−
m
)
2
\sigma^{2}=p_0(m_0-m)^{2}+p_1(m_1-m)^{2}
σ2=p0(m0−m)2+p1(m1−m)2
带入
p
0
p_0
p0,
p
1
p_1
p1,
m
m
m化简得:
σ
2
=
p
0
p
1
(
m
0
−
m
1
)
2
\sigma^{2}=p_0p_1(m_0-m_1)^{2}
σ2=p0p1(m0−m1)2
则遍历灰度值,使得
σ
2
\sigma^{2}
σ2最大的值为阈值。
代码实现:
def OTSU(img):
n = img.size #图像点数
Sigma = -1 #初始化sigma
for m in range(0,256): #遍历灰度值
fg = img[img>m] #前景
bg = img[img<=m] #背景
p1 = bg.size/n
p0 = fg.size/n
if bg.size==0:
m1=0
else:
m1=bg.mean()
if fg.size==0:
m0=0
else:
m0=fg.mean()
sigma=p1 * p0 * (m0 - m1)**2
#print(sigma)
if sigma>Sigma:
Sigma=sigma
th = m
return th
T=OTSU(img)
th,img_bin = cv.threshold(img,T,255,cv.THRESH_BINARY)
print(f'Thrshold is {th}')
show(np.hstack([img,img_bin]))
输出结果为:
OpenCV自带有OTSU的阈值函数:
在二值化方式选择cv.THRESH_OTSU
即可
th,img_bin = cv.threshold(img,-1,255,cv.THRESH_OTSU)
5.自适应阈值
算法思想:局部二值化
- step1:对某个像素值,原来的 S S S,取其周围n*n的区域,求区域均值或者高斯加权值,记为 T T T.
- step2:对8为图像,如果 S > T S>T S>T,则该像素点二值化为255,否则为0
优化的情况下:1.可以加入参数
C
C
C,
C
C
C可以为任何数,当
S
>
T
−
C
S>T-C
S>T−C,则把原像素值二值化为255. 2.也可以增加一个参数
a
a
a,当
S
>
(
1
−
a
)
T
S>(1-a)T
S>(1−a)T时把原像素点二值化为255,通常取
a
=
0.15
a=0.15
a=0.15
代码为:
img_adapt = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,17,1)
show(img_adapt)
PS:
cv.adaptiveThreshold(原图片,最大值,自适应阈值化方式,二值化方式,卷积核尺寸,参数C)
C=1时:
此例C=8时效果最好:
自己代码实现:
C=0
winSize=21
img_GaussBlur = cv.GaussianBlur(img,(winSize,winSize),1)
img_bin=np.uint8(img>img_GaussBlur-3)*255
show(img_bin)
或者
a=0.15
img_bin=np.uint8(img>(1-a)img_GaussBlur)*255
show(img_bin)
更多推荐
所有评论(0)