【Opencv入门到项目实战】(二):图像阈值和平滑处理

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(最大值),否则取0
    • cv2.THRESH_BINARY_INV THRESH_BINARY的相反操作
    • cv2.THRESH_TRUNC 大于阈值部分设为阈值,其余不变
    • cv2.THRESH_TOZERO 大于阈值部分不变,否则设为0
    • cv2.THRESH_TOZERO_INV THRESH_TOZERO的相反操作

通常情况下,在我们图像当中,越亮的地方值越大,以第一个为例,在这里越亮的地方,超过阈值部分,我取255,是不是相当于把它放到极亮,相当于就是一个白点。否则的话就取零,因此比较暗的地方,小于阈值时我们就直接给它取零,相当于是一个黑的地方。接下来我们来看看这几种阈值处理的效果

首先导入一张灰度图

python 复制代码
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
scss 复制代码
(238, 218)

可以看到此时的通道数为1

python 复制代码
# 其中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()函数来实现自适应阈值处理,具体语法如下

python 复制代码
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:在计算阈值时的常数,用于对均值或加权和进行调整。

函数的返回值是处理后的二值图像。

python 复制代码
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阈值处理。

python 复制代码
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 方法得到的二值图像。

python 复制代码
ret
复制代码
119.0

可以看到,Otsu's方法会自动计算阈值,这里阈值等于119,并将图像分为两个类别(黑色和白色)。

使用 Otsu's 阈值处理,我们无需手动选择阈值,而是通过计算来确定最佳阈值,从而实现更准确的图像分割。这对于具有不同光照条件、对比度变化或噪声存在的图像尤其有用。

2.平滑处理

当我们处理图像时,有时候需要对图像进行平滑处理,以减少噪声、去除细节或者模糊图像,它的具体计算有点类似卷积的计算,在介绍具体方法之前我们先来看一张图片:

python 复制代码
img = cv2.imread('lenaNoise.png')
cv2.imshow('Noise', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

可以看到这张图片上面有很多椒盐噪声,我们希望能够用平滑方法来处理,在OpenCV提供了多种图形平滑处理方法,下面我们详细介绍一些常用的方法:

2.1均值滤波(Mean Filter)

将每个像素的邻域像素的平均值作为该像素的新值。这种滤波器对于去除轻度噪声非常有效,但可能会导致图像变得模糊。在OpenCV中,我们调用cv2.blur()函数来实现均值滤波。

python 复制代码
blur = cv2.blur(img, (3, 3)) #使用3×3的滤波器
cv2.imshow('blur', blur)
cv2.waitKey(0)
cv2.destroyAllWindows()

可以看见上面的椒盐噪声减弱了一些,没有那么明显,下面我们来看一下它的具体计算逻辑,这里我们选择了3×3的滤波器,因此,每次我们都会看以目标像素为中心的3×3的领域9个值,如下图所示,以204为中心,我们计算包括它在内及其领域共9个值的平均值来做代替。

2.2高斯滤波(Gaussian Filter)

刚刚我们介绍的均值平衡是简单的求算数平均 ,而高斯平衡认为其邻域像素的权重不应该一样,越靠近中心的像素权重应该越重,且权重服从高斯分布,然后使用高斯权重来计算邻域像素的加权平均值 。相比于均值滤波器,高斯滤波器能够更好地保留图像的细节信息。在OpenCV中,可以使用cv2.GaussianBlur()函数来实现高斯滤波。

python 复制代码
# 高斯滤波
# 高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的
gaussian = cv2.GaussianBlur(img, (3,3), 1)  

cv2.imshow('gaussian', gaussian)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.3中值滤波(Median Filter)

中值滤波是一种非线性滤波器,它将每个像素的邻域像素的中值作为该像素的新值。这种滤波器对于去除椒盐噪声非常有效,同时能够保留图像边缘的细节,对于我们给出的这张图而言,效果非常好。在OpenCV中,我们调用cv2.medianBlur()函数来实现中值滤波。

python 复制代码
# 中值滤波
# 相当于用中值代替
median = cv2.medianBlur(img, 3)  # 中值滤波

cv2.imshow('median', median)
cv2.waitKey(0)
cv2.destroyAllWindows()

可以看出使用中值平滑处理后的效果针对于椒盐噪声非常好。下面我们将三个图放一起来比较

python 复制代码
# 展示所有的
res = np.hstack((blur,gaussian,median))#按水平方向堆砌,三张图水平方向放一起

cv2.imshow('blur vs gaussian vs median', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

上述几种方法究竟选哪一个好呢?一般我们需要根据特定的任务和图像特征进行评估和调整,根据我们的需求和图像特点,选择合适的方法来实现图像的平滑处理,例如以本案例来说,使用中值平滑处理的效果是最好的。

相关推荐
Elastic 中国社区官方博客12 分钟前
Elasticsearch:使用机器学习生成筛选器和分类标签
大数据·人工智能·elasticsearch·机器学习·搜索引擎·ai·分类
movie__movie16 分钟前
Spring AI MCP 客户端实战:轻松连接高德地图等工具
数据库·人工智能·spring
跳跳糖炒酸奶41 分钟前
第四章、Isaacsim在GUI中构建机器人(3):添加摄像头和传感器
人工智能·python·算法·ubuntu·机器人
求知呀2 小时前
最直观的 Cursor 使用教程
前端·人工智能·llm
飞哥数智坊2 小时前
从“工具人”到“超级个体”:程序员如何在AI协同下实现能力跃迁
人工智能
chenqi2 小时前
WebGPU和WebLLM:在浏览器中解锁端侧大模型的未来
前端·人工智能
罗西的思考3 小时前
[2W字长文] 探秘Transformer系列之(23)--- 长度外推
人工智能·算法
小杨4044 小时前
python入门系列十四(多进程)
人工智能·python·pycharm
阿坡RPA19 小时前
手搓MCP客户端&服务端:从零到实战极速了解MCP是什么?
人工智能·aigc
用户277844910499319 小时前
借助DeepSeek智能生成测试用例:从提示词到Excel表格的全流程实践
人工智能·python