目录
[一、cv2.threshold 函数整体说明](#一、cv2.threshold 函数整体说明)
[1️⃣ cv2.THRESH_BINARY(最常用)](#1️⃣ cv2.THRESH_BINARY(最常用))
[2️⃣ cv2.THRESH_BINARY_INV(反二值化)](#2️⃣ cv2.THRESH_BINARY_INV(反二值化))
[3️⃣ cv2.THRESH_TRUNC(截断阈值)](#3️⃣ cv2.THRESH_TRUNC(截断阈值))
[4️⃣ cv2.THRESH_TOZERO(阈值以下清零)](#4️⃣ cv2.THRESH_TOZERO(阈值以下清零))
[5️⃣ cv2.THRESH_TOZERO_INV(TOZERO 的反向)](#5️⃣ cv2.THRESH_TOZERO_INV(TOZERO 的反向))
[1 .均值滤波原理](#1 .均值滤波原理)
[2. 示例代码](#2. 示例代码)
[1 .方框滤波原理](#1 .方框滤波原理)
[2 .归一化与否的区别](#2 .归一化与否的区别)
[OpenCV 实现示例](#OpenCV 实现示例)
[OpenCV 实现示例](#OpenCV 实现示例)
[1️⃣ 结构元素(Structuring Element)](#1️⃣ 结构元素(Structuring Element))
[2️⃣ 二值腐蚀的规则](#2️⃣ 二值腐蚀的规则)
[OpenCV 中的腐蚀实现](#OpenCV 中的腐蚀实现)
[cv2.dilate() 函数重点讲解(参数与腐蚀相同)](#cv2.dilate() 函数重点讲解(参数与腐蚀相同))
[1️⃣ src:输入图像](#1️⃣ src:输入图像)
[2️⃣ kernel:结构元素(决定"怎么膨胀")](#2️⃣ kernel:结构元素(决定“怎么膨胀”))
[3️⃣ iterations:膨胀次数(决定"膨胀几轮")](#3️⃣ iterations:膨胀次数(决定“膨胀几轮”))
[(1)src ------ 输入图像](#(1)src —— 输入图像)
[(2)op ------ 形态学操作类型](#(2)op —— 形态学操作类型)
[(3)kernel ------ 结构元素](#(3)kernel —— 结构元素)
[(4)iterations ------ 重复次数(默认 1)](#(4)iterations —— 重复次数(默认 1))
[1️⃣ 定义(核心公式)](#1️⃣ 定义(核心公式))
[OpenCV 示例代码](#OpenCV 示例代码)
[1️⃣ 定义(核心公式)](#1️⃣ 定义(核心公式))
[OpenCV 示例代码(常用写法)](#OpenCV 示例代码(常用写法))
[op 参数可选值说明](#op 参数可选值说明)
图像阈值
阈值的作用是:根据像素强度大小,将图像中的信息进行"区分、简化和分离"。
更直白一点:
把"有用的"和"没那么重要的"像素分开。
一、cv2.threshold 函数整体说明
参数含义(博客标准表述)
-
src :输入图像
只能是单通道图像,通常为灰度图
-
dst :输出图像
经过阈值处理后的结果
-
thresh :阈值
用于判断像素"是否满足条件"的分界值
-
maxval :最大值
当像素满足条件时,被赋予的值(常用 255)
-
type :阈值处理类型
决定"满足阈值"和"不满足阈值"时像素如何变化
-
ret :实际使用的阈值
普通阈值时
ret == thresh(在自适应 / OTSU 时才有特殊意义)
二、五种阈值类型
1️⃣ cv2.THRESH_BINARY(最常用)
规则:
bash
像素值 > thresh → maxval
像素值 ≤ thresh → 0
一句话理解:
超过阈值的变成白色,其余变成黑色
2️⃣ cv2.THRESH_BINARY_INV(反二值化)
规则:
bash
像素值 > thresh → 0
像素值 ≤ thresh → maxval
一句话理解:
和 BINARY 完全相反,黑白对调
3️⃣ cv2.THRESH_TRUNC(截断阈值)
规则:
bash
像素值 > thresh → thresh
像素值 ≤ thresh → 原值不变
一句话理解:
把亮的"压下来",暗的保持不变
4️⃣ cv2.THRESH_TOZERO(阈值以下清零)
规则:
bash
像素值 > thresh → 原值不变
像素值 ≤ thresh → 0
一句话理解:
阈值以下的像素被变成黑色(0)
5️⃣ cv2.THRESH_TOZERO_INV(TOZERO 的反向)
规则:
bash
像素值 > thresh → 0
像素值 ≤ thresh → 原值不变
📌 特点 :
和 TOZERO 完全相反,用得相对少
示例最常见的二值化处理(THRESH_BINARY)
python
import cv2
# 读取图像并转换为灰度图
img = cv2.imread('test.png', cv2.IMREAD_GRAYSCALE)
# 固定阈值二值化
ret, binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Binary', binary)
cv2.waitKey(0)
cv2.destroyAllWindows()
阈值处理要求输入图像为单通道,因此通常先读取或转换为灰度图。
python
ret, binary = cv2.threshold(...)
-
ret:ret表示函数实际采用的阈值 -
binary:阈值处理后的图像结果,就是输出图像dst
图像模糊(平滑处理)
平滑滤波主要用于降低图像中的随机噪声。其基本思想是利用邻域像素的信息,对当前像素进行重新计算,从而减弱局部的剧烈变化。
一、均值滤波
1 .均值滤波原理
均值滤波是一种典型的线性平滑滤波方法,其核心思想是:
用邻域像素的平均值替换当前像素的值。
以 3×3 窗口为例,滤波器以当前像素为中心,选取周围 9 个像素,计算它们的平均值,并将该平均值作为中心像素的新值。
2. 示例代码
python
import cv2
img = cv2.imread('lenaNoise.png')
blur = cv2.blur(img, (3, 3))
cv2.imshow('blur', blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
二、方框滤波
1 .方框滤波原理
方框滤波与均值滤波本质相同,都是在固定大小的邻域内对像素进行处理。其不同之处在于是否对计算结果进行归一化。
python
box = cv2.boxFilter(img, -1, (3, 3), normalize=True)
2 .归一化与否的区别
-
normalize=True对邻域内像素求和后再除以像素个数,结果为平均值,效果等价于均值滤波。
-
normalize=False仅对邻域像素进行求和,不进行平均。此时中心像素的新值等于邻域像素值的累加结果。
从数学角度看:
-
均值滤波 = 求和 + 归一化
-
非归一化方框滤波 = 直接求和
三、高斯滤波与中值滤波
高斯滤波的基本思想
高斯滤波是一种加权平均滤波 。与均值滤波中"所有像素权重相同"不同,高斯滤波遵循高斯分布规律:
距离中心像素越近,权重越大;距离越远,权重越小。
因此,中心像素对最终结果的影响最大,边缘像素影响较小。
高斯滤波的原理说明
在高斯滤波中,邻域内像素值会与一个高斯权重矩阵相乘,再进行加权求和,最终得到中心像素的新值。其数学模型可以表示为:

OpenCV 实现示例
python
import cv2
img = cv2.imread('lenaNoise.png')
gaussian = cv2.GaussianBlur(img, (3, 3), 0)
cv2.imshow('gaussian', gaussian)
cv2.waitKey(0)
cv2.destroyAllWindows()
参数说明
python
cv2.GaussianBlur(src, ksize, sigmaX)
-
src:输入图像 -
ksize:高斯核大小,通常为奇数,如 (3,3)、(5,5),以当前像素为中心,取多大范围的邻域参与加权计算。 -
sigmaX:X 方向的标准差-
为 0 时,由 OpenCV 根据核大小自动计算,根据
ksize自动计算一个合适的sigmaX -
离中心像素越远,权重下降得有多快
-
四、中值滤波
中值滤波的基本思想
中值滤波是一种非线性滤波方法 。
其核心思想是:
用邻域像素的"中位数"替换当前像素值。
中值滤波的原理说明
以 3×3 窗口为例:
-
取当前像素周围的 9 个像素值
-
对这 9 个数进行排序
-
取排序后的中间值
-
用该中位数替换中心像素
📌 与均值不同,中值滤波不会受到极端噪声值的强烈影响。
OpenCV 实现示例
python
import cv2
img = cv2.imread('lenaNoise.png')
median = cv2.medianBlur(img, 3)
cv2.imshow('median', median)
cv2.waitKey(0)
cv2.destroyAllWindows()
参数说明
python
cv2.medianBlur(src, ksize)
-
src:输入图像 -
ksize:滤波窗口大小**(必须是奇数)**
| 滤波方法 | 类型 | 特点 | 适用场景 |
|---|---|---|---|
| 均值滤波 | 线性 | 简单平均,易模糊边缘 | 噪声较弱 |
| 高斯滤波 | 线性 | 加权平均,平滑自然 | 高斯噪声 |
| 中值滤波 | 非线性 | 抗极端值,保边缘 | 椒盐噪声 |
形态变换
腐蚀
形态学腐蚀(Erosion)是数学形态学中的一种基本操作,主要用于缩小前景区域 、消除小的白色噪点 以及分离相互连接的目标 。腐蚀操作通常应用于二值图像,也可用于灰度图像。
可以把腐蚀理解为:
用一个结构元素在图像上"扫描",
只要结构元素覆盖范围内存在不满足条件的像素,
当前像素就会被"削弱"。
在二值图像中,腐蚀的效果表现为:
-
白色前景区域 变小
-
黑色背景区域 变大
-
细小的白色噪声被去除

腐蚀的数学原理
1️⃣ 结构元素(Structuring Element)
腐蚀操作需要一个结构元素(kernel),常见形状有:
-
矩形
-
十字形
-
椭圆形
例如一个 3×3 的结构元素:
bash
1 1 1
1 1 1
1 1 1
2️⃣ 二值腐蚀的规则
对于二值图像:
只有当结构元素覆盖的区域内,所有像素都为前景(白色)时,中心像素才保持为白色;否则变为黑色。
换句话说:只要邻域中有一个黑点 → 中心像素变黑
以 3×3 结构元素为例,对当前中心像素:
-
将结构元素中心对准当前像素
-
检查结构元素覆盖的邻域
-
若邻域内存在黑色像素
→ 当前像素设为黑色
-
若邻域内全部为白色
→ 当前像素保持白色
灰度腐蚀的规则
在灰度图像中,腐蚀的定义为:
取结构元素覆盖区域内的最小灰度值,作为中心像素的新值。
📌 这可以理解为:
-
"亮区域被削弱"
-
"暗区域被扩散"
OpenCV 中的腐蚀实现
python
cv2.erode(src, kernel, iterations=1)
参数说明:
-
src:输入图像(通常为二值图像) -
kernel:结构元素,决定了算法在进行腐蚀或膨胀时,当前像素周围哪些像素会参与判断 -
iterations:腐蚀次数
示例代码
python
import cv2
import numpy as np
img = cv2.imread('binary.png', 0)
kernel = np.ones((3, 3), np.uint8)
eroded = cv2.erode(img, kernel, iterations=1)
cv2.imshow('eroded', eroded)
cv2.waitKey(0)
cv2.destroyAllWindows()
iterations 的作用
-
iterations = 1→ 腐蚀一次,边缘缩小一圈
-
iterations > 1→ 多次腐蚀,前景区域进一步缩小
膨胀(腐蚀的逆操作)
膨胀 = 让白色前景"变大",让目标向外扩张。
只要结构元素覆盖范围内"有白色",
中心像素就会变成白色。
-
腐蚀:白的变小
-
膨胀:白的变大
| 操作 | 判断规则 |
|---|---|
| 腐蚀 | 只要有黑 → 变黑 |
| 膨胀 | 只要有白 → 变白 |
cv2.dilate() 函数重点讲解(参数与腐蚀相同)
python
dst = cv2.dilate(src, kernel, iterations=1)
1️⃣ src:输入图像
-
通常是 二值图像(0/255),也可以是灰度图或彩色图。
-
形态学最常见流程是:
灰度 → 二值化 → 膨胀/腐蚀
📌 初学建议:先用二值图理解效果最直观。
2️⃣ kernel:结构元素(决定"怎么膨胀")
kernel 是一个小矩阵,用来规定:
-
膨胀时"看多大范围"
-
朝哪些方向扩张
-
扩张的形状
python
kernel = np.ones((3,3), np.uint8)
含义:
-
使用 3×3 矩形结构元素
-
以中心为主,向四周扩一圈(效果比较均匀)
常见结构元素写法:
python
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3)) # 矩形
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3,3)) # 十字
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3)) # 椭圆
3️⃣ iterations:膨胀次数(决定"膨胀几轮")
python
dilate = cv2.dilate(src, kernel, iterations=3)
含义:
-
膨胀执行 3 次
-
每一次都是在上一次结果基础上继续膨胀
📌 规律很简单:
iterations越大,白色区域越大,连接效果越明显,但细节越容易糊掉。
开运算与闭运算
核心函数:cv2.morphologyEx
python
dst = cv2.morphologyEx(src, op, kernel, iterations=1)
参数逐个解释
(1)src ------ 输入图像
python
img = cv2.imread('dige.png')
-
一般是 二值图像
-
形态学操作对二值图最直观
(2)op ------ 形态学操作类型
这是开运算 / 闭运算的核心区别:
| 运算 | 顺序 | 主要作用 |
|---|---|---|
| 开运算 | 腐蚀 → 膨胀 | 去白噪点 |
| 闭运算 | 膨胀 → 腐蚀 | 填黑洞、连断裂 |
(3)kernel ------ 结构元素
python
kernel = np.ones((5,5), np.uint8)
-
决定:
-
看多大范围
-
形态变化"有多狠"
-
-
5×5 比 3×3 效果更明显
(4)iterations ------ 重复次数(默认 1)
- 每多一次,相当于再做一轮形态学操作
cv2.morphologyEx() 是 OpenCV 中用于执行高级形态学操作的函数。通过设置不同的操作类型参数,可以实现开运算和闭运算。其中,**开运算由腐蚀和膨胀组成,常用于去除小的白色噪点;闭运算由膨胀和腐蚀组成,常用于填补目标内部的小黑洞或连接断裂区域。**结构元素的大小和形状会直接影响形态学处理的效果。
形态学梯度运算
一、梯度运算是什么?一句话
形态学梯度 = 膨胀结果 − 腐蚀结果
得到的主要是目标的边缘轮廓(边界区域会被突出)。
二、它为什么能提取边缘?(直观解释)
-
膨胀:白色区域向外扩张(边界往外推)
-
腐蚀:白色区域向内收缩(边界往里缩)
把"外扩后的图"减去"内缩后的图":
只剩下"外边界到内边界之间的一圈差值"
这圈差值就是边缘带
所以梯度结果看起来像"描边"。
标准示例代码
python
import cv2
import numpy as np
# 1. 读取图像并转为灰度
img = cv2.imread('image.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 2. 二值化(可选,但强烈推荐)
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 3. 构造结构元素(常用 3x3)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
# 4. 形态学梯度运算
gradient = cv2.morphologyEx(binary, cv2.MORPH_GRADIENT, kernel)
# 5. 显示结果
cv2.imshow('Binary', binary)
cv2.imshow('Morphological Gradient', gradient)
cv2.waitKey(0)
cv2.destroyAllWindows()

礼帽(Top-hat)与黑帽(Black-hat)运算
这两个其实都是 基于"开运算 / 闭运算"的差分运算,不是全新的形态学操作。
一、一句话先记住
礼帽:提亮的小白结构
黑帽:提暗的小黑结构
二、礼帽(Top-hat)运算
1️⃣ 定义(核心公式)
Top-hat=原图−开运算
也就是:礼帽 = 原图 − (腐蚀 → 膨胀)
把**"被开运算去掉的那部分"**拿出来。
OpenCV 示例代码
python
import cv2
import numpy as np
# 读取图像,并以灰度模式加载
# 第二个参数为 0,表示直接读取为单通道灰度图
img = cv2.imread('image.png', 0)
# 构造结构元素(Structuring Element)
# cv2.MORPH_RECT 表示矩形结构元素
# (15, 15) 表示结构元素的大小,决定"多大的亮结构会被提取"
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15, 15))
# 礼帽(Top-hat)运算
# Top-hat = 原图 - 开运算
# 用于提取图像中尺寸较小的亮区域或亮细节
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
# 显示礼帽运算结果
cv2.imshow('Top-hat', tophat)
# 等待按键,防止窗口一闪而过
cv2.waitKey(0)
# 关闭所有 OpenCV 创建的窗口
cv2.destroyAllWindows()
该示例通过礼帽运算提取图像中尺寸较小的亮结构,结构元素大小决定了被增强亮区域的尺度范围。
三、黑帽(Black-hat)运算
1️⃣ 定义(核心公式)
Black-hat=闭运算−原图
也就是:黑帽 = (膨胀 → 腐蚀) − 原图 ,把"被闭运算填掉的那部分"拿出来。
所以黑帽最终得到的是:
原图中"尺寸较小的暗区域"
OpenCV 示例代码(常用写法)
python
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
cv2.imshow('Black-hat', blackhat)
cv2.waitKey(0)
cv2.destroyAllWindows()
函数:cv2.morphologyEx
在数学形态学中,礼帽运算和黑帽运算是基于开运算和闭运算的差分操作,而形态学梯度则是由膨胀和腐蚀的差值构成,并不依赖开运算或闭运算。OpenCV 将上述运算统一封装在 cv2.morphologyEx() 函数中,通过不同的 op 参数进行区分。
python
cv2.morphologyEx(src, op, kernel)
其中:
-
src:输入图像(通常为二值图像或灰度图像) -
op:形态学操作类型 -
kernel:结构元素,用于定义邻域范围和形状
op 参数可选值说明
op 用于指定具体的形态学运算类型,常见取值如下:
-
cv2.MORPH_OPEN,开运算,腐蚀 → 膨胀 -
cv2.MORPH_CLOSE**,**闭运算,膨胀 → 腐蚀 -
cv2.MORPH_GRADIENT,**形态学梯度,**膨胀−腐蚀,提取边界 -
cv2.MORPH_TOPHAT,礼帽**=原图−开运算** -
cv2.MORPH_BLACKHAT**,黑帽=**闭运算−原图
| 运算类型 | 主要作用 |
|---|---|
| 开运算(OPEN) | 去除小的白色噪点 |
| 闭运算(CLOSE) | 填补小的黑洞、连接断裂区域 |
| 形态学梯度(GRADIENT) | 提取目标边界 |
| 礼帽(TOPHAT) | 提取图像中较小的亮结构 |
| 黑帽(BLACKHAT) | 提取图像中较小的暗结构 |
cv2.morphologyEx()通过不同的op参数实现多种形态学组合运算,使得复杂的形态学操作可以通过统一接口完成,既保证了运算顺序的正确性,也提高了代码的简洁性与可读性。
