
系列:图像处理算法入门
期数:第003期 / 共144期
日期:2026-08-12
关键词:数字图像、像素、矩阵、采样、量化、分辨率、位深、颜色通道
难度:⭐⭐☆☆☆(需少量NumPy基础)
一、前言
上期我们搭建好了开发环境,从今天开始进入图像处理的核心理论。理解"图像在计算机中到底是什么",是后续所有算法的地基。本文将从物理图像出发,拆解数字化的三步骤——采样、量化、编码,最终落到一个关键认知:数字图像就是 NumPy 数组(矩阵)。文末提供 4 个完整可运行的代码实验,帮助你在代码层面建立直觉。
二、从物理世界到数字图像:三步走
我们肉眼看到的照片是连续的,但计算机只能处理离散数据。将连续图像转化为数字图像需要三个步骤:
连续图像 ──采样──▶ 离散空间 ──量化──▶ 离散灰度 ──编码──▶ 数字图像
(模拟) (Sampling) (像素网格) (Quantization)(整数值) (Encoding) (二进制矩阵)
2.1 采样(Sampling)—— 空间离散化
定义:将连续的二维空间划分为有限的网格点,每个网格点取一个值作为该位置的代表。
- 采样密度越高(网格越密),空间分辨率越高,图像越清晰。
- 采样不足会导致锯齿/摩尔纹,称为混叠(Aliasing)。
直观理解:把一幅画用棋盘格覆盖,每个格子取一个颜色值。格子越小,还原越精确。
2.2 量化(Quantization)—— 幅值离散化
定义:将每个采样点的连续灰度值映射到有限个离散等级。
- 量化等级越多,灰度分辨率越高,过渡越平滑。
- 量化不足会导致伪轮廓(False Contouring)——本应平滑的渐变出现明显台阶。
常见量化等级:
| 位深 | 量化等级 | 取值范围 | 典型场景 |
|---|---|---|---|
| 1 bit | 2 级 | 0-1 | 二值图、OCR |
| 8 bit | 256 级 | 0-255 | 普通照片(最常见) |
| 16 bit | 65536 级 | 0-65535 | 医学影像、RAW |
| 32 bit | 浮点 | 0.0-1.0 | HDR、科学计算 |
2.3 编码(Encoding)—— 二进制表示
将量化后的整数值用二进制存储。8 位图每个像素占 1 字节,RGB 三通道彩色图每像素占 3 字节。
计算公式:
图像大小(字节) = 宽 × 高 × 通道数 × (位深 / 8)
示例:一张 1920×1080 的 24 位 RGB 图像:
1920 × 1080 × 3 × 1 = 6,220,800 字节 ≈ 5.93 MB(未压缩)
三、像素与分辨率
3.1 像素(Pixel)
像素是数字图像的最小组成单元,名称来自 Picture Element 的缩写。每个像素包含:
- 空间坐标 (x, y) —— 在矩阵中的行列位置
- 灰度值/颜色值 —— 一个或多个数值
在 NumPy 中,像素就是矩阵的一个元素:image[row, col]。
坐标约定:图像坐标系以左上角为原点,行向下、列向右增加。这与数学中的笛卡尔坐标系(Y 向上)不同,初学者容易混淆。
3.2 分辨率(Resolution)
| 概念 | 含义 | 典型值 |
|---|---|---|
| 空间分辨率 | 单位长度内的像素数(PPI/DPI) | 屏幕显示 72 PPI,印刷 300 DPI |
| 灰度分辨率 | 可辨别的灰度等级数 | 8bit = 256 级 |
| 图像尺寸 | 像素总数(宽×高) | 1920×1080 ≈ 207万像素 |
PPI vs DPI:PPI(Pixels Per Inch)用于屏幕显示,DPI(Dots Per Inch)用于打印输出。日常语境常混用。
四、位深与颜色通道
4.1 位深(Bit Depth)
位深决定了每个通道能表示的色彩精度:
| 图像类型 | 通道数 | 位深/通道 | 总位深 | 可表示颜色数 |
|---|---|---|---|---|
| 二值图 | 1 | 1 bit | 1 bit | 2 |
| 灰度图 | 1 | 8 bit | 8 bit | 256 |
| RGB 彩色 | 3 | 8 bit | 24 bit | 16,777,216 |
| RGBA(带透明度) | 4 | 8 bit | 32 bit | 16M + 256级透明 |
4.2 颜色通道(Color Channel)
RGB 图像由三个独立矩阵叠加而成,分别对应红、绿、蓝三个通道:
RGB图像 = [R矩阵] + [G矩阵] + [B矩阵]
形状: (H, W, 3)
在 OpenCV 中,默认顺序是 BGR 而非 RGB(历史原因),这是新手最常见的坑。
OpenCV 读取: img.shape → (H, W, 3) 通道顺序: B, G, R
Pillow 读取: img.size → (W, H) 通道顺序: R, G, B
五、核心认知:图像 = 矩阵
这是全文最重要的一句话:
数字图像在计算机中就是一个多维数组(矩阵)。灰度图是二维矩阵,彩色图是三维张量。所有图像处理算法本质上都是矩阵运算。
| 图像类型 | NumPy 数组形状 | dtype | 取值范围 |
|---|---|---|---|
| 灰度图 (8bit) | (H, W) | uint8 | 0-255 |
| 灰度图 (16bit) | (H, W) | uint16 | 0-65535 |
| RGB 彩色 | (H, W, 3) | uint8 | 0-255 |
| 浮点图 | (H, W) | float32 | 0.0-1.0 |
理解了这一点,你就能用 NumPy 做几乎所有基础图像操作——无需调用任何图像库。
六、代码实践
6.1 实验一:用 NumPy 从零创建灰度图像
"""
实验一:用 NumPy 创建灰度图像矩阵并可视化
理解:灰度图 = 二维数组,值越大越亮
"""
import numpy as np
import matplotlib.pyplot as plt
# ========== 1. 创建全黑图像(5x5) ==========
img_black = np.zeros((5, 5), dtype=np.uint8)
print("5x5 全黑图像矩阵:")
print(img_black)
# 输出:全是 0 的矩阵
# ========== 2. 创建全白图像(5x5) ==========
img_white = np.ones((5, 5), dtype=np.uint8) * 255
print("\n5x5 全白图像矩阵:")
print(img_white)
# 输出:全是 255 的矩阵
# ========== 3. 创建渐变图像(0→255) ==========
# np.linspace 生成 0-255 的渐变,reshape 成 1x256,再广播为 256x256
gradient_row = np.linspace(0, 255, 256, dtype=np.uint8)
img_gradient = np.tile(gradient_row, (256, 1)) # 沿行方向重复256次
# ========== 4. 创建棋盘格图像 ==========
# 利用模运算生成 8x8 格子的棋盘
size, block = 256, 32
rows = np.arange(size) // block
cols = np.arange(size) // block
checkerboard = ((rows[:, None] + cols[None, :]) % 2 * 255).astype(np.uint8)
# ========== 5. 可视化 ==========
fig, axes = plt.subplots(1, 4, figsize=(16, 4))
titles = ["全黑 5x5", "全白 5x5", "水平渐变 256x256", "棋盘格 256x256"]
images = [img_black, img_white, img_gradient, checkerboard]
for ax, img, title in zip(axes, images, titles):
ax.imshow(img, cmap="gray", vmin=0, vmax=255)
ax.set_title(title, fontsize=12)
ax.axis("off")
plt.suptitle("实验一:NumPy 创建灰度图像", fontsize=14)
plt.tight_layout()
plt.savefig("code/output/003_exp1_grayscale.png", dpi=150, bbox_inches="tight")
plt.show()
print("\n✅ 实验一完成,图像已保存至 code/output/003_exp1_grayscale.png")
6.2 实验二:创建 RGB 彩色图像
"""
实验二:用 NumPy 创建 RGB 彩色图像
理解:彩色图 = (H, W, 3) 三维数组,三个通道分别对应 R/G/B
"""
import numpy as np
import matplotlib.pyplot as plt
# ========== 1. 创建纯色图像(红色、绿色、蓝色) ==========
H, W = 256, 256
img_red = np.zeros((H, W, 3), dtype=np.uint8)
img_red[:, :, 0] = 255 # R=255, G=0, B=0
img_green = np.zeros((H, W, 3), dtype=np.uint8)
img_green[:, :, 1] = 255 # R=0, G=255, B=0
img_blue = np.zeros((H, W, 3), dtype=np.uint8)
img_blue[:, :, 2] = 255 # R=0, G=0, B=255
# ========== 2. 创建双色渐变图 ==========
img_gradient = np.zeros((H, W, 3), dtype=np.uint8)
img_gradient[:, :, 0] = np.linspace(0, 255, W, dtype=np.uint8) # R 左→右渐变
img_gradient[:, :, 2] = np.linspace(255, 0, W, dtype=np.uint8) # B 右→左渐变
# ========== 3. 创建三色拼接图 ==========
img_tri = np.zeros((H, W, 3), dtype=np.uint8)
img_tri[:, :W//3] = [255, 0, 0] # 左 1/3 红色
img_tri[:, W//3:2*W//3] = [0, 255, 0] # 中 1/3 绿色
img_tri[:, 2*W//3:] = [0, 0, 255] # 右 1/3 蓝色
# ========== 4. 可视化 ==========
fig, axes = plt.subplots(1, 5, figsize=(20, 4))
titles = ["纯红", "纯绿", "纯蓝", "红蓝渐变", "三色拼接"]
images = [img_red, img_green, img_blue, img_gradient, img_tri]
for ax, img, title in zip(axes, images, titles):
ax.imshow(img)
ax.set_title(title, fontsize=12)
ax.axis("off")
plt.suptitle("实验二:NumPy 创建 RGB 彩色图像", fontsize=14)
plt.tight_layout()
plt.savefig("code/output/003_exp2_rgb.png", dpi=150, bbox_inches="tight")
plt.show()
print("✅ 实验二完成,图像已保存至 code/output/003_exp2_rgb.png")
6.3 实验三:采样——空间分辨率对图像质量的影响
"""
实验三:模拟不同采样率对图像质量的影响
通过下采样+上采样模拟低分辨率效果
"""
import cv2
import numpy as np
import matplotlib.pyplot as plt
# ========== 1. 生成高分辨率测试图(含细节) ==========
H, W = 512, 512
# 创建包含线条和文字的合成图
img = np.zeros((H, W), dtype=np.uint8)
# 绘制同心圆
center = (W // 2, H // 2)
for r in range(20, 240, 20):
cv2.circle(img, center, r, 255, 1)
# 绘制网格线
for i in range(0, H, 32):
cv2.line(img, (0, i), (W, i), 128, 1)
cv2.line(img, (i, 0), (i, W), 128, 1)
# ========== 2. 不同采样率下采样后上采样回原尺寸 ==========
# 下采样因子分别为 2, 4, 8, 16
factors = [1, 2, 4, 8, 16]
fig, axes = plt.subplots(1, len(factors), figsize=(20, 4))
for ax, factor in zip(axes, factors):
# 下采样:每隔 factor 个像素取一个
downsampled = img[::factor, ::factor]
# 上采样:用最近邻插值还原到原始尺寸
upsampled = cv2.resize(downsampled, (W, H), interpolation=cv2.INTER_NEAREST)
h_down, w_down = downsampled.shape
title = f"原始 {H}x{W}" if factor == 1 else f"采样率 1/{factor}\n({w_down}x{h_down} → {W}x{H})"
ax.imshow(upsampled, cmap="gray", vmin=0, vmax=255)
ax.set_title(title, fontsize=10)
ax.axis("off")
plt.suptitle("实验三:采样率对图像质量的影响(混叠效应)", fontsize=14)
plt.tight_layout()
plt.savefig("code/output/003_exp3_sampling.png", dpi=150, bbox_inches="tight")
plt.show()
print("✅ 实验三完成,图像已保存至 code/output/003_exp3_sampling.png")
6.4 实验四:量化——位深对图像质量的影响
"""
实验四:模拟不同量化等级对图像质量的影响
将 256 级灰度压缩到更少的灰度等级
"""
import numpy as np
import matplotlib.pyplot as plt
# ========== 1. 创建渐变测试图 ==========
W = 256
gradient = np.linspace(0, 255, W, dtype=np.uint8)
img = np.tile(gradient, (W, 1)) # 256x256 水平渐变
# ========== 2. 不同量化等级 ==========
# 量化方法:img_quantized = (img // step) * step
bits_list = [8, 4, 3, 2, 1] # 对应 256, 16, 8, 4, 2 级
levels = [2 ** b for b in bits_list]
fig, axes = plt.subplots(1, len(bits_list), figsize=(20, 4))
for ax, bits, level in zip(axes, bits_list, levels):
if bits < 8:
step = 256 // level
img_q = (img // step) * step
img_q = np.clip(img_q, 0, 255).astype(np.uint8)
else:
img_q = img.copy()
ax.imshow(img_q, cmap="gray", vmin=0, vmax=255)
ax.set_title(f"{bits} bit / {level} 级", fontsize=12)
ax.axis("off")
plt.suptitle("实验四:量化等级对图像质量的影响(伪轮廓效应)", fontsize=14)
plt.tight_layout()
plt.savefig("code/output/003_exp4_quantization.png", dpi=150, bbox_inches="tight")
plt.show()
print("✅ 实验四完成,图像已保存至 code/output/003_exp4_quantization.png")
七、常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
imshow 显示彩色图偏蓝 | OpenCV 读取的是 BGR,matplotlib 需要 RGB | 使用 cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 转换 |
| 灰度图显示为偏色 | imshow 默认用彩色 colormap | 添加 cmap="gray", vmin=0, vmax=255 |
| NumPy 创建图像后保存为黑色 | dtype 不是 uint8 或值域超出 0-255 | 确保 dtype=np.uint8 且值在 0-255 |
| 渐变图有条纹 | 量化等级不足(< 8bit) | 使用至少 8bit(256级)存储 |
| 坐标系混乱 | 图像行列与 xy 坐标方向不同 | 记住 img[row=y, col=x],行向下,列向右 |
八、相关产品推荐
移动端 App
| 产品 | 平台 | 与本期内容的关联 | 适合场景 |
|---|---|---|---|
| Snapseed | iOS / Android | 内置"细节"面板可直观对比像素级放大效果,理解采样概念 | 日常照片编辑、像素级观察 |
| Lightroom Mobile | iOS / Android | 支持 RAW(16bit)拍摄,可对比 8bit vs 16bit 动态范围差异 | 移动端专业摄影后期 |
| VSCO | iOS / Android | 胶片滤镜基于 LUT(查找表),本质上是对像素值的量化映射 | 风格化调色 |
专业级工具
| 产品 | 平台 | 与本期内容的关联 | 适合场景 |
|---|---|---|---|
| Adobe Photoshop | Win / macOS | 支持切换 8/16/32bit 模式,直方图面板实时显示像素分布 | 专业图像编辑 |
| Affinity Photo | Win / macOS / iPad | 一次性买断,支持 16bit/32bit HDR 工作流 | 专业级 Photoshop 替代 |
| ImageJ | Win / macOS / Linux | 开源科研工具,可逐像素查看矩阵值,支持 16bit/浮点图像 | 科研图像分析、像素级研究 |
九、扩展练习
- 矩阵操作练习:用 NumPy 创建一张 512×512 的灰度图,在中心画一个直径 200 的白色实心圆,四周为黑色。提示:用
np.meshgrid生成坐标,计算距离判断。 - 量化对比:读取一张真实照片,分别量化为 8bit/6bit/4bit/2bit,计算每次量化后的 MSE(均方误差),绘制"量化位数 vs MSE"曲线。
- 通道分离:用 NumPy 切片操作分离一张 RGB 图像的三个通道,分别显示为红色、绿色、蓝色的单通道图(其他通道设为0),并拼接为一行展示。
十、知识总结
| 概念 | 核心要点 | 一句话记忆 |
|---|---|---|
| 采样 | 空间离散化,决定图像尺寸 | 格子越密越清晰 |
| 量化 | 灰度离散化,决定色彩精度 | 等级越多越平滑 |
| 编码 | 二进制存储,决定文件大小 | 位深×通道×像素 = 文件大小 |
| 像素 | 图像最小单元 | 矩阵的一个元素 |
| 分辨率 | 空间分辨率(PPI) vs 灰度分辨率(级数) | PPI 管清晰,位深管过渡 |
| 矩阵 | 图像 = 多维数组 | 灰度(H,W) 彩色(H,W,3) |
十一、下节预告
第004期:图像文件格式深度解析:JPEG/PNG/TIFF/BMP,将拆解四种常见格式的压缩原理、适用场景与文件结构,并用代码实测各格式的文件大小与质量差异。
本期核心结论:数字图像在计算机中就是 NumPy 数组。灰度图是 (H, W) 的二维矩阵,彩色图是 (H, W, 3) 的三维张量。所有图像处理算法,本质上都是矩阵运算。建立这个认知,后续学习事半功倍。
觉得有用的话,点赞收藏不迷路,我们下期见!

372

被折叠的 条评论
为什么被折叠?



