Digital Image Sampling and Processing Notes

Yipyip!
开学一周速通图像处理,剩下时间 All in CS!

Episode 1

Method

(1) 采样: 将图像在空间上离散化, (得到一个二维矩阵,称为采样矩阵)

(2) 量化: 将采样后的各个点的灰度值转换为离散值 (纯坐标数字化)

选取原则

(1) 灰度变化慢的地方, 粗采样, 细量化

(2) 灰度变化快的地方, 细采样, 粗量化

采样定理

(1) 采样定理: 采样频率要大于等于信号频率的两倍

(2) 采样定理的意义: 避免混叠现象

图像质量

(1) 灰度级: 表示pixels明暗程度的整数量

(2) 层次: 实际图像拥有的灰度级数量(层次越多,视觉效果越好)

(3) 对比度: 图像中灰度反差的大小,即最大亮度/最小亮度 $$C = \frac{L_{max} - L_{min}}{L_{max} + L_{min}}$$

(4) 清晰度

Pixels 的位置关系

(1) 4-邻域: $ p(x,y)$ 的上下左右

(2) 8-邻域: $p(x,y)$ 的八向

$$Blue: 四邻域, Green: D-邻域, 重叠部分为八邻域$$

连通性

(1) 4-连通: 两个像素点的4-邻域有公共点

(2) 8-连通: 两个像素点的8-邻域有公共点

(3) M-连通(混合连通): p 在$N_4(p)$或 q 在$N_D(p)$中,且$N_4(p)$与$N_4(q)$的交集为$\varnothing$

连通性示意图

4-Connected

8-Connected

距离 (Distance)

对于二维平面上的两个点 $p(x_p, y_p)$ 和 $q(x_q, y_q)$, 有以下三种距离定义:

(1) 欧式距离: $$d(p,q) = \sqrt{(x_p - x_q)^2 + (y_p - y_q)^2}$$

(2) $D_4$距离(城市距离): $$d(p,q) = |x_p - x_q| + |y_p - y_q|$$

eg:

(3) 棋盘距离(切比雪夫距离): $$d(p,q) = max(|x_p - x_q|, |y_p - y_q|)$$

eg:

用python绘制距离矩阵

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import matplotlib.pyplot as plt
import numpy as np

def plot_distance_matrix(matrix, title):
fig, ax = plt.subplots()
cax = ax.matshow(matrix, cmap='viridis')
for (i, j), val in np.ndenumerate(matrix):
ax.text(j, i, f'{val:.0f}', ha='center', va='center', color='white')
plt.title(title)
plt.colorbar(cax)
plt.show()

# 中心点
center = (2, 2)

# 曼哈顿距离
d4_matrix = np.zeros((5, 5))
for i in range(5):
for j in range(5):
d4_matrix[i, j] = abs(i - center[0]) + abs(j - center[1])

# 棋盘距离
d8_matrix = np.zeros((5, 5))
for i in range(5):
for j in range(5):
d8_matrix[i, j] = max(abs(i - center[0]), abs(j - center[1]))

plot_distance_matrix(d4_matrix, 'Manhattan Distance')
plot_distance_matrix(d8_matrix, 'Chessboard Distance')

Episode 2

仿射变换

仿射变换是指在二维平面上的点经过一系列的线性变换平移变换后得到的新的点,即 $$g(x,y) = A \cdot f(x,y) + b$$

A变换矩阵(Affine Matrix),b 为平移向量(Translation Vector)

仿射变换应用在图像中可以做到旋转、缩放、平移、剪切等操作

计算公式如下:

以尺度变换举例:
假如 变换矩阵 $A$ 为 $\begin{bmatrix} 0.5 & 0 & 0 \ 0 & 0.5 & 0 \ 0 & 0 & 1\end{bmatrix}$,平移向量 $b$ 为 $\begin{bmatrix} 0 \ 0 \end{bmatrix}$,那么根据公式计算可以得到新的点坐标为 $x’, y’$ = $0.5x$ , $0.5y$,即将图像缩小为原图的 $\frac{1}{2}$

用py实现:

1
2
3
4
5
6
7
8
9
10
11
12
img = cv2.imread('lena.png')
rows, cols, ch = img.shape

# 尺度变换
M = np.float32([[0.5, 0, 0], [0, 0.5, 0]])
dst = cv2.warpAffine(img, M, (cols, rows))

# 对比
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

上述代码会将图像缩小为原图的 $\frac{1}{2}$

灰度变换

灰度变换是指将图像的灰度级进行变换,常见的灰度变换有线性变换、非线性变换等

图像反转

就是将图像的灰度级进行反转,即
$$g(x,y) = 255 - f(x,y)$$ or
$$S=L-1-R$$

1
2
3
4
5
6
# 图像反转
dst = np.zeros((rows, cols, ch), np.uint8)
for i in range(rows):
for j in range(cols):
for k in range(ch):
dst[i, j, k] = 255 - img[i, j, k]

Result:
greyreverse

线性变换

就是将图像的灰度级进行线性变换,即 $$ s = a \cdot r + b$$

其中 a 为增益(Gain),b 为偏置(Bias)

1
2
3
4
5
6
7
8
# 线性变换
dst = np.zeros((rows, cols, ch), np.uint8)
a = 2
b = 100
for i in range(rows):
for j in range(cols):
for k in range(ch):
dst[i, j, k] = np.clip(a * img[i, j, k] + b, 0, 255)

Result:
greylinear

非线性变换

非线性变换是指将图像的灰度级进行非线性变换,常见的非线性变换有对数变换、伽马变换等

对数变换

计算公式: $$s = c \cdot \log_{v+1}(1 + v*r) , r \in [0, 1]$$

由于对数本身“凸”的性质,它可以将低灰度部分的亮度提高,由式子可以看出当 $v$ 越大时灰度提高的就越明显,图像就会变亮

1
2
3
4
5
6
7
# 对数变换
dst = np.zeros((rows, cols, ch), np.uint8)
c = 255 / np.log(1 + np.max(img))
for i in range(rows):
for j in range(cols):
for k in range(ch):
dst[i, j, k] = np.clip(c * np.log(1 + img[i, j, k]), 0, 255)

Result:
greylog

Gamma 变换/修正 (Gamma Correction)

计算公式: $$s = c \cdot r^{\gamma}$$
or
$$V_{out} = A \cdot V_{in}^{\gamma}$$

Gamma 变换是对图像的非线性调整,可以将灰度过高或过低的区域进行调整,增强对比度,引用Gamma曲线可以看到

  • 当 $\gamma > 1$ 时,图像灰度级高的区域会变被拉伸,低的区域会被压缩
  • 当 $\gamma < 1$ 时,图像灰度级高的区域会被压缩,低的区域会被拉伸
1
2
3
4
5
6
7
# Gamma 变换
def gamma_transform(image, gamma, c=1):
dst = np.zeros((rows, cols, ch), np.uint8)
for i in range(rows):
for j in range(cols):
for k in range(ch):
dst[i, j, k] = np.clip(c * np.power(image[i, j, k] / 255, gamma) * 255, 0, 255)

Result:
greygamma

由结果可以看出,当$\gamma > 1$时, 图像变暗,$\gamma < 1$时,图像变亮了

直方图均衡化

由于图像的灰度级分布不均匀,导致图像的对比度不高,直方图均衡化就是将图像的灰度级分布均匀化,使得图像的对比度增强

直方图均衡化的计算公式如下:
$$s = T(r) = \frac{L-1}{MN} \sum_{j=0}^{r} n_j$$

其中 $n_j$ 为灰度级为 j 的像素点个数,$M$ 为图像的行数,$N$ 为图像的列数,$L$ 为灰度级的个数,$s$为灰度级为r的像素点的累积分布,即新的灰度级

下表能更好的展示直方图均衡化的过程

假设有一张图像的灰度级分布如下:

* * * * *
1 5 3 2 1
25 1 2 3 5
3 2 25 5 1
2 3 25 1 2

统计灰度值的占比如下:

1 2 3 5 25
0.25 0.25 0.2 0.15 0.15

那么其灰度直方图可以表示为:

灰度值 占比 累积分布 新的灰度值
1 0.25 0.25 6.3
2 0.25 0.5 12.5
3 0.2 0.7 17.5
5 0.15 0.85 21.3
25 0.15 1 25

由此我们就得到了新的灰度级分布,即直方图均衡化的结果

Opencv可以直接调用 cv2.equalizeHist() 函数来实现直方图均衡化
这里我先将原彩色图像转为灰度图像,然后再进行直方图均衡化

Result:
histeq

空间域滤波

滤波一词来源于信号处理,是指对信号进行处理,以便得到所需的信息。在图像处理中,滤波是指对图像进行处理,以便得到所需的信息。滤波的目的是增强图像的某些特征,抑制图像的某些特征,或者提取图像的某些特征。比如对图像进行降噪、锐化、平滑等操作。

空间域滤波的基本原理

首先我们会有一个Kernel,也叫 Filter (滤波器) , 它是一个小矩阵,用来对图像进行处理。对于图像中的每一个像素,我们都会用Kernel对其进行卷积处理,得到一个新的像素值。这个新的像素值就是对原图像中的像素进行滤波后得到的像素值。

比如一个 $3 \times 3$ 的 Kernel 模板,其形式是:
$$\begin{bmatrix}
1 & 1 & 1 \
1 & 1 & 1 \
1 & 1 & 1
\end{bmatrix}
$$

假设有一个像素分布如下的图像:
$$
\begin{bmatrix}
1 & 2 & 3 \
4 & 5 & 6 \
7 & 8 & 9
\end{bmatrix}
$$

我们用 Kernel 对这个图像的每一个像素进行卷积处理 (可以看作是直接将Kernel覆盖在这个图像上,这个像素对应着Kernel的中点’1’的位置) ,得到新的像素值。比如对于中间的像素5,我们可以得到新的像素值为:

$$\begin{bmatrix} 1 & 1 & 1 \ 1 & 1 & 1 \ 1 & 1 & 1 \end{bmatrix} \times \begin{bmatrix} 1 & 2 & 3 \ 4 & 5 & 6 \ 7 & 8 & 9 \end{bmatrix} = 45$$

更直观点的计算为:

$$ 1 \times 2 + 1 \times 3 + 1 \times 4 + 1 \times 5 + 1 \times 6 + 1 \times 7 + 1 \times 8 + 1 \times 9 = 45 $$

对于图像中的其他像素,我们也可以用同样的方法得到新的像素值。比如第一行第一列的像素1,我们可以得到新的像素值为:

$$1 \times 1 + 1 \times 2 + 1 \times 4 + 1 \times 5 = 12$$

这样我们就可以得到一个新的图像,这个新的图像就是原图像经过Kernel滤波后得到的图像QwQ…

平滑空间滤波器

平滑空间滤波器有:

  • 平滑线性滤波器
  • 高斯滤波器
  • 中值滤波器

平滑线性滤波器最常见的是均值滤波器,它的 Kernel 模板还是上面的那个,只不过这个Kernel的每一个元素都是$\frac{1}{9}$,对上面那个图像进行均值滤波后,我们可以得到新的图像为:

$$
\begin{bmatrix}
1.33 & 2.33 & 1.78 \
3 & 5 & 3.67 \
2.67 & 4.33 & 3.11
\end{bmatrix}
$$

看出来了吧!这个新图像的每一个像素值都是其周围像素的平均值。比如第一个像素1,将Kernel的”中心” 贴在这个像素上,我们可以看出来这个像素周围的像素只有$2,4,5$,那么根据均值滤波的原理,这个像素”1”经过滤波后新的值就是
$$ \frac{1+2+4+5}{9} = 1.33 $$,其他像素也是同理。对于5,它周围的像素为$1,2,3,4,6,7,8,9$,那么它经过均值滤波后的值就是$45/9=5$。

图示: