文章目录
- 1.图像阈值处理
- 1.1简单阈值处理(Simple Thresholding)
- 1.2自适应阈值处理(Adaptive Thresholding)
- 1.3Otsu's阈值处理
- 2.平滑处理
- 1.1均值滤波(Mean Filter)
- 1.2高斯滤波(Gaussian Filter)
- 1.3中值滤波(Median Filter)
1.图像阈值处理
在图像处理中,阈值处理是一种常用的技术,可以将图像转换为二值图像,即只有两个像素值(一般为黑色和白色)。OpenCV
提供了多种图像阈值处理的方法,接下来我们讨论一下在opencv
如何对一个图形进行阈值处理。
1.1简单阈值处理(Simple Thresholding)
简单阈值处理是一种基本的阈值处理方法,它将图像的每个像素与一个阈值进行比较,并根据比较结果将像素设置为两个值中的一个。在OpenCV
中,调用cv2.threshold()
来实现,主要包含4
个参数: 第一个为输入图,第二个我们设定的阈值,一般为127
,那么我们就以127
为界进行判断,第三个参数是最大的一个可能值,一般情况下为255
。主要就是第四个参数,表示我们要进行的阈值处理及判断条件。这里主要包含5种方法,具体如下
cv2.threshold(input, thresh, maxval, type)
input:
输入图,只能输入单通道图像,通常来说为灰度图thresh
: 阈值maxval
: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值type
:二值化操作的类型,包含以下5种类型:cv2.THRESH_BINARY
超过阈值部分取maxval(最大值),否则取0cv2.THRESH_BINARY_INV
THRESH_BINARY的相反操作cv2.THRESH_TRUNC
大于阈值部分设为阈值,其余不变cv2.THRESH_TOZERO
大于阈值部分不变,否则设为0cv2.THRESH_TOZERO_INV
THRESH_TOZERO的相反操作
通常情况下,在我们图像当中,越亮的地方值越大,以第一个为例,在这里越亮的地方,超过阈值部分,我取255
,是不是相当于把它放到极亮,相当于就是一个白点。否则的话就取零,因此比较暗的地方,小于阈值时我们就直接给它取零,相当于是一个黑的地方。接下来我们来看看这几种阈值处理的效果
首先导入一张灰度图
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
img=cv2.imread('yangqi.jpg') #导入你要读取的图片路径
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #灰度图读取
img_gray.shape
(238, 218)
可以看到此时的通道数为1
# 其中ret返回的是阈值
ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY) #超过127的取值为255,否则为0
ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)#超过127的取值为0,否则为255
ret, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC)#超过阈值的设为阈值,否则不变
ret, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO)#超过127的不变,否则为0
ret, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)#超过127的为0,否则不变
titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
第一幅图:原始的图像就是这只小狗,可以看出身体比较白,其余地方比较暗。
第二幅图:使用BINARY
二值法处理的结果,处理完之后大于127亮点的全为白,暗点的全为黑,这个意思这是咱们第一种方法。
**第三幅图:**使用BINARYINV
处理的结果,这和我们第二幅图的结果完全相反,处理完之后大于127亮点的全为黑,暗点的全为白
**第四幅图:**使用TRUNC
截断值处理的结果,这个比较好理解,所有大于127截断使其等于127了,其余的不变
**第五幅图:**使用TOZERO
,从名字上就可以理解它的用法,大于阈值的部分保持不变,小于阈值的部分变为0
**第六幅图:**使用TOZERO_INV
,和上一种方法的结果刚好相反,大于阈值的变为0,小于阈值的保持不变。
1.2自适应阈值处理(Adaptive Thresholding)
自适应阈值处理是一种根据图像局部区域的特性自动确定阈值的方法。它将图像分成若干个小区域,并根据每个区域内像素的统计信息来计算阈值。在OpenCV
中,可以使用cv2.adaptiveThreshold()
函数来实现自适应阈值处理,具体语法如下
cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)
参数说明:
src
:输入的灰度图像,单通道图像。maxValue
:当像素超过阈值时,所设置的最大像素值。adaptiveMethod
:自适应方法的类型。可以是以下两种之一:cv2.ADAPTIVE_THRESH_MEAN_C
:根据邻域块的均值计算阈值。cv2.ADAPTIVE_THRESH_GAUSSIAN_C
:根据邻域块的加权和的高斯平均值计算阈值。
thresholdType
:阈值处理的类型。可以是以下两种之一:cv2.THRESH_BINARY
:超过阈值的像素被设置为maxValue
,否则设置为0。cv2.THRESH_BINARY_INV
:超过阈值的像素被设置为0,否则设置为maxValue
。
blockSize
:用于计算阈值的像素邻域大小。它必须是奇数,并且大于1。C
:在计算阈值时的常数,用于对均值或加权和进行调整。
函数的返回值是处理后的二值图像。
thresh1 = cv2.adaptiveThreshold(img_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,3,3) #这里领域大小为3
thresh2 = cv2.adaptiveThreshold(img_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY_INV,3,3)#这里领域大小为3
titles = ['Original Image', 'BINARY', 'BINARY_INV']
images = [img_gray, thresh1, thresh2]
for i in range(3):
plt.subplot(1,3, i + 1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
通过自适应阈值处理,我们可以根据每个像素邻域内的统计信息来确定阈值,从而更好地适应不同区域之间的光照变化。这对于处理具有不均匀光照条件的图像非常有用,例如图像中存在阴影或光源不均匀的情况。
1.3Otsu’s阈值处理
Otsu's
阈值处理是一种自动确定阈值的方法,它能够找到一个最佳的阈值,使得将图像分割为两个类别后的类别间方差最小化, 这种方法对于没有先验知识的图像分割非常有用。在OpenCV
中,我们调用cv2.threshold()
函数,并将阈值类型设置为cv2.THRESH_OTSU
来实现Otsu's
阈值处理。
ret, thresh = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
titles = ['Original Image', "Otsu's"]
images = [img_gray, thresh]
for i in range(2):
plt.subplot(1,2, i + 1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
ret
是计算得到的最佳阈值,thresh
是通过应用 Otsu's
方法得到的二值图像。
ret
119.0
可以看到,Otsu's
方法会自动计算阈值,这里阈值等于119,并将图像分为两个类别(黑色和白色)。
使用 Otsu's
阈值处理,我们无需手动选择阈值,而是通过计算来确定最佳阈值,从而实现更准确的图像分割。这对于具有不同光照条件、对比度变化或噪声存在的图像尤其有用。
2.平滑处理
当我们处理图像时,有时候需要对图像进行平滑处理,以减少噪声、去除细节或者模糊图像,它的具体计算有点类似卷积的计算,在介绍具体方法之前我们先来看一张图片:
img = cv2.imread('lenaNoise.png')
cv2.imshow('Noise', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
可以看到这张图片上面有很多椒盐噪声,我们希望能够用平滑方法来处理,在OpenCV
提供了多种图形平滑处理方法,下面我们详细介绍一些常用的方法:
1.1均值滤波(Mean Filter)
将每个像素的邻域像素的平均值作为该像素的新值。这种滤波器对于去除轻度噪声非常有效,但可能会导致图像变得模糊。在OpenCV
中,我们调用cv2.blur()
函数来实现均值滤波。
blur = cv2.blur(img, (3, 3)) #使用3×3的滤波器
cv2.imshow('blur', blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
可以看见上面的椒盐噪声减弱了一些,没有那么明显,下面我们来看一下它的具体计算逻辑,这里我们选择了3×3
的滤波器,因此,每次我们都会看以目标像素为中心的3×3
的领域9个值,如下图所示,以204
为中心,我们计算包括它在内及其领域共9
个值的平均值来做代替。
1.2高斯滤波(Gaussian Filter)
刚刚我们介绍的均值平衡是简单的求算数平均,而高斯平衡认为其邻域像素的权重不应该一样,越靠近中心的像素权重应该越重,且权重服从高斯分布,然后使用高斯权重来计算邻域像素的加权平均值。相比于均值滤波器,高斯滤波器能够更好地保留图像的细节信息。在OpenCV
中,可以使用cv2.GaussianBlur()
函数来实现高斯滤波。
# 高斯滤波
# 高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的
gaussian = cv2.GaussianBlur(img, (3,3), 1)
cv2.imshow('gaussian', gaussian)
cv2.waitKey(0)
cv2.destroyAllWindows()
1.3中值滤波(Median Filter)
中值滤波是一种非线性滤波器,它将每个像素的邻域像素的中值作为该像素的新值。这种滤波器对于去除椒盐噪声非常有效,同时能够保留图像边缘的细节,对于我们给出的这张图而言,效果非常好。在OpenCV
中,我们调用cv2.medianBlur()
函数来实现中值滤波。
# 中值滤波
# 相当于用中值代替
median = cv2.medianBlur(img, 3) # 中值滤波
cv2.imshow('median', median)
cv2.waitKey(0)
cv2.destroyAllWindows()
可以看出使用中值平滑处理后的效果针对于椒盐噪声非常好。下面我们将三个图放一起来比较
# 展示所有的
res = np.hstack((blur,gaussian,median))#按水平方向堆砌,三张图水平方向放一起
cv2.imshow('blur vs gaussian vs median', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
上述几种方法究竟选哪一个好呢?一般我们需要根据特定的任务和图像特征进行评估和调整,根据我们的需求和图像特点,选择合适的方法来实现图像的平滑处理,例如以本案例来说,使用中值平滑处理的效果是最好的。
🔎本章的介绍到此介绍,如果文章对你有帮助,请多多点赞、收藏、评论、订阅支持!!《Opencv入门到项目实战》