首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >《数字图像处理》第 2 章 - 数字图像基础

《数字图像处理》第 2 章 - 数字图像基础

作者头像
啊阿狸不会拉杆
发布2026-01-21 14:29:10
发布2026-01-21 14:29:10
1220
举报

前言

        大家好!今天给大家梳理《数字图像处理》第 2 章的核心内容 —— 数字图像基础。这一章是整个数字图像处理的入门基石,涵盖了从视觉感知到图像数字化、像素关系、数学工具等核心知识点。全文搭配可直接运行的 Python 代码效果对比图和详细注释,帮大家直观理解抽象概念,新手也能轻松上手!

2.1 视觉感知要素

2.1.1 人眼的结构

        人眼是图像感知的核心器官,核心结构包括:角膜→虹膜→瞳孔→晶状体→视网膜(含视锥 / 视杆细胞)。

  • 视锥细胞:约 600-700 万个,集中在黄斑区,负责彩色视觉和高分辨率细节感知;
  • 视杆细胞:约 1 亿个,分布在视网膜周边,负责低光照下的暗视觉(无色彩感知)。
2.1.2 人眼的成像原理

        人眼类似凸透镜成像系统:光线经晶状体聚焦后,在视网膜上形成倒立的实像,视网膜上的感光细胞将光信号转化为神经电信号,经视神经传递到大脑视觉皮层,大脑最终将倒立的像 “矫正” 为正立的视觉感知。

2.1.3 亮度适应与亮度分辨力
  • 亮度适应:人眼能适应的亮度范围约从10−6 cd/m²(暗视觉)到106 cd/m²(亮视觉),但不能同时适应整个范围,只能在某一 “亮度级” 下分辨细节;
  • 亮度分辨力:人眼对亮度变化的分辨能力有限,通常在相同亮度背景下,能分辨的最小亮度差约为背景亮度的 1%-2%。

代码案例:模拟人眼亮度分辨力(亮度差感知)

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plt
# 设置matplotlib支持中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']  # 黑体
plt.rcParams['axes.unicode_minus'] = False    # 解决负号显示问题

# 生成背景亮度为100的图像,中间添加不同亮度差的矩形块
def simulate_brightness_resolution():
    # 构建500x500的背景图像,亮度值100(灰度范围0-255)
    background = np.ones((500, 500)) * 100
    # 定义不同的亮度差(1%、2%、5%、10%)
    diffs = [1, 2, 5, 10]  # 对应100的1%、2%、5%、10%
    colors = ['r', 'g', 'b', 'y']
    labels = ['1%亮度差', '2%亮度差', '5%亮度差', '10%亮度差']
    
    fig, ax = plt.subplots(1, 1, figsize=(8, 8))
    ax.imshow(background, cmap='gray', vmin=0, vmax=255)
    ax.axis('off')
    
    # 在图像中绘制不同亮度差的矩形
    y_start = 100
    for i, diff in enumerate(diffs):
        # 计算矩形的亮度值
        rect_brightness = 100 + diff
        # 绘制矩形:x范围200-300,y范围按顺序排列
        rect = np.ones((80, 100)) * rect_brightness
        background[y_start+i*80 : y_start+(i+1)*80, 200:300] = rect
    
    ax.imshow(background, cmap='gray', vmin=0, vmax=255)
    # 添加图例
    for i, label in enumerate(labels):
        ax.text(310, y_start+i*80+40, label, color=colors[i], fontsize=12)
    
    plt.title('人眼亮度分辨力模拟(背景亮度100)', fontsize=14)
    plt.show()

# 运行函数
simulate_brightness_resolution()

        效果说明:运行后能看到,1% 亮度差的矩形几乎和背景融为一体(人眼难以分辨),2% 开始隐约可见,5% 以上清晰可辨,直观体现人眼的亮度分辨特性。

2.2 光与电磁波谱

 图像的本质是光的分布,可见光只是电磁波谱中很小的一段(波长 400nm-700nm):

  • 波长 < 400nm:紫外线、X 射线、γ 射线;
  • 波长 > 700nm:红外线、微波、无线电波;
  • 数字图像处理主要关注可见光(成像)和近红外线(遥感、夜视等)。

        公式(光的波长与频率关系):c=λ×f

        其中:c为光速(3×108 m/s),λ为波长,f为频率。

2.3 图像传感与采集

        图像采集的核心是将光信号转化为电信号,再转化为数字信号。常见的传感器类型如下:

2.3.1 单传感器图像采集

        单个光敏传感器,通过机械扫描(如旋转 / 平移)逐点采集图像,优点是精度高,缺点是速度慢(如早期传真机、高精度光谱仪)。

2.3.2 线阵传感器图像采集

        由一行传感器组成,通过物体 / 传感器移动实现二维图像采集(如扫描仪、工业检测线扫相机),适合长条状物体成像(如纸张、布匹)。

2.3.3 面阵传感器图像采集

        由二维阵列的传感器组成(如 CCD/CMOS),直接一次性采集二维图像,速度快、操作简单,是目前数码相机、手机摄像头的主流方案。

2.3.4 简易图像形成模型

        数字图像可简化为光照(i)和反射(r)的乘积:

代码案例:模拟图像形成模型(光照 × 反射)

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 生成光照图(中心亮、边缘暗)
x, y = np.meshgrid(np.linspace(-1, 1, 500), np.linspace(-1, 1, 500))
i = np.exp(-(x**2 + y**2)/0.5)  # 高斯分布光照
i = i / i.max()  # 归一化到0-1

# 生成反射图(矩形区域反射率高,其余低)
r = np.ones((500, 500)) * 0.2  # 背景反射率0.2
r[150:350, 150:350] = 0.8     # 中心矩形反射率0.8

# 生成最终图像
f = i * r

# 绘制对比图
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
axes[0].imshow(i, cmap='gray', vmin=0, vmax=1)
axes[0].set_title('光照分量 i(x,y)', fontsize=12)
axes[0].axis('off')

axes[1].imshow(r, cmap='gray', vmin=0, vmax=1)
axes[1].set_title('反射分量 r(x,y)', fontsize=12)
axes[1].axis('off')

axes[2].imshow(f, cmap='gray', vmin=0, vmax=1)
axes[2].set_title('最终图像 f(x,y)=i×r', fontsize=12)
axes[2].axis('off')

plt.tight_layout()
plt.show()

2.4 图像采样与量化

2.4.1 采样与量化的基本概念
  • 采样:将连续的空间坐标(x,y)离散化,即 “取点”,采样间隔决定空间分辨率;
  • 量化:将连续的亮度值离散化,即 “取级”,量化级数决定灰度分辨率。
2.4.2 数字图像的表示方法

采样和量化后的数字图像是二维矩阵:

2.4.3 空间分辨率与灰度分辨率
  • 空间分辨率:单位长度内的像素数(如dpi、像素/厘米),分辨率越低,图像越模糊;
  • 灰度分辨率:灰度级的数量(如8位灰度图=256级),分辨率越低,图像“层次感”越差。

代码案例:空间分辨率+灰度分辨率对比

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg  # 用于加载本地图像
import os  # 用于检查文件是否存在

# 设置matplotlib支持中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# ===================== 加载本地图像 =====================
image_path = "../picture/CSGO.jpg"

# 检查文件是否存在
if not os.path.exists(image_path):
    raise FileNotFoundError(f"未找到图像文件:{image_path}\n请检查路径是否正确!")

# 加载图像并转换为灰度图(兼容彩色/灰度图像)
img = mpimg.imread(image_path)
# 如果是彩色图像(3通道),转换为灰度图;如果已是灰度图则直接使用
if len(img.shape) == 3:
    # 按RGB权重转换为灰度:Y = 0.2989R + 0.5870G + 0.1140B
    img = np.dot(img[..., :3], [0.2989, 0.5870, 0.1140]).astype(np.uint8)
# 确保图像是8位灰度图(0-255)
img = img.astype(np.uint8)

# 打印图像基本信息,方便调试
print(f"图像尺寸:{img.shape}")
print(f"图像数据类型:{img.dtype}")
print(f"灰度值范围:{img.min()} ~ {img.max()}")

# ===================== 原有逻辑(保留不变) =====================
# 1. 空间分辨率对比(下采样)
# 动态计算下采样间隔,适配不同尺寸的图像(避免采样后尺寸过小/过大)
# 目标采样后尺寸约为原尺寸的1/16(32x32对应512x512)和1/4(128x128对应512x512)
h, w = img.shape
step_32 = max(1, h // 32)  # 确保步长至少为1
step_128 = max(1, h // 128)

img_32 = img[::step_32, ::step_32]    # 低分辨率(约32x32)
img_128 = img[::step_128, ::step_128]  # 中分辨率(约128x128)

# 2. 灰度分辨率对比(量化)
def quantize(img, levels):
    """量化图像到指定灰度级"""
    if levels == 1:  # 避免除以0
        return np.zeros_like(img)
    img_normalized = img / 255.0  # 归一化到0-1
    img_quantized = np.floor(img_normalized * (levels - 1)) / (levels - 1)
    return (img_quantized * 255).astype(np.uint8)

img_2level = quantize(img, 2)    # 2级灰度
img_16level = quantize(img, 16)  # 16级灰度

# ===================== 绘制对比图(适配新图像尺寸) =====================
fig, axes = plt.subplots(2, 2, figsize=(12, 10))

# 空间分辨率
axes[0,0].imshow(img, cmap='gray')
axes[0,0].set_title(f'原始图像({h}x{w})', fontsize=12)
axes[0,0].axis('off')

axes[0,1].imshow(img_32, cmap='gray')
axes[0,1].set_title(f'空间分辨率降低({img_32.shape[0]}x{img_32.shape[1]})', fontsize=12)
axes[0,1].axis('off')

# 灰度分辨率
axes[1,0].imshow(img_16level, cmap='gray')
axes[1,0].set_title('灰度分辨率16级', fontsize=12)
axes[1,0].axis('off')

axes[1,1].imshow(img_2level, cmap='gray')
axes[1,1].set_title('灰度分辨率2级', fontsize=12)
axes[1,1].axis('off')

plt.tight_layout()
plt.show()
2.4.4 图像插值

        插值是提升图像空间分辨率的常用方法(补全像素),常见方法:最近邻插值、双线性插值、双三次插值。

代码案例:不同插值方法效果对比

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg  # 加载本地图像
import os  # 检查文件是否存在
from scipy.ndimage import zoom

# 设置matplotlib支持中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# ===================== 加载自定义本地图像 =====================
# 请替换为你的本地图像路径(支持jpg/png/bmp等格式)
image_path = "../picture/TianHuoSanXuanBian.jpg"

# 检查文件是否存在
if not os.path.exists(image_path):
    raise FileNotFoundError(f"未找到图像文件:{image_path}\n请检查路径是否正确!")

# 加载图像
img = mpimg.imread(image_path)

# 彩色图像转灰度图(兼容彩色/灰度图像)
if len(img.shape) == 3:
    # 标准RGB转灰度公式:Y = 0.2989R + 0.5870G + 0.1140B
    img = np.dot(img[..., :3], [0.2989, 0.5870, 0.1140]).astype(np.uint8)
# 确保图像为8位灰度图
img = img.astype(np.uint8)

# 打印图像基本信息,方便调试
h, w = img.shape
print(f"原始图像尺寸:{h}x{w}")
print(f"图像数据类型:{img.dtype}")

# ===================== 动态下采样(降低分辨率) =====================
# 动态计算下采样步长,使低分辨率图像约为64x64(适配不同尺寸图像)
step_h = max(1, h // 64)
step_w = max(1, w // 64)
img_low = img[::step_h, ::step_w]  # 下采样到约64x64
low_h, low_w = img_low.shape
print(f"下采样后低分辨率图像尺寸:{low_h}x{low_w}")

# ===================== 不同插值方法放大(放大倍数适配低分辨率尺寸) =====================
# 计算放大倍数,使放大后图像接近原图像尺寸(或固定放大4倍)
scale_h = h / low_h  # 按高度放大
scale_w = w / low_w  # 按宽度放大
# 也可固定放大4倍:scale_h = scale_w = 4

# 1. 最近邻插值(order=0):速度快,块效应明显
img_nn = zoom(img_low, (scale_h, scale_w), order=0)
# 2. 双线性插值(order=1):平滑,细节损失
img_bl = zoom(img_low, (scale_h, scale_w), order=1)
# 3. 双三次插值(order=3):效果最好,细节保留完整
img_bc = zoom(img_low, (scale_h, scale_w), order=3)

# 裁剪到原图像尺寸(避免插值后尺寸微小偏差)
img_nn = img_nn[:h, :w]
img_bl = img_bl[:h, :w]
img_bc = img_bc[:h, :w]

# ===================== 绘制插值效果对比图 =====================
fig, axes = plt.subplots(2, 2, figsize=(12, 10))

# 低分辨率原图
axes[0,0].imshow(img_low, cmap='gray')
axes[0,0].set_title(f'低分辨率图像({low_h}x{low_w})', fontsize=12)
axes[0,0].axis('off')

# 最近邻插值
axes[0,1].imshow(img_nn, cmap='gray')
axes[0,1].set_title('最近邻插值', fontsize=12)
axes[0,1].axis('off')

# 双线性插值
axes[1,0].imshow(img_bl, cmap='gray')
axes[1,0].set_title('双线性插值', fontsize=12)
axes[1,0].axis('off')

# 双三次插值
axes[1,1].imshow(img_bc, cmap='gray')
axes[1,1].set_title('双三次插值', fontsize=12)
axes[1,1].axis('off')

plt.tight_layout()
plt.show()

        效果说明:最近邻插值最模糊(有明显块效应),双线性插值更平滑,双三次插值效果最好(细节保留最完整)。

2.5 像素间的基本关系

2.5.1 像素的邻域

像素(x,y)的邻域是围绕它的像素集合,常见类型:

  • 4邻域(N4):上下左右4个像素,即(x±1,y)、(x,y±1);
  • 8邻域(N8):4邻域+对角线4个像素,共8个;
  • D邻域:仅对角线4个像素。
2.5.2 邻接性、连通性、区域与边界
  • 邻接性:两个像素满足位置邻域+灰度相似(如同一灰度级);
  • 连通性:从像素A到B存在一条邻接像素的路径;
  • 区域:连通的像素集合;
  • 边界:区域内与背景邻接的像素。
2.5.3 距离度量

常用的像素距离:

  1. 欧氏距离(Euclidean)
  2. 曼哈顿距离(城市街区距离)
  3. 切比雪夫距离(棋盘距离)

代码案例:像素距离计算与可视化

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 定义中心像素(5,5),计算不同距离的像素
center = (5,5)
x, y = np.meshgrid(np.arange(0,11), np.arange(0,11))
# 初始化距离矩阵
d_euclidean = np.sqrt((x-center[0])**2 + (y-center[1])**2)
d_manhattan = np.abs(x-center[0]) + np.abs(y-center[1])
d_chessboard = np.maximum(np.abs(x-center[0]), np.abs(y-center[1]))

# 绘制距离可视化
fig, axes = plt.subplots(1, 3, figsize=(15, 5))

# 欧氏距离
im1 = axes[0].imshow(d_euclidean, cmap='viridis')
axes[0].scatter(center[0], center[1], color='red', s=100, label='中心像素')
axes[0].set_title('欧氏距离', fontsize=12)
axes[0].axis('off')
plt.colorbar(im1, ax=axes[0], shrink=0.8)

# 曼哈顿距离
im2 = axes[1].imshow(d_manhattan, cmap='viridis')
axes[1].scatter(center[0], center[1], color='red', s=100)
axes[1].set_title('曼哈顿距离', fontsize=12)
axes[1].axis('off')
plt.colorbar(im2, ax=axes[1], shrink=0.8)

# 棋盘距离
im3 = axes[2].imshow(d_chessboard, cmap='viridis')
axes[2].scatter(center[0], center[1], color='red', s=100)
axes[2].set_title('切比雪夫距离', fontsize=12)
axes[2].axis('off')
plt.colorbar(im3, ax=axes[2], shrink=0.8)

plt.tight_layout()
plt.show()

2.6 数字图像处理常用数学工具简介

2.6.1 数组运算与矩阵运算的区别
  • 数组运算(逐元素运算):对应位置元素直接运算(如NumPy数组),如A+B表示每个元素相加;
  • 矩阵运算(线性代数运算):遵循矩阵乘法规则(行×列),如A×B需要满足列数=行数。
2.6.2 线性运算与非线性运算
  • 线性运算:满足可加性+齐次性,如f(ax+by)=af(x)+bf(y)(如滤波、变换);
  • 非线性运算:不满足线性规则,如取绝对值、指数、对数、阈值分割。
2.6.3 算术运算

        图像算术运算:加(去噪)、减(背景差分)、乘(掩膜)、除(归一化)。

2.6.4 集合运算与逻辑运算
  • 集合运算:并、交、补(用于图像区域处理);
  • 逻辑运算:与、或、非、异或(用于二值图像处理)。
2.6.5 空间域运算

直接对像素灰度值进行运算,如:

        g(x,y)=T[f(x,y)]

其中T为变换函数(如灰度调整、滤波)。

2.6.6 向量与矩阵运算

        图像可视为向量/矩阵,常用运算:转置、逆、特征值分解、奇异值分解(SVD)。

2.6.7 图像变换

        将图像从空间域转换到变换域(如傅里叶变换、离散余弦变换、小波变换),便于频域分析、压缩、滤波。

2.6.8 概率统计方法

        用统计特征描述图像:均值(亮度)、方差(对比度)、直方图(灰度分布)、协方差(相关性)。

代码案例:图像数学运算综合演示

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plt
from skimage import data

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 加载两张灰度图
img1 = data.camera()
img2 = data.coins()
# 统一尺寸(取最小尺寸)
h, w = min(img1.shape[0], img2.shape[0]), min(img1.shape[1], img2.shape[1])
img1 = img1[:h, :w]
img2 = img2[:h, :w]

# 1. 算术运算(加、减)
img_add = np.clip((img1 + img2) / 2, 0, 255).astype(np.uint8)  # 相加后归一化
img_sub = np.clip(img1 - img2 + 128, 0, 255).astype(np.uint8)  # 相减后偏移

# 2. 逻辑运算(二值化后)
img1_bin = (img1 > 128).astype(np.uint8) * 255
img2_bin = (img2 > 128).astype(np.uint8) * 255
img_and = np.bitwise_and(img1_bin, img2_bin)
img_or = np.bitwise_or(img1_bin, img2_bin)

# 3. 空间域运算(灰度调整)
img_bright = np.clip(img1 * 1.5, 0, 255).astype(np.uint8)  # 增亮
img_contrast = np.clip((img1 - 128) * 2 + 128, 0, 255).astype(np.uint8)  # 增强对比度

# 4. 统计特征计算
mean = np.mean(img1)
var = np.var(img1)
hist, bins = np.histogram(img1, bins=256, range=(0,255))

# 绘制结果
fig, axes = plt.subplots(3, 2, figsize=(12, 15))

# 算术运算
axes[0,0].imshow(img_add, cmap='gray')
axes[0,0].set_title(f'算术运算:相加', fontsize=12)
axes[0,0].axis('off')

axes[0,1].imshow(img_sub, cmap='gray')
axes[0,1].set_title(f'算术运算:相减', fontsize=12)
axes[0,1].axis('off')

# 逻辑运算
axes[1,0].imshow(img_and, cmap='gray')
axes[1,0].set_title(f'逻辑运算:与', fontsize=12)
axes[1,0].axis('off')

axes[1,1].imshow(img_or, cmap='gray')
axes[1,1].set_title(f'逻辑运算:或', fontsize=12)
axes[1,1].axis('off')

# 空间域+统计
axes[2,0].imshow(img_contrast, cmap='gray')
axes[2,0].set_title(f'空间域:对比度增强(均值={mean:.2f},方差={var:.2f})', fontsize=10)
axes[2,0].axis('off')

axes[2,1].plot(hist)
axes[2,1].set_title('灰度直方图', fontsize=12)
axes[2,1].set_xlabel('灰度值')
axes[2,1].set_ylabel('像素数')

plt.tight_layout()
plt.show()

小结

总结
  1. 数字图像基础的核心是“从光到数字”的转化:人眼感知光→传感器采集光信号→采样/量化转化为数字图像;
  2. 像素是数字图像的基本单元,其邻域、连通性、距离度量是图像处理的基础,而数组/矩阵运算、算术/逻辑运算等是核心工具;
  3. 分辨率(空间+灰度)直接决定图像质量,插值是提升空间分辨率的常用方法,不同插值方法各有优劣(双三次插值效果最佳)。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-01-17,如有侵权请联系 [email protected] 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 [email protected] 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 2.1 视觉感知要素
    • 2.1.1 人眼的结构
    • 2.1.2 人眼的成像原理
    • 2.1.3 亮度适应与亮度分辨力
  • 2.2 光与电磁波谱
  • 2.3 图像传感与采集
    • 2.3.1 单传感器图像采集
    • 2.3.2 线阵传感器图像采集
    • 2.3.3 面阵传感器图像采集
    • 2.3.4 简易图像形成模型
  • 2.4 图像采样与量化
    • 2.4.1 采样与量化的基本概念
    • 2.4.2 数字图像的表示方法
    • 2.4.3 空间分辨率与灰度分辨率
    • 2.4.4 图像插值
  • 2.5 像素间的基本关系
    • 2.5.1 像素的邻域
    • 2.5.2 邻接性、连通性、区域与边界
    • 2.5.3 距离度量
  • 2.6 数字图像处理常用数学工具简介
    • 2.6.1 数组运算与矩阵运算的区别
    • 2.6.2 线性运算与非线性运算
    • 2.6.3 算术运算
    • 2.6.4 集合运算与逻辑运算
    • 2.6.5 空间域运算
    • 2.6.6 向量与矩阵运算
    • 2.6.7 图像变换
    • 2.6.8 概率统计方法
  • 小结
    • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档