(04)python-opencv图像处理——图像阈值、平滑图像、形态转换、图像梯度

news2024/10/24 1:51:51

目录

前言

一、图像阈值

1.1 简单的阈值法

 1.2 自适应阈值

二、平滑图像

2.1 二维卷积(图像滤波)

2.2 图像模糊

2.2.1均值模糊

2.2.2高斯模糊

2.2.3 中值滤波

2.2.4 双边滤波

三、形态转换

1、腐蚀

2、膨胀

3、开运算

4、闭运算

四、图像梯度

Sobel 和 Scharr 微分

参考文

前言

在本博文中,进行图像阈值、平滑图像、形态转换、图像梯度的学习以及介绍。

一、图像阈值

在本部分中,

  • 你会学到简单阈值法,自适应阈值法,以及 Otsu 阈值法(俗称大津法)等。
  • 你会学到如下函数:cv.thresholdcv.adaptiveThreshold 等。

1.1 简单的阈值法

        此方法是直截了当的。如果像素值大于阈值,则会被赋为一个值(可能为白色),否则会赋为另一个值(可能为黑色)。使用的函数是 cv.threshold。第一个参数是源图像,它应该是灰度图像。第二个参数是阈值,用于对像素值进行分类。第三个参数是 maxval,它表示像素值大于(有时小于)阈值时要给定的值。opencv 提供了不同类型的阈值,由函数的第四个参数决定。不同的类型有:

  • cv.THRESH_BINARY
  • cv.THRESH_BINARY_INV
  • cv.THRESH_TRUNC
  • cv.THRESH_TOZERO
  • cv.THRESH_TOZERO_INV

文档清楚地解释了每种类型的含义。请查看文档。

获得两个输出。第一个是 retval,稍后将解释。第二个输出是我们的阈值图像。

下面是一个使用 OpenCV 的 cv.threshold() 函数进行图像二值化的示例,说明如何应用不同的阈值类型来处理图像。

import cv2
import numpy as np

# 读取图像,并将其转换为灰度图
img = cv2.imread('images/demo2.png', 0)
# 定义阈值和最大值
threshold_value = 127
max_value = 255
# 应用不同类型的阈值操作
_, thresh_binary = cv2.threshold(img, threshold_value, max_value, cv2.THRESH_BINARY)
_, thresh_binary_inv = cv2.threshold(img, threshold_value, max_value, cv2.THRESH_BINARY_INV)
_, thresh_trunc = cv2.threshold(img, threshold_value, max_value, cv2.THRESH_TRUNC)
_, thresh_tozero = cv2.threshold(img, threshold_value, max_value, cv2.THRESH_TOZERO)
_, thresh_tozero_inv = cv2.threshold(img, threshold_value, max_value, cv2.THRESH_TOZERO_INV)
# 显示结果
cv2.imshow('Original Image', img)
cv2.imshow('Binary Threshold', thresh_binary)
cv2.imshow('Binary Inverse Threshold', thresh_binary_inv)
cv2.imshow('Truncate Threshold', thresh_trunc)
cv2.imshow('ToZero Threshold', thresh_tozero)
cv2.imshow('ToZero Inverse Threshold', thresh_tozero_inv)

# 等待按键输入并关闭窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
  • 输入图像:代码读取并将输入图像转换为灰度图像。

  • 阈值参数threshold_value = 127,像素值大于127的地方将根据选择的阈值类型做相应处理,max_value = 255 表示阈值操作后的最大值。

  • 阈值操作

    • cv.THRESH_BINARY:如果像素值大于阈值,则设置为 max_value,否则为 0。

    • cv.THRESH_BINARY_INV:与 THRESH_BINARY 相反,像素值大于阈值时为 0,否则为 max_value

    • cv.THRESH_TRUNC:像素值大于阈值时设置为阈值,其他值保持不变。

    • cv.THRESH_TOZERO:大于阈值的像素值保持不变,小于阈值的像素值设为 0。

    • cv.THRESH_TOZERO_INV:小于阈值的像素值保持不变,大于阈值的像素值设为 0。

 1.2 自适应阈值

        在前一节中,我们使用一个全局变量作为阈值。但在图像在不同区域具有不同照明条件的条件下,这可能不是很好。在这种情况下,我们采用自适应阈值。在此,算法计算图像的一个小区域的阈值。因此,我们得到了同一图像不同区域的不同阈值,对于不同光照下的图像,得到了更好的结果。

它有三个“特殊”输入参数,只有一个输出参数。

Adaptive Method-它决定如何计算阈值。

  • cv.ADAPTIVE_THRESH_MEAN_C 阈值是指邻近地区的平均值。
  • cv.ADAPTIVE_THRESH_GAUSSIAN_C 阈值是权重为高斯窗的邻域值的加权和。

Block Size-它决定了计算阈值的窗口区域的大小。

C-它只是一个常数,会从平均值或加权平均值中减去该值。

下面的代码比较了具有不同照明的图像的全局阈值和自适应阈值:

import cv2
import numpy as np
# 读取图像,并将其转换为灰度图
img = cv2.imread('images/demo2.png', 0)
# 使用全局阈值
_, global_thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# 使用自适应阈值 - 均值方法
adaptive_thresh_mean = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C,
                                             cv2.THRESH_BINARY, 11, 2)
# 使用自适应阈值 - 高斯方法
adaptive_thresh_gaussian = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                                 cv2.THRESH_BINARY, 11, 2)
# 显示结果
cv2.imshow('Original Image', img)
cv2.imshow('Global Thresholding', global_thresh)
cv2.imshow('Adaptive Mean Thresholding', adaptive_thresh_mean)
cv2.imshow('Adaptive Gaussian Thresholding', adaptive_thresh_gaussian)

# 等待按键输入并关闭窗口
cv2.waitKey(0)
cv2.destroyAllWindows()

 

二、平滑图像

2.1 二维卷积(图像滤波)

与一维信号一样,图像也可以通过各种低通滤波器(LPF)、高通滤波器(HPF)等进行过滤。LPF 有助于消除噪音、模糊图像等。HPF 滤波器有助于在图像中找到边缘。

opencv 提供了函数 cv.filter2D(),用于将内核与图像卷积起来。

二维卷积在图像处理中是一种非常基础且重要的操作。通过卷积,我们可以应用不同的滤波器(即内核)对图像进行操作,达到不同的效果。常见的滤波操作包括低通滤波器(LPF)和高通滤波器(HPF)。这些滤波器可以用于去除噪声、模糊图像、增强边缘等。

  • 低通滤波器 (LPF):通常用于平滑图像、去噪声。例如:均值滤波、高斯滤波。

  • 高通滤波器 (HPF):用于增强图像中的边缘、锐化图像。例如:Sobel 滤波、Laplacian 滤波。

OpenCV 提供的 cv.filter2D() 函数可以实现任意的内核卷积操作。

具体操作说明:

  • cv.filter2D() 函数的参数如下:

    • src:输入图像。

    • ddepth:输出图像的深度,通常与输入图像深度相同。

    • kernel:滤波器矩阵,即卷积核(大小一般为奇数,比如 3x3、5x5)。

import cv2
import numpy as np
# 读取图像
img = cv2.imread('images/demo2.png')
# 创建一个高通滤波器(用于锐化图像)
kernel = np.array([[-1, -1, -1],
                   [-1,  9, -1],
                   [-1, -1, -1]])
# 应用二维卷积
sharpened_image = cv2.filter2D(img, -1, kernel)
# 显示原始图像和锐化后的图像
cv2.imshow('Original Image', img)
cv2.imshow('Sharpened Image', sharpened_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.2 图像模糊

        图像模糊是通过将图像与低通滤波核卷积来实现的。它有助于消除噪音。它实际上从图像中删除高频内容(例如:噪声、边缘)。所以在这个操作中边缘有点模糊。(好吧,有一些模糊技术不会使边缘太模糊)。OpenCV 主要提供四种模糊技术。

        在图像处理中,模糊(平滑处理)是为了减少图像中的噪声和细节,通常用于预处理或后处理阶段。OpenCV 提供了多种模糊技术,常用的有均值模糊、高斯模糊、中值滤波和双边滤波。每种模糊方法的原理和效果略有不同,下面分别说明并举例。

2.2.1均值模糊

原理:均值模糊是最简单的一种滤波方式。它通过取图像中某个区域的所有像素值的均值,来平滑该区域。这种模糊方法会导致图像细节损失较多。

import cv2
# 读取图像
img = cv2.imread('images/demo2.png')
# 使用均值模糊,窗口大小为 5x5
mean_blur = cv2.blur(img, (5, 5))
# 显示原图像和均值模糊后的图像
cv2.imshow('Original Image', img)
cv2.imshow('Mean Blur', mean_blur)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

2.2.2高斯模糊


原理:高斯模糊使用高斯分布的权重对图像进行平滑。与均值模糊不同,高斯模糊给邻近像素分配不同的权重,中心像素的权重较高,边缘像素的权重较低。这使得高斯模糊在保留图像细节的同时,有效去除噪声。

import cv2
# 读取图像
img = cv2.imread('input_image.jpg')
# 使用高斯模糊,窗口大小为 5x5,标准差为 0
gaussian_blur = cv2.GaussianBlur(img, (5, 5), 0)
# 显示原图像和高斯模糊后的图像
cv2.imshow('Original Image', img)
cv2.imshow('Gaussian Blur', gaussian_blur)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.2.3 中值滤波

原理:中值滤波是非线性滤波的一种,它将窗口内的所有像素按大小排序,然后用中值替换中心像素。这种方法特别适合处理椒盐噪声,并且在保留边缘的同时有效去噪。

import cv2

# 读取图像
img = cv2.imread('input_image.jpg')

# 使用中值滤波,窗口大小为 5x5
median_blur = cv2.medianBlur(img, 5)

# 显示原图像和中值滤波后的图像
cv2.imshow('Original Image', img)
cv2.imshow('Median Blur', median_blur)

cv2.waitKey(0)
cv2.destroyAllWindows()

2.2.4 双边滤波

原理:双边滤波是一种保边滤波器,它不仅考虑空间距离,还考虑像素值的相似度。双边滤波可以在平滑图像的同时保留边缘信息,因此特别适用于边缘保留的去噪。

import cv2

# 读取图像
img = cv2.imread('input_image.jpg')

# 使用双边滤波,d为滤波器直径,sigmaColor控制颜色邻近值,sigmaSpace控制空间邻近值
bilateral_blur = cv2.bilateralFilter(img, 9, 75, 75)

# 显示原图像和双边滤波后的图像
cv2.imshow('Original Image', img)
cv2.imshow('Bilateral Filter', bilateral_blur)

cv2.waitKey(0)
cv2.destroyAllWindows()

三、形态转换

        形态学变换是基于图像形状的一些简单操作。它通常在二值图像上执行。它需要两个输入,一个是我们的原始图像,第二个是决定操作性质的结构元素或内核。两个基本的形态学操作是腐蚀和膨胀。接下来如开,闭,梯度等也会介绍。在下图的帮助下,我们将逐一看到它们:

1、腐蚀

腐蚀的基本概念就像土壤侵蚀一样,只侵蚀前景对象的边界(总是尽量保持前景为白色)。那它有什么作用呢?内核在图像中滑动(如二维卷积)。只有当内核下的所有像素都为 1 时,原始图像中的像素(1 或 0)才会被视为 1,否则会被侵蚀(变为零)。

所以根据内核的大小,边界附近的所有像素都将被丢弃。因此,前景对象的厚度或大小在图像中减少或只是白色区域减少。它有助于消除小的白色噪音(如我们在“颜色空间”一章中所看到的),分离两个连接的对象等。

作为一个例子,我将使用一个 5x5 内核,内核元素均为1。让我们看看它是如何工作的:

import cv2
import numpy as np

# 读取二值图像
image = cv2.imread('binary_image.jpg', 0)

# 创建5x5的结构元素(内核)
kernel = np.ones((5, 5), np.uint8)

# 执行腐蚀操作
eroded_image = cv2.erode(image, kernel, iterations=1)

# 显示原始图像和腐蚀后的图像
cv2.imshow('Original Image', image)
cv2.imshow('Eroded Image', eroded_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

2、膨胀

它与腐蚀正好相反。这里,如果内核下至少有一个像素为“1”,则像素元素为“1”。所以它会增加图像中的白色区域,或者增加前景对象的大小。通常情况下,在去除噪音的情况下,腐蚀后会膨胀。因为,腐蚀消除了白噪声,但它也缩小了我们的对象。所以我们扩大它。由于噪音消失了,它们不会再回来,但我们的目标区域会增加到腐蚀之前的状态。它还可用于连接对象的断开部分。

# 执行膨胀操作
dilated_image = cv2.dilate(image, kernel, iterations=1)

# 显示膨胀后的图像
cv2.imshow('Dilated Image', dilated_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

3、开运算

开只是腐蚀的另一个名称,随后是膨胀。正如我们上面所解释的,它对消除噪音很有用。在这里,我们使用 cv.morphologyEx()

# 执行开运算
opened_image = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)

# 显示开运算后的图像
cv2.imshow('Opened Image', opened_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

4、闭运算

关闭与打开相反,膨胀后腐蚀。它在填充前景对象内的小孔或对象上的小黑点时很有用。

# 执行闭运算
closed_image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel)

# 显示闭运算后的图像
cv2.imshow('Closed Image', closed_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

四、图像梯度

OpenCv 提供三种类型的梯度滤波器或高通滤波器,Sobel、Scharr 和 Laplacian。我们会逐步介绍。

Sobel 和 Scharr 微分

原理

  • Sobel 算子是一种边缘检测算子,它结合了高斯平滑与微分运算,从而提高了对噪声的抵抗力。Sobel 算子通过两个方向(水平和垂直)来计算图像的梯度。

  • Scharr 算子是 Sobel 算子的一个变种,具有更好的旋转不变性和更高的梯度响应。Scharr 算子在某些情况下能够提供更精确的边缘检测,尤其是细节较多的图像。

Sobel 和 Scharr 内核

  • Sobel 内核(3x3):

  • Scharr 内核(3x3):

import cv2
import numpy as np

# 读取图像并转换为灰度图
image = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)

# Sobel 微分
sobel_x = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3)  # X方向
sobel_y = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3)  # Y方向
sobel_magnitude = cv2.magnitude(sobel_x, sobel_y)  # 计算梯度幅值

# Scharr 微分
scharr_x = cv2.Scharr(image, cv2.CV_64F, 1, 0)  # X方向
scharr_y = cv2.Scharr(image, cv2.CV_64F, 0, 1)  # Y方向
scharr_magnitude = cv2.magnitude(scharr_x, scharr_y)  # 计算梯度幅值

# 显示结果
cv2.imshow('Original Image', image)
cv2.imshow('Sobel Magnitude', sobel_magnitude)
cv2.imshow('Scharr Magnitude', scharr_magnitude)
cv2.waitKey(0)
cv2.destroyAllWindows()

参考文献

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2213041.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Pycharm系列】如何使用Windows的pycharm来远程连接linux做开发?

目录 前言一、原因二、步骤2-1、打开配置2-2、新建SFTP连接2-3、添加SSH连接信息2-4、配置连接信息2-5、构建连接2-6、打开远程项目文件目录2-7、配置项目依赖 总结 前言 使用Linux部署,使用Windows远程开发,可以提升开发效率,以及项目运行的…

使用可白嫖的高配置服务器——DAMODEL进行AI开发教程

DAMODEL:DAMODEL 目前DAmodel注册并实名赠送50大洋的免费额度,搭载4090的服务器费用不到2r/h 教程: 完成注册并实名后 在此点击创建实例 选择实例配置 选择镜像,看你使用哪种dl框架 。 实例自带的磁盘会随实例释放。需要自己…

Python获取盘符并创建文件夹-基于window系统

1、问题概述? 提供代码详解及完整应用代码 在项目开发中,我们有时候需要当前计算机的盘符,并判断那个盘符的空间最大,然后再最大空闲盘符中创建目录。实现如下功能 1、获取所有盘符信息。 2、获取盘符的空间,并判断大小 3、在盘符中创建需要的目录 …

osgEarth 键鼠 增删改 feature Node

为了满足shapefile 编辑,实现键鼠对地理要素的增删改。 读取shapefile,用Geometry Feature FeatureNode绘制在osgEarth上; 自定义osgGA::GUIEventHandler,handle函数中监测osgGA::GUIEventAdapter::PUSH 之前疑惑在拾取&#x…

已解决:“发生生成错误,是否继续并运行上次的成功的生成?”无法启动程序,系统找不到指定的文件

版本:Visual Studio 2022用于C开发 目录 问题描述 问题原因 解决办法 问题描述 代码没有问题,运行后出现如下界面: 点击“是”后,又出现如下问题: 问题原因 源程序文件下出现两个main函数。 像我的文件目录下的另…

Allegro PCB中过孔的整体替换

Cadence Allegro PCB中过孔的整体替换 在PCB设计过程中,之前是使用的小的过孔,后面需要替换成大的过孔,一个一个去替换过孔非常麻烦的,这里,讲解一下如何去整体的替换过孔,具体的操作方法如下所示&#xf…

微软推出最新 Azure 虚拟机 ND H200 v5 系列

声明:本文翻译自微软全球官方博客,ND H200 v5 系列虚拟机目前只在 Microsoft Azure 海外版上发布。 随着人工智能领域的高速发展,企业对于可扩展和高性能基础设施的需求呈指数级增长。客户需要 Azure AI 基础设施来开发智能驱动的创新解决方案…

HUAWEI_HCIA_实验指南_Lib2.1_交换机基础配置

1、原理概述 交换机之间通过以太网电接口对接时需要协商一些接口参数,比如速率、双工模式等。交换机的全双工是指交换机在发送数据的同时也能够接收数据,两者同时进行。就如平时打电话一样,说话的同时也能够听到对方的声音。而半双工指在同一…

Linux高性能服务器编程

文章目录 Linux高性能服务器编程一、TCP/IP协议族1.TCP/IP体系结构图2.ARP协议2.1 ARP协议工作原理2.2 以太网ARP请求/应答报文格式2.3 ARP高速缓存的查看与修改 3. DNS协议3.1 DNS 查询和应答报文 二、IP协议详解1.路由表更新 三、TCP1.特点2.字节流3.TCP头部结构4.三次握手与…

双卡双待功能

双卡功能,指的是设备上安装和使用了两张SIM卡的功能,这两张SIM卡可以来自同一运营商,也可以来自不同的运营商。设备可以选择使用其中一张SIM卡,或者两张同时使用。当然,能否两张SIM卡同时使用,还取决于设备…

Python 语言学习——做题记录 2.3

这次主要练习集合这一数据类型。 P1. 洛谷B3633集合运算2 import sys n1input() a1sys.stdin.readline() a2a1.split() A{int(i) for i in a2} #print(A) n2input() b1sys.stdin.readline() b2b1.split() B{int(i) for i in b2} #print(B)print(len(A)) CA&B DA|B Uset(ra…

全球化智能组网基于多技术混合组网,适用于各行业的全球办公组网

在全球化的今天,企业的业务网络不仅需要覆盖更广泛的地理区域,同时也要能够灵活应对各种复杂的业务场景。为此,中国联通国际公司推出了全球化智能组网服务,该服务以中国联通云联网为核心,结合SD-WAN、多云连接&#xf…

echarts图例右侧竖向排列修改图例文字颜色

实操链接戳这里哈 left代表图例在水平放置的位置,有left、center、right top代表图例在垂直方向的位置,有top、middle、bottom width是最主要的,当设置的宽度比较小时,才会迫使图例换行,从而形成竖直排列的现像。 lege…

SpringBoot2核心功能-数据访问

目录 一、数据源的自动配置-HikariDataSource1、导入JDBC场景2、分析自动配置3、修改配置项4、测试 二、使用Druid数据源2.1、druid官方github地址2.2、自定义方式2.2.1、创建数据源2.2.2、StatViewServlet2.2.3、StatFilter 2.3、使用官方starter方式2.3.1、引入druid-starter…

DS线性表之队列的讲解和实现(5)

文章目录 前言一、队列的概念及结构二、队列的实现队列节点和队列初始化销毁判断是否为空入队列出队列获取队头队尾数据获取队列元素个数 三、实际使用效果总结 前言 队列实现源代码   队列是我们遇到的第二个实用数据结构,栈和队列地位等同 一、队列的概念及结构…

SAP学习笔记 - 豆知识13 - Msg 番号 NR751 - Object RF_BELEG R100、番号範囲間隔 49 不存在 FBN1

其实这种就是自动採番的番号没弄。 比如跨年了,那该新年度的番号范围没弄啊,就会出这种错误。 把番号范围给加一下就可以了。 1,现象 比如点 VL02N 出荷传票变更 画面,点 出库确认 就会出如下错误: Object RF_BEL…

双十一有哪些必买的好物清单?分享2024年双十一好用的好物排行榜

随着数字化生活的日益普及,每年的双十一已不仅仅是简单的购物狂欢,在这个充满期待的日子,无数家庭和个人都希望能以最实惠的价格,淘到那些能给日常生活带来便利与乐趣的好物。今天我们将聚焦于那些兼具实用性和创新性的产品&#…

使用飞桨AI Studio平台训练数据,并进行图像识别分析得牡丹花测试

🎼个人主页:【Y小夜】 😎作者简介:一位双非学校的大二学生,编程爱好者, 专注于基础和实战分享,欢迎私信咨询! 🎆入门专栏:🎇【MySQL&#xff0…

zookeeper客户端

启动单机版的zookeeper 配置Maven环境 (1) IDEA自带maven (2) 更新Maven库镜像地址: ① 拷贝D:\Program Files\JetBrains\IntelliJ IDEA 2018.3.5\plugins\maven\lib\maven3\conf\settings.xml [IntelliJ的安装目录]到 C:/用户/username/.m2 (如果.m2文件不存在&…

JDK17下,使用SHA1算法报Certificates do not conform to algorithm constraints错误

JDK17从17.0.5开始,默认不再允许使用SHA1算法,如果引用的jar包或代码里使用了SHA1算法,会报以下错误。 Caused by: javax.net.ssl.SSLHandshakeException: Certificates do not conform to algorithm constraintsat java.base/sun.security.…