图像处理基础与经典算法
一、图像表示基础
1.1 数字图像模型
- 灰度图: I(x,y) ∈ [0, 255], 单通道
- 彩色图: RGB ∈ [0,255]³, 三通道
- 二值图: I(x,y) ∈ {0, 1}
- 多光谱: 高光谱 > 3通道
- 深度图: 每个像素存储距离值
- Indexed Image: 索引+调色板
1.2 颜色空间
| 颜色空间 | 描述 | CV用途 |
|---|---|---|
| RGB | 红绿蓝三原色 | 显示/存储 |
| Lab* | 感知均匀 | 颜色分析 |
| HSV/HSI | 色相/饱和度/明度 | 颜色分割/检测 |
| YCbCr | 亮度+色度 | 视频压缩 |
| Grayscale | 单通道亮度 | 特征提取基础 |
| CMYK | 印刷四色 | 打印 |
转换原因: RGB 对光照/阴影敏感,HSV/Lab 更鲁棒
1.3 图像坐标系
u (列/x)
────────→
│ ┌────────
v │ │(u,v)
│ │ 像素
↓ │
(行/y)
二、基础图像操作
2.1 像素操作
import cv2
import numpy as np
# 读取/写入
img = cv2.imread('image.jpg')
cv2.imwrite('output.jpg', img)
# 颜色空间转换
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 像素访问
pixel = img[100, 200] # (b,g,r)
img[100:200, 200:300] = [255, 0, 0] # ROI操作
2.2 几何变换(投影模型&单应矩阵)
| 变换 | 自由度 | 矩阵形式 | 不变性质 |
|---|---|---|---|
| 平移 | 2 | [I|t] | 方向 |
| 刚体(旋转+平移) | 3 | [R|t] | 长度+角度 |
| 相似(缩放+刚体) | 4 | s[R|t] | 角度 |
| 仿射 | 6 | A=[[a11,a12,a13],[a21,a22,a23]] | 平行线 |
| 透视/投影 | 8 | H (3×3) | 直线(交比) |
# 图像缩放
resized = cv2.resize(img, (width, height))
resized = cv2.resize(img, None, fx=0.5, fy=0.5)
# 旋转
(h, w) = img.shape[:2]
M = cv2.getRotationMatrix2D((w/2, h/2), 45, 1.0)
rotated = cv2.warpAffine(img, M, (w, h))
# 透视变换
M = cv2.getPerspectiveTransform(src_pts, dst_pts)
warped = cv2.warpPerspective(img, M, (out_w, out_h))
2.3 直方图操作
# 直方图计算
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
# 直方图均衡化(增强对比度)
equ = cv2.equalizeHist(gray)
# CLAHE(自适应直方图均衡化,避免噪声放大)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
enhanced = clahe.apply(gray)
# 直方图匹配
# 将图像直方图映射到目标分布
三、图像滤波(核心)
3.1 线性滤波
| 滤波器 | 核 | 效果 | 公式 |
|---|---|---|---|
| 均值滤波 | 1/k² * ones(k,k) | 平滑去噪,模糊 | G(i) = 1/N Σ I(j) |
| 高斯滤波 | G(x,y) = exp(-(x²+y²)/2σ²) | 加权平滑,保留边缘 | G*I |
| Sobel | [-1,0,1; -2,0,2; -1,0,1] | 水平和垂直边缘 | ∇I |
| Scharr | 优化Sobel权重 | 更精确梯度 | ∇I |
| Laplacian | [0,1,0; 1,-4,1; 0,1,0] | 二阶边缘检测 | ∇²I |
| LoG | Gauss + Laplacian | 高斯拉普拉斯 | σ · (∇²G) * I |
3.2 非线性滤波
| 滤波器 | 原理 | 优点 |
|---|---|---|
| 中值滤波 | 邻域内像素取中值 | 去椒盐噪声,保边缘 |
| 双边滤波 | 空间域+像素值域加权 | 保边去噪,美颜 |
| 非局部均值 | 全图相似块加权 | 去噪效果最好 |
| 导向滤波 | 利用引导图滤波 | O(1)复杂度,保边 |
# 线性滤波
blur = cv2.blur(img, (5,5)) # 均值滤波
gauss = cv2.GaussianBlur(img, (5,5), 1.5) # 高斯滤波
sobel = cv2.Sobel(img, cv2.CV_64F, 1, 0) # Sobel X方向
lap = cv2.Laplacian(img, cv2.CV_64F) # Laplacian
# 非线性滤波
median = cv2.medianBlur(img, 5) # 中值滤波
bilateral = cv2.bilateralFilter(img, 9, 75, 75) # 双边滤波
3.3 图像金字塔
Level 0 (原始) → Level 1 (1/2) → Level 2 (1/4)
W×H W/2 × H/2 W/4 × H/4
- 高斯金字塔: 平滑+下采样
- 拉普拉斯金字塔: 高频残差(用于图像融合/压缩)
- SIFT的关键: 在不同尺度(八度)上检测关键点
# 高斯金字塔
layer = img.copy()
gp = [layer]
for i in range(6):
layer = cv2.pyrDown(layer)
gp.append(layer)
# 拉普拉斯金字塔
lp = [gp[5]]
for i in range(5, 0, -1):
expanded = cv2.pyrUp(gp[i])
laplacian = cv2.subtract(gp[i-1], expanded)
lp.append(laplacian)
四、边缘检测 ⭐
4.1 Canny边缘检测(经典算法)
步骤:
- 高斯平滑: 去噪声
- 计算梯度: Sobel → 幅值M + 方向θ
- M = √(Gx² + Gy²)
- θ = atan2(Gy, Gx)
- 非极大值抑制: 只保留局部的梯度最大值
- 双阈值: 高阈值>强边缘, 低阈值>弱边缘
- 边缘跟踪: 只保留与强边缘连接的弱边缘
edges = cv2.Canny(img, threshold1=50, threshold2=150)
4.2 其他边缘检测
| 算法 | 特点 |
|---|---|
| Sobel | 简单快速,对噪声敏感 |
| Prewitt | 类似Sobel,权重更简单 |
| Roberts Cross | 2×2核,对噪声极敏感 |
| LoG (Marr-Hildreth) | 零交叉检测 |
| DoG | LoG的高效近似 |
| Canny | 最经典,效果最好 |
4.3 边缘检测评估指标
- RMSE (均方根误差)
- PSNR (峰值信噪比)
- SSIM (结构相似性)
- Edge Precision / Recall
- Pratt’s Figure of Merit (FOM)
五、形态学操作(二值图处理)
5.1 基本操作
| 操作 | 公式 | 效果 |
|---|---|---|
| 腐蚀 | A⊖B = {z | B_z ⊆ A} |
| 膨胀 | A⊕B = {z | B̂_z ∩ A ≠ ∅} |
| 开运算 | (A⊖B)⊕B | 先腐蚀后膨胀:去噪点 |
| 闭运算 | (A⊕B)⊖B | 先膨胀后腐蚀:填小孔 |
| 形态学梯度 | 膨胀-腐蚀 | 边缘提取 |
| Top Hat | 原图 - 开运算 | 提取亮特征 |
| Black Hat | 闭运算 - 原图 | 提取暗特征 |
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
eroded = cv2.erode(img, kernel, iterations=1)
dilated = cv2.dilate(img, kernel, iterations=1)
opened = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
closed = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
六、图像分割(经典方法)
| 方法 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 阈值分割 (Otsu) | 最大化类间方差 | 自动/快速 | 仅适合双峰直方图 |
| 分水岭算法 | 洪水泛滥 | 粘连分割 | 易过分割 |
| GrabCut | 图割迭代 | 交互式分割 | 需初始框 |
| Mean Shift | 聚类+空间 | 自动分割 | 参数敏感 |
| SLIC超像素 | K-means + 空间约束 | 快速 | 需指定数量 |
| GraphCut | 最小割 | 能量优化分割 | 计算量大 |
# Otsu阈值
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 自适应阈值
adaptive = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2)
# GrabCut
mask = np.zeros(img.shape[:2], np.uint8)
bgdModel = np.zeros((1,65), np.float64)
fgdModel = np.zeros((1,65), np.float64)
rect = (x, y, w, h)
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT)
mask2 = np.where((mask==2)|(mask==0), 0, 1).astype('uint8')
result = img * mask2[:,:,np.newaxis]
# SLIC超像素
from skimage.segmentation import slic
segments = slic(img, n_segments=250, compactness=10)
七、霍夫变换(Hough Transform)
7.1 原理
将图像空间的点映射到参数空间:
- 直线检测: ρ = x·cosθ + y·sinθ
- 一点 → 一条正弦曲线
- N点共线 → 曲线交汇于一处
- 圆检测: (x-a)² + (y-b)² = r²
# 直线检测
lines = cv2.HoughLinesP(edges, rho=1, theta=np.pi/180,
threshold=100, minLineLength=100, maxLineGap=10)
# 圆检测
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, dp=1, minDist=20,
param1=50, param2=30, minRadius=0, maxRadius=0)
八、图像增强与复原
8.1 增强技术
| 技术 | 方法 |
|---|---|
| 对比度拉伸 | 线性/非线性映射 |
| 直方图均衡化 | HE / CLAHE |
| Gamma校正 | I’ = I^γ |
| 锐化 | Laplacian + 原图: I’ = I - α∇²I |
| Retinex | 光照分离 |
| 去雾 | Dark Channel Prior (DCP) |
8.2 去噪方法
| 方法 | 特点 |
|---|---|
| 滤波去噪 | 高斯/中值/双边 |
| Non-Local Means | 相似块平均 |
| BM3D | 3D协同滤波,SSIM最佳 |
| DnCNN (DL) | 深度学习去噪 |
| Noise2Void (Self-supervised) | 无需clean数据 |
# 锐化
kernel_sharpen = np.array([[0,-1,0], [-1,5,-1], [0,-1,0]])
sharpened = cv2.filter2D(img, -1, kernel_sharpen)
# Retinex
# ... 需实现多尺度Retinex (MSRCR)
九、视频处理基础
9.1 基本操作
cap = cv2.VideoCapture('video.mp4')
fps = int(cap.get(cv2.CAP_PROP_FPS))
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
while True:
ret, frame = cap.read()
if not ret: break
# 处理每一帧
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
9.2 帧差法(运动检测)
diff = cv2.absdiff(frame1, frame2)
thresh = cv2.threshold(diff, 25, 255, cv2.THRESH_BINARY)[1]
9.3 背景减除
backSub = cv2.createBackgroundSubtractorMOG2()
# 或: backSub = cv2.createBackgroundSubtractorKNN()
fgMask = backSub.apply(frame)
📺 推荐视频
| 资源 | 链接 |
|---|---|
| OpenCV 官方入门教程 | https://docs.opencv.org/master/d9/df8/tutorial_root.html |
| Learn OpenCV (YouTube) | https://www.youtube.com/@LearnOpenCV |
| 图像处理基础 (MIT 6.819) | MIT OCW |
| 数字图像处理 (王伟, 中科大) | B站 |
📚 推荐书籍
- Digital Image Processing (4th Ed.) - Gonzalez & Woods ⭐
- Computer Vision: Algorithms and Applications - Szeliski (第3章)
- Practical Python and OpenCV - Adrian Rosebrock
- Learning OpenCV - Bradski & Kaehler
- Programming Computer Vision with Python - Jan Erik Solem
🔗 视频链接
- OpenCV Tutorial (B站): 搜索 “OpenCV教程”
- 中科大《数字图像分析》: B站搜索
- CS231n 图像分类部分
附录:深层补充
1. 频率域图像处理详解
1.1 傅里叶变换在图像中的含义
二维离散傅里叶变换(DFT):
F ( u , v ) = ∑ x = 0 M − 1 ∑ y = 0 N − 1 f ( x , y ) e − j 2 π ( u x / M + v y / N ) F(u,v) = \sum_{x=0}^{M-1} \sum_{y=0}^{N-1} f(x,y) e^{-j2\pi(ux/M + vy/N)} F(u,v)=x=0∑M−1y=0∑N−1f(x,y)e−j2π(ux/M+vy/N)
频率分量的物理含义:
- 低频( u , v u,v u,v 接近0):对应图像中灰度缓慢变化区域(平滑背景、大块物体)
- 高频( u , v u,v u,v 较大):对应灰度急剧变化区域(边缘、角点、纹理、噪声)
- 幅度谱 ∣ F ( u , v ) ∣ |F(u,v)| ∣F(u,v)∣:各频率成分的强度
- 相位谱 ∠ F ( u , v ) \angle F(u,v) ∠F(u,v):各频率成分的位置信息(相位对图像感知极其重要,即使幅度谱被破坏,仅用相位谱也能恢复出可识别的边缘信息)
性质:
- 中心化:将低频移到中心( F ( u − M / 2 , v − N / 2 ) ⋅ ( − 1 ) u + v F(u-M/2, v-N/2) \cdot (-1)^{u+v} F(u−M/2,v−N/2)⋅(−1)u+v)
- 旋转不变性:图像旋转 θ \theta θ → 幅度谱也旋转 θ \theta θ
- 尺度变化:图像缩小 → 频谱扩展(反比关系)
1.2 滤波器传递函数
理想低通滤波器(ILPF):
H ( u , v ) = { 1 D ( u , v ) ≤ D 0 0 D ( u , v ) > D 0 H(u,v) = \begin{cases} 1 & D(u,v) \leq D_0 \\ 0 & D(u,v) > D_0 \end{cases} H(u,v)={10D(u,v)≤D0D(u,v)>D0
- 优点:数学简单
- 缺点:振铃效应(Gibbs现象),因频域突变导致空域振荡
Butterworth低通滤波器(BLPF):
H ( u , v ) = 1 1 + [ D ( u , v ) / D 0 ] 2 n H(u,v) = \frac{1}{1 + [D(u,v)/D_0]^{2n}} H(u,v)=1+[D(u,v)/D0]2n1
- n n n 阶控制过渡带宽度
- n n n 越大越接近理想滤波器(振铃越强)
- n n n 小则平滑过渡,无振铃
高斯低通滤波器(GLPF):
H ( u , v ) = e − D 2 ( u , v ) / 2 σ 2 = e − D 2 ( u , v ) / 2 D 0 2 H(u,v) = e^{-D^2(u,v)/2\sigma^2} = e^{-D^2(u,v)/2D_0^2} H(u,v)=e−D2(u,v)/2σ2=e−D2(u,v)/2D02
- 空域和频域都是高斯(无振铃)
- 时频不确定性原理: σ x ⋅ σ u ≥ 1 / 4 π \sigma_x \cdot \sigma_u \geq 1/4\pi σx⋅σu≥1/4π
import numpy as np
import cv2
def fft_filter(img, D0, filter_type='gaussian', n=2):
"""频域滤波通用函数"""
# DFT
f = np.fft.fft2(img.astype(np.float32))
fshift = np.fft.fftshift(f)
# 构建滤波器
rows, cols = img.shape
crow, ccol = rows // 2, cols // 2
U, V = np.meshgrid(np.arange(cols), np.arange(rows))
D = np.sqrt((U - ccol)**2 + (V - crow)**2)
if filter_type == 'ideal':
H = (D <= D0).astype(np.float32)
elif filter_type == 'butterworth':
H = 1 / (1 + (D / D0)**(2*n))
elif filter_type == 'gaussian':
H = np.exp(-D**2 / (2 * D0**2))
# 应用滤波器并反变换
f_filtered = fshift * H
f_ishift = np.fft.ifftshift(f_filtered)
img_back = np.fft.ifft2(f_ishift)
return np.abs(img_back)
1.3 FFT加速卷积原理
空域卷积复杂度 O ( M N ⋅ k 2 ) O(MN \cdot k^2) O(MN⋅k2),频域复杂度 O ( M N log M N ) O(MN \log MN) O(MNlogMN)。
卷积定理:
f ∗ g = F − 1 { F { f } ⋅ F { g } } f * g = \mathcal{F}^{-1}\{\mathcal{F}\{f\} \cdot \mathcal{F}\{g\}\} f∗g=F−1{F{f}⋅F{g}}
加速条件:当卷积核 k × k k \times k k×k 满足 k k k 远大于 log 2 N \log_2 N log2N 时,FFT加速显著。实践中,图像越大、核越大,FFT加速越明显。
实际例子:1000×1000图像,50×50卷积核
- 空域: 10 6 × 2500 = 2.5 × 10 9 10^6 \times 2500 = 2.5 \times 10^9 106×2500=2.5×109 次操作
- FFT: 2 × 10 6 × log 2 ( 2048 ) ≈ 2.2 × 10 7 2 \times 10^6 \times \log_2(2048) \approx 2.2 \times 10^7 2×106×log2(2048)≈2.2×107 次操作
- 加速比:约100倍
2. 边缘检测的深入对比
2.1 各算子的数学原理
Sobel算子:
G x = [ − 1 0 1 − 2 0 2 − 1 0 1 ] , G y = [ − 1 − 2 − 1 0 0 0 1 2 1 ] G_x = \begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{bmatrix}, \quad G_y = \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \end{bmatrix} Gx=
−1−2−1000121
,Gy=
−101−202−101
本质:水平方向平滑(3点均值)+ 垂直方向差分(中心差分的加权版)。
Prewitt算子:
G x = [ − 1 0 1 − 1 0 1 − 1 0 1 ] , G y = [ − 1 − 1 − 1 0 0 0 1 1 1 ] G_x = \begin{bmatrix} -1 & 0 & 1 \\ -1 & 0 & 1 \\ -1 & 0 & 1 \end{bmatrix}, \quad G_y = \begin{bmatrix} -1 & -1 & -1 \\ 0 & 0 & 0 \\ 1 & 1 & 1 \end{bmatrix} Gx=
−1−1−1000111
,Gy=
−101−101−101
比Sobel更简单的权重(无中心加强),对噪声更敏感。
Roberts Cross算子:
G x = [ 1 0 0 − 1 ] , G y = [ 0 1 − 1 0 ] G_x = \begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}, \quad G_y = \begin{bmatrix} 0 & 1 \\ -1 & 0 \end{bmatrix} Gx=[100−1],Gy=[0−110]
2×2核,方向对角,对噪声最敏感(感受野最小)。
Laplacian算子:
∇ 2 f = ∂ 2 f ∂ x 2 + ∂ 2 f ∂ y 2 \nabla^2 f = \frac{\partial^2 f}{\partial x^2} + \frac{\partial^2 f}{\partial y^2} ∇2f=∂x2∂2f+∂y2∂2f
离散近似(4邻域): [ 0 1 0 1 − 4 1 0 1 0 ] \begin{bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \end{bmatrix}
0101−41010
8邻域: [ 1 1 1 1 − 8 1 1 1 1 ] \begin{bmatrix} 1 & 1 & 1 \\ 1 & -8 & 1 \\ 1 & 1 & 1 \end{bmatrix}
1111−81111
特点:二阶导数为零交叉(zero-crossing)对应边缘。
LoG (Laplacian of Gaussian):
LoG ( x , y ) = 1 π σ 4 ( x 2 + y 2 2 σ 2 − 1 ) e − x 2 + y 2 2 σ 2 \text{LoG}(x,y) = \frac{1}{\pi\sigma^4}\left(\frac{x^2+y^2}{2\sigma^2} - 1\right) e^{-\frac{x^2+y^2}{2\sigma^2}} LoG(x,y)=πσ41(2σ2x2+y2−1)e−2σ2x2+y2
先高斯平滑再Laplacian,等效于用LoG核对图像做一次卷积。
DoG (Difference of Gaussians):
DoG ( x , y ) = G σ 1 ( x , y ) − G σ 2 ( x , y ) ≈ LoG ( x , y ) \text{DoG}(x,y) = G_{\sigma_1}(x,y) - G_{\sigma_2}(x,y) \approx \text{LoG}(x,y) DoG(x,y)=Gσ1(x,y)−Gσ2(x,y)≈LoG(x,y)
LoG的高效近似(SIFT中用于检测尺度空间极值)。
2.2 Canny完整流程详解
def canny_edge_detection(img, sigma=1.0, low_thresh=0.1, high_thresh=0.3):
# Step 1: 高斯平滑
# 核大小取 2*ceil(3*sigma)+1
ksize = int(2 * np.ceil(3 * sigma) + 1)
smoothed = cv2.GaussianBlur(img, (ksize, ksize), sigma)
# Step 2: 计算梯度幅值和方向
Gx = cv2.Sobel(smoothed, cv2.CV_64F, 1, 0, ksize=3)
Gy = cv2.Sobel(smoothed, cv2.CV_64F, 0, 1, ksize=3)
magnitude = np.sqrt(Gx**2 + Gy**2)
angle = np.arctan2(Gy, Gx) * 180 / np.pi
# 量化角度到4个方向: 0°, 45°, 90°, 135°
angle[angle < 0] += 180
angle = np.round(angle / 45) * 45 % 180
# Step 3: 非极大值抑制(Non-Maximum Suppression)
# 对每个像素,沿梯度方向比较相邻两像素的幅值
# 若当前像素不是最大值则抑制
nms = np.zeros_like(magnitude)
h, w = magnitude.shape
for i in range(1, h-1):
for j in range(1, w-1):
theta = angle[i, j]
if theta == 0: # 水平方向
n1, n2 = magnitude[i, j-1], magnitude[i, j+1]
elif theta == 45: # 对角线
n1, n2 = magnitude[i+1, j-1], magnitude[i-1, j+1]
elif theta == 90: # 垂直方向
n1, n2 = magnitude[i-1, j], magnitude[i+1, j]
else: # 135°对角线
n1, n2 = magnitude[i-1, j-1], magnitude[i+1, j+1]
if magnitude[i, j] >= n1 and magnitude[i, j] >= n2:
nms[i, j] = magnitude[i, j]
# Step 4: 双阈值检测
high = high_thresh * nms.max()
low = low_thresh * high
strong = (nms >= high).astype(np.uint8) * 255
weak = ((nms >= low) & (nms < high)).astype(np.uint8) * 25
# Step 5: 边缘跟踪(滞后的阈值化)
# 只保留与强边缘相连的弱边缘
edges = strong.copy()
# 使用8连通检查
for i in range(1, h-1):
for j in range(1, w-1):
if weak[i, j] > 0: # 弱边缘
if np.any(strong[i-1:i+2, j-1:j+2]): # 邻域有强边缘
edges[i, j] = 255
return edges
各算子噪声鲁棒性对比(从优到劣):
Canny > LoG > Sobel > Prewitt > Roberts
Canny通过三步保证鲁棒性:1) 高斯平滑(去噪)2) NMS(细化边缘)3) 双阈值滞后(剔除虚假响应)
3. 形态学操作的数学形态学
3.1 集合论定义
设 A A A 为二值图像中的像素集合, B B B 为结构元素。
腐蚀:
A ⊖ B = { z ∣ B z ⊆ A } A \ominus B = \{z \mid B_z \subseteq A\} A⊖B={z∣Bz⊆A}
// 结构元素完全包含在A中的所有中心点
膨胀:
A ⊕ B = { z ∣ B ^ z ∩ A ≠ ∅ } A \oplus B = \{z \mid \hat{B}_z \cap A \neq \emptyset\} A⊕B={z∣B^z∩A=∅}
// 结构元素(取反射后)在A中有交集的所有中心点
开运算:
A ∘ B = ( A ⊖ B ) ⊕ B A \circ B = (A \ominus B) \oplus B A∘B=(A⊖B)⊕B
// 先腐蚀后膨胀:去除小凸起、断开细连接
闭运算:
A ∙ B = ( A ⊕ B ) ⊖ B A \bullet B = (A \oplus B) \ominus B A∙B=(A⊕B)⊖B
// 先膨胀后腐蚀:填充小孔洞、连接断裂
对偶性:
( A ⊖ B ) c = A c ⊕ B ^ (A \ominus B)^c = A^c \oplus \hat{B} (A⊖B)c=Ac⊕B^
( A ∘ B ) c = A c ∙ B ^ (A \circ B)^c = A^c \bullet \hat{B} (A∘B)c=Ac∙B^
3.2 击中击不中变换(Hit-or-Miss)
定义: A ⊛ B = ( A ⊖ B 1 ) ∩ ( A c ⊖ B 2 ) A \circledast B = (A \ominus B_1) \cap (A^c \ominus B_2) A⊛B=(A⊖B1)∩(Ac⊖B2)
其中 B = ( B 1 , B 2 ) B = (B_1, B_2) B=(B1,B2) 是复合结构元素, B 1 B_1 B1 匹配前景, B 2 B_2 B2 匹配背景。
应用:
- 细化(Thinning): A ⊗ B = A − ( A ⊛ B ) A \otimes B = A - (A \circledast B) A⊗B=A−(A⊛B)
- 粗化(Thickening): A ⊙ B = A ∪ ( A ⊛ B ) A \odot B = A \cup (A \circledast B) A⊙B=A∪(A⊛B)
- 骨架提取:通过反复细化
- 角点检测:特定模式的击中击不中
3.3 形态学重建
地质学重建:基于标记图像(marker)和掩模图像(mask)的迭代膨胀。
R M ( F ) = 重复 [ ( F ⊕ B ) ∩ M ] 直到稳定 R_M(F) = \text{重复} [(F \oplus B) \cap M] \text{ 直到稳定} RM(F)=重复[(F⊕B)∩M] 直到稳定
其中 F F F 是标记图像(marker), M M M 是掩模图像(mask), F ⊆ M F \subseteq M F⊆M。
应用:
- 重建开运算:先腐蚀再重建,比标准开运算更好地保留形状
- 填充孔洞:标记为边界像素的补集,重建后反转
- 边界清除:标记为边界像素,重建后移除连接边界的物体
def morphological_reconstruction(marker, mask, kernel_size=3):
"""形态学重建"""
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_size, kernel_size))
marker_prev = np.zeros_like(marker)
while not np.array_equal(marker, marker_prev):
marker_prev = marker.copy()
# 膨胀加交会
dilated = cv2.dilate(marker, kernel)
marker = cv2.bitwise_and(dilated, mask)
return marker
4. 图像金字塔与多尺度表示
4.1 Gaussian金字塔和Laplacian金字塔的构建数学
Gaussian金字塔(下采样):
G l + 1 ( i , j ) = ∑ m = − 2 2 ∑ n = − 2 2 w ( m , n ) ⋅ G l ( 2 i + m , 2 j + n ) G_{l+1}(i,j) = \sum_{m=-2}^{2} \sum_{n=-2}^{2} w(m,n) \cdot G_l(2i+m, 2j+n) Gl+1(i,j)=m=−2∑2n=−2∑2w(m,n)⋅Gl(2i+m,2j+n)
其中 w ( m , n ) w(m,n) w(m,n) 是高斯权重,通常用5×5可分离高斯核:
w = 1 256 [ 1 4 6 4 1 4 16 24 16 4 6 24 36 24 6 4 16 24 16 4 1 4 6 4 1 ] w = \frac{1}{256} \begin{bmatrix} 1 & 4 & 6 & 4 & 1 \\ 4 & 16 & 24 & 16 & 4 \\ 6 & 24 & 36 & 24 & 6 \\ 4 & 16 & 24 & 16 & 4 \\ 1 & 4 & 6 & 4 & 1 \end{bmatrix} w=2561
1464141624164624362464162416414641
这一步相当于高斯平滑 + 2倍下采样。
Laplacian金字塔(高频残差):
L l = G l − expand ( G l + 1 ) L_l = G_l - \text{expand}(G_{l+1}) Ll=Gl−expand(Gl+1)
其中 expand 操作:将图像放大2倍后高斯插值。
expand ( G l + 1 ) ( i , j ) = 4 ∑ m = − 2 2 ∑ n = − 2 2 w ( m , n ) ⋅ G l + 1 ( i − m 2 , j − n 2 ) \text{expand}(G_{l+1})(i,j) = 4 \sum_{m=-2}^{2} \sum_{n=-2}^{2} w(m,n) \cdot G_{l+1}\left(\frac{i-m}{2}, \frac{j-n}{2}\right) expand(Gl+1)(i,j)=4m=−2∑2n=−2∑2w(m,n)⋅Gl+1(2i−m,2j−n)
L l L_l Ll 包含了 G l G_l Gl 中 G l + 1 G_{l+1} Gl+1 所无法表示的高频信息(边缘、纹理细节)。
完全重建:
G 0 = expand ( G 1 ) + L 0 = expand ( expand ( G 2 ) + L 1 ) + L 0 = . . . G_0 = \text{expand}(G_1) + L_0 = \text{expand}(\text{expand}(G_2) + L_1) + L_0 = ... G0=expand(G1)+L0=expand(expand(G2)+L1)+L0=...
4.2 多频段图像融合(Multi-band Blending)
用于全景拼接和无缝图像融合。
算法步骤:
def multi_band_blending(img1, img2, mask, num_levels=5):
"""
img1, img2: 输入图像
mask: 融合权重掩模(0=img1区域, 1=img2区域, 中间=过渡)
"""
# 1. 构建两幅图的Laplacian金字塔
lap_pyramid1 = build_laplacian_pyramid(img1, num_levels)
lap_pyramid2 = build_laplacian_pyramid(img2, num_levels)
# 2. 构建掩模的Gaussian金字塔
mask_pyramid = build_gaussian_pyramid(mask, num_levels)
# 3. 逐层融合
blended_pyramid = []
for l in range(num_levels):
blended = lap_pyramid1[l] * (1 - mask_pyramid[l]) + lap_pyramid2[l] * mask_pyramid[l]
blended_pyramid.append(blended)
# 4. 从金字塔重建图像
result = reconstruct_from_laplacian_pyramid(blended_pyramid)
return result
原理:高斯金字塔的层对应低通版本,Laplacian层对应带通版本。每层独立融合可以:
- 低频区域(顶层):跨越拼接缝平滑过渡
- 高频区域(底层):保留各自纹理细节,仅在接缝附近融合
相比于直接加权融合(出现突兀的重影和接缝),多频段融合可以同时实现平滑过渡和细节保留。
选择融合层数的经验:
- 图像分辨率 W × H W \times H W×H → 最大层数 L = ⌊ log 2 min ( W , H ) ⌋ L = \lfloor \log_2 \min(W,H) \rfloor L=⌊log2min(W,H)⌋
- 通常取 4-6 层
- 当两张图对齐非常精确时,可以减少层数(更多直接混合)
- 当有视差或对齐误差时,增加层数让低频过渡更平滑
更多推荐

所有评论(0)