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

目录

前言

一、图像阈值

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()

参考文献

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Ubuntu】“Linux版PhotoShop”绘图软件的安装和汉化

【Ubuntu】“Linux版PhotoShop”绘图软件的安装和汉化 零、前言 最近换了Linux系统,但是写教程做PPT的时候还是得用到绘图软件,上网一查,总结对比之后发现Krita比较好用,故此讲解一下如何安装和汉化Krita。 壹、安装 安装很简…

探索 Python 装饰器的新境界:wrapt 库的神秘力量

文章目录 探索 Python 装饰器的新境界:wrapt 库的神秘力量背景:为何选择 wrapt?wrapt 是什么?如何安装 wrapt?简单的 wrapt 库函数使用方法创建简单装饰器保持元信息处理参数传递 场景应用:wrapt 的实际用例…

php 生成随机数

记录:随机数抽奖 要求:每次生成3个 1 - 10 之间可重复(或不可重复)的随机数,10次为一轮,每轮要求数字5出现6次、数字4出现3次、…。 提炼需求: 1,可设置最小数、最大数、每次抽奖生…

CentOS7.9 下安装 Docker

第一步: sudo yum install -y yum-utils \ > device-mapper-persistent-data \ > lvm2 第二步:安装 sudo wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sudo yum -y install…

C语言刷题 LeetCode 删除单链表的重复节点 双指针法

题目要求 链表结构:题目中提到的是未排序的链表,链表是由一系列节点组成的,每个节点包含一个值(数据)和一个指向下一个节点的指针。去重:我们需要遍历链表,删除所有重复的节点,只保…

组合式API有什么好处

什么是组合式API? 组合式 API (Composition API) 是一系列 API (响应式API、生命周期钩子、依赖注入)的集合。它不是函数式编程,组合式 API 是以 Vue 中数据可变的、细粒度的响应性系统为基础的,而函数式编程通常强调…

一个项目用5款数据库?MySQL、PostgreSQL、ClickHouse、MongoDB区别,适用场景

文章目录 一、常用数据库概览1.1 关系型数据库1.2 非关系型数据库1.2.1 KV数据库1.2.2 文档型数据库1.2.3 列式存储数据库1.2.4 图数据库 1.3 SQL与NoSQL区别1.3.1 结构化与非结构化1.3.2 关联和非关联1.3.3 查询方式1.3.4 事务1.3.5 总结 二、MySQL三、PostgreSQL3.1 特点、适…

ARM base instruction -- smull

有符号乘法运算 Signed Multiply Long multiplies two 32-bit register values, and writes the result to the 64-bit destination register. 将两个32位寄存器值相乘&#xff0c;并将结果写入64位目标寄存器。 64-bit variant SMULL <Xd>, <Wn>, <Wm>…

二叉树LeetCode刷题

二叉树LeetCode刷题 1. 检查两颗树是否相同2. 另一颗树的子树3. 翻转二叉树4. 判断一颗二叉树是否是平衡二叉树5. 二叉搜索树与双向链表6. 对称二叉树7. 二叉树的构建及遍历8. 二叉树的分层遍历9. 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先10. 根据一棵树的前序遍…

单片机IO电流倒灌

最近在某视频上看到了一个博主因为IO口电流倒灌导致ADC参考基准电压不准&#xff0c;致使ADC采样数据不准。抱着什么是IO电流倒灌的疑问&#xff0c;学习了一些文章&#xff0c;防止以后踩坑。并在下面做一下对IO口电流倒灌的总结。 目录 # 一、什么是IO电流倒灌 # 二、电流倒…

PHP商会招商项目系统一站式服务助力企业腾飞

商会招商项目系统——一站式服务&#xff0c;助力企业腾飞 &#x1f680;&#x1f4bc; &#x1f680; 开篇&#xff1a;企业成长的加速器&#xff0c;商会招商项目系统来袭 在竞争激烈的市场环境中&#xff0c;企业如何快速找到适合自己的发展路径&#xff0c;实现腾飞&…

电脑知识:适用于 Windows 10 的 PDF 编辑器列表

PDF 是一种流行的、多功能且安全的文件格式&#xff0c;用于在线共享文档。但是&#xff0c;如果没有合适的应用程序&#xff0c;查看和编辑 PDF 文件可能会变得复杂。 幸运的是&#xff0c;有很多 PDF 编辑器可以帮助您更正重要文档上的错误、填写表格、为合同添加签名、更改…

电脑基础知识:mfc110.dll丢失的解决方法

1.mfc110.dll 丢失常见原因 mfc110.dll 文件的丢失或损坏是Windows系统中常见的问题&#xff0c;它可能由多种原因引起&#xff0c;以下是一些主要的因素&#xff1a; 不完全的软件卸载 在卸载程序时&#xff0c;如果相关的 DLL 文件没有被正确移除&#xff0c;可能会导致文件…

linux 环境运行 jenkins.war包,有可能会出现字体问题,jdk版本:11 jenkins 版本:2.420

jenkins的目录&#xff1a; /usr/jenkins 启动命令 java -Djava.awt.headlesstrue sudo timedatectl set-timezone Asia/Shanghai-Xmx1024m -jar jenkins.war --httpPort8090 任意目录启动&#xff1a; nohup java -Djava.awt.headlesstrue -Xms1024m -Xmx1024m -jar /usr/j…

【C++笔试强训】如何成为算法糕手Day7

学习编程就得循环渐进&#xff0c;扎实基础&#xff0c;勿在浮沙筑高台 循环渐进Forward-CSDN博客 目录 循环渐进Forward-CSDN博客 字符串中找出连续最长的数字串 思路&#xff1a; 岛屿数量 思路&#xff1a; 深度优先遍历DFS 广度优先遍历 BFS 并查集 拼三角 思路…

学成在线——关于nacos配置优先级的坑

出错&#xff1a; 本地要起两个微服务&#xff0c;一个是content-api&#xff0c;另一个是gateway网关服务。 发现通过网关服务请求content微服务时&#xff0c;怎么请求都请求不到。 配置如下&#xff1a; content-api-dev.yaml的配置&#xff1a; server:servlet:context-p…

【华为】配置BGP协议

边界网关协议BGP是一种实现自治系统AS之间的路由可达&#xff0c;并选择最佳路由的距离矢量路由协议。BGP在不同自治系统之间进行路由转发&#xff0c;分为EBGP&#xff08;外部边界网关协议&#xff09;和IBGP&#xff08;内部边界网关协议&#xff09;两种情况。 [A]in g0/0/…

HTML(七)表格

在HTML中&#xff0c;表格的标准形式如下&#xff1a; <table></table> 使用上面的语言&#xff0c;就已经生成了一个表格&#xff0c;只不过这个表格什么都没有 那么&#xff0c;该如何让表格存在东西呢&#xff1f; 首先&#xff0c;我们需要使用到<tr> …

C++ 匿名对象(没有名字的对象,类似于临时对象)

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 所属栏目&#xff1a;C知识点的补充_Jason_from_China的博客-CSDN博客 概念概述 用类型(实参)定义出来的对象叫做匿名对象&#xff0c;相比之前我们定义的类型…

【Windows】【DevOps】Windows Server 2022 安装ansible,基于powershell实现远程自动化运维部署 入门到放弃!

目标服务器安装openssh server参考 【Windows】【DevOps】Windows Server 2022 在线/离线 安装openssh实现ssh远程登陆powershell、scp文件拷贝-CSDN博客 注意&#xff1a;Ansible不支持Windows操作系统部署 根据官方说明&#xff1a; Windows Frequently Asked Questions —…