# 第 1 章 引言 (Introduction)

## 📌 本章知识点概览

1. 什么是数字图像处理
2. 数字图像处理的起源与发展
3. 典型应用领域
4. 图像处理系统的基本组成
5. 本书的知识框架

---

## 1.1 什么是数字图像处理？

### 📖 核心概念

**图像 (Image)**：对人类视觉感知的二维表示，包含亮度和颜色信息。

**数字图像 (Digital Image)**：将连续图像离散化为有限个像素点的二维数组，每个像素有特定的灰度值或颜色值。

**数字图像处理 (Digital Image Processing)**：
> 使用计算机算法对数字图像进行分析、操作和处理，以改善图像质量、提取有用信息或为后续任务做准备。

### 🎯 为什么要处理图像？

| 目的 | 说明 | 例子 |
|------|------|------|
| **改善视觉效果** | 让人眼更容易观察 | 增强对比度、去噪、锐化 |
| **提取信息** | 为机器分析做准备 | 边缘检测、特征提取 |
| **压缩存储** | 减少数据量 | JPEG 压缩 |
| **自动识别** | 模式识别基础 | 人脸识别、字符识别 |

---

## 1.2 数字图像处理的起源与发展

### 📜 发展历程

| 年代 | 里程碑事件 |
|------|------------|
| 1920s | 巴特兰电缆传输第一张数字照片（报纸行业） |
| 1960s | 喷气推进实验室处理月球照片（计算机处理开端） |
| 1970s | CT 扫描发明（医学图像处理革命） |
| 1980s | 个人计算机普及，图像处理工具出现 |
| 1990s | JPEG/MPEG 标准确立，互联网图像传输 |
| 2000s | 数码相机普及，消费级应用爆发 |
| 2010s | 深度学习崛起，CNN 在图像识别中取得突破 |
| 2020s | 生成式 AI（GAN、Diffusion）改变图像生成 |

### 💡 关键洞察

数字图像处理的发展始终由**硬件进步**和**应用需求**双轮驱动：
- 硬件：计算能力提升 → 能处理更复杂的算法
- 需求：从科研→医疗→消费→工业，应用场景不断扩展

---

## 1.3 典型应用领域

### 🏥 医学成像
- **X 射线成像**：肺部检查、骨折检测
- **CT（计算机断层扫描）**：三维重建内部器官
- **MRI（磁共振成像）**：软组织高分辨率成像
- **PET（正电子发射断层扫描）**：功能成像，癌症检测
- **应用**：病灶检测、手术规划、疾病诊断

### 🛰️ 遥感与地理信息
- **卫星图像分析**：土地利用分类、农作物监测
- **气象预报**：云图分析、台风追踪
- **环境监测**：森林覆盖变化、水体污染检测
- **灾害评估**：洪水、地震灾后评估

### 🏭 工业检测
- **产品质量检测**：表面缺陷识别
- **自动分拣**：基于颜色、形状分类
- **尺寸测量**：非接触式精密测量
- **机器人视觉**：引导机械臂定位抓取

### 🚔 安防与监控
- **人脸识别**：门禁系统、身份验证
- **行为分析**：异常行为检测
- **车牌识别**：停车场管理、交通违章
- **视频摘要**：从长时间监控中提取关键事件

### 🎨 多媒体与娱乐
- **图像编辑**：Photoshop 等工具
- **电影特效**：绿幕抠图、CGI 合成
- **游戏开发**：纹理映射、光照渲染
- **虚拟现实**：360°全景图像处理

### 📱 消费级应用
- **手机摄影**：HDR、夜景模式、人像虚化
- **社交媒体**：滤镜、美颜
- **文档扫描**：透视矫正、文字增强
- **AR 应用**：实时图像叠加

---

## 1.4 图像处理系统的基本组成

### 🔧 系统架构

```
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  图像获取   │ ──→ │  图像处理   │ ──→ │  输出/显示  │
│  (采集)     │     │  (算法)     │     │  (结果)     │
└─────────────┘     └─────────────┘     └─────────────┘
       ↑                   ↑                   ↑
   传感器              计算机              显示器/
   摄像头              算法库              打印机/
   扫描仪              存储                网络传输
```

### 📦 核心组件

#### 1. 图像获取子系统
| 组件 | 功能 | 例子 |
|------|------|------|
| **传感器** | 将光信号转换为电信号 | CCD、CMOS |
| **采样** | 空间离散化 | 决定图像分辨率 |
| **量化** | 灰度/颜色离散化 | 8 位 (256 级)、16 位 |
| **数字化** | 模数转换 (ADC) | 生成数字矩阵 |

#### 2. 处理子系统
- **硬件**：CPU、GPU、专用图像处理芯片
- **软件**：OpenCV、MATLAB、scikit-image
- **算法**：滤波、变换、分割、识别

#### 3. 存储与传输
- **存储格式**：BMP（无压缩）、JPEG（有损）、PNG（无损）
- **传输协议**：HTTP、RTSP（视频流）

#### 4. 显示与输出
- **显示器**：LCD、OLED
- **打印**：喷墨、激光
- **网络传输**：社交媒体、云存储

---

## 1.5 数字图像处理的知识框架

### 📚 本书结构概览

```
数字图像处理
├── 基础篇
│   ├── 第 2 章：数字图像基础（采样、量化、像素关系）
│   └── 第 3 章：灰度变换与空间滤波
│
├── 频域篇
│   └── 第 4 章：频率域滤波（傅里叶变换）
│
├── 增强与复原篇
│   ├── 第 5 章：图像复原与重建
│   └── 第 6 章：彩色图像处理
│
├── 压缩与变换篇
│   ├── 第 7 章：小波和多分辨率处理
│   └── 第 8 章：图像压缩
│
├── 分割与描述篇
│   ├── 第 9 章：形态学图像处理
│   ├── 第 10 章：图像分割
│   └── 第 11 章：表示与描述
│
└── 识别篇
    └── 第 12 章：目标识别
```

### 🎓 学习路径建议

```
入门（1-2 周）
  ↓
第 1-2 章：理解什么是数字图像、如何表示
  ↓
基础技能（2-3 周）
  ↓
第 3 章：学会基本的图像增强操作
  ↓
进阶（3-4 周）
  ↓
第 4-6 章：频域分析、复原、彩色处理
  ↓
高级应用（4-6 周）
  ↓
第 7-12 章：压缩、分割、识别
  ↓
实战项目
  ↓
综合运用所学知识完成实际项目
```

---

## 💻 第 1 章实践任务

### 任务 1：环境搭建
```bash
# 安装 Python 图像处理库
pip install opencv-python
pip install scikit-image
pip install pillow
pip install matplotlib
pip install numpy
```

### 任务 2：Hello World 图像程序
```python
import cv2
import matplotlib.pyplot as plt

# 读取图像
img = cv2.imread('test.jpg')

# 转换为 RGB（OpenCV 默认 BGR）
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 显示图像
plt.imshow(img_rgb)
plt.axis('off')
plt.title('My First Image')
plt.show()

# 保存图像
cv2.imwrite('output.jpg', img)
```

### 任务 3：查看图像基本信息
```python
import cv2

img = cv2.imread('test.jpg')
print(f"图像尺寸：{img.shape}")  # (高，宽，通道数)
print(f"数据类型：{img.dtype}")  # uint8
print(f"像素总数：{img.size}")
```

---

## 📝 本章小结

### ✅ 你应该掌握
- [ ] 理解什么是数字图像和数字图像处理
- [ ] 了解数字图像处理的主要应用领域
- [ ] 知道图像处理系统的基本组成
- [ ] 理解本书的知识框架和学习路径
- [ ] 完成环境搭建和第一个图像程序

### 🤔 思考题
1. 数字图像处理与计算机视觉有什么区别？
2. 为什么医学成像对图像处理技术要求最高？
3. 手机拍照中的"夜景模式"用到了哪些图像处理技术？

### 📖 延伸阅读
- 维基百科：Digital image processing
- OpenCV 官方教程：https://docs.opencv.org/
- scikit-image 示例库：https://scikit-image.org/docs/stable/auto_examples/

---

_第 1 章完 | 下一章：第 2 章 数字图像基础_
# 第 2 章 数字图像基础 (Digital Image Fundamentals)

## 📌 本章知识点概览

1. 视觉感知基础
2. 光和电磁波谱
3. 图像感知与获取
4. **采样与量化**（核心重点 ⭐）
5. 像素间的基本关系
6. 线性与非线性操作

---

## 2.1 视觉感知基础

### 👁️ 人眼结构

```
光线 → 角膜 → 瞳孔 → 晶状体 → 视网膜 → 视神经 → 大脑
              ↓
          虹膜控制进光量
```

**关键结构：**
- **角膜**：透明外层，初步聚焦
- **晶状体**：可变焦，精细调节
- **视网膜**：感光细胞分布层
  - **锥状细胞**：600-700 万，负责彩色视觉（明亮环境）
  - **杆状细胞**：7500-1.5 亿，负责灰度视觉（暗环境）

### 🎨 颜色视觉原理

**三原色理论**：人眼有三种锥状细胞，分别对红 (R)、绿 (G)、蓝 (B) 敏感

```
红光 (564-580nm) → L 型锥细胞
绿光 (534-545nm) → M 型锥细胞  
蓝光 (420-440nm) → S 型锥细胞
```

**颜色混合**：所有颜色 = R + G + B 的不同强度组合

---

## 2.2 光和电磁波谱

### 🌈 电磁波谱

```
γ射线 → X 射线 → 紫外线 → 可见光 → 红外线 → 微波 → 无线电波
         (短波长)                      (长波长)
```

**可见光范围**：380nm - 780nm

| 颜色 | 波长范围 (nm) |
|------|---------------|
| 紫色 | 380-450 |
| 蓝色 | 450-495 |
| 绿色 | 495-570 |
| 黄色 | 570-590 |
| 橙色 | 590-620 |
| 红色 | 620-780 |

### 💡 核心公式

**波长 - 频率关系**：
```
c = λ × f
```
- c = 光速 (3×10⁸ m/s)
- λ = 波长 (m)
- f = 频率 (Hz)

**光子能量**：
```
E = h × f = h × c / λ
```
- h = 普朗克常数 (6.626×10⁻³⁴ J·s)
- 波长越短 → 频率越高 → 能量越大

---

## 2.3 图像感知与获取

### 📷 图像获取过程

```
三维场景 → 光学成像 → 传感器 → 电信号 → 数字化 → 数字图像
```

### 🔍 传感器类型

| 传感器 | 原理 | 应用 |
|--------|------|------|
| **CCD** | 电荷耦合器件，高质量 | 专业相机、天文摄影 |
| **CMOS** | 互补金属氧化物，低功耗 | 手机、消费级相机 |
| **红外传感器** | 检测热辐射 | 夜视、温度测量 |
| **X 射线传感器** | 检测 X 射线穿透 | 医疗、安检 |

---

## 2.4 采样与量化 ⭐⭐⭐（核心重点）

### 📐 采样 (Sampling)

**定义**：将连续图像在**空间上离散化**，决定图像的**分辨率**。

```
连续图像 → 采样网格 → 离散像素点
```

**采样定理（奈奎斯特）**：
> 采样频率必须大于信号最高频率的**2 倍**，才能无失真地恢复原信号。

**欠采样后果**：出现**混叠 (Aliasing)** 现象
- 表现为：锯齿边缘、摩尔纹
- 解决：采样前进行低通滤波（抗混叠滤波）

### 🎚️ 量化 (Quantization)

**定义**：将每个像素的**灰度值离散化**，决定图像的**灰度级数**。

**量化级别**：
- **1 位**：2 级（黑白二值图像）
- **8 位**：256 级（标准灰度图像）⭐ 最常用
- **16 位**：65536 级（医学图像、高动态范围）
- **24 位**：真彩色（RGB 各 8 位）

### 📊 采样与量化的关系

```
图像质量 = f(采样密度，量化级数)
```

| 采样 | 量化 | 效果 |
|------|------|------|
| 高 | 高 | 高质量，大文件 |
| 高 | 低 | 细节多但有伪轮廓 |
| 低 | 高 | 马赛克但灰度平滑 |
| 低 | 低 | 质量差，文件小 |

### 💻 代码实践：采样与量化

```python
import cv2
import numpy as np
import matplotlib.pyplot as plt

# 读取图像
img = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE)

# 1. 降低采样（空间分辨率）
def reduce_sampling(img, factor):
    h, w = img.shape
    # 缩小
    small = cv2.resize(img, (w//factor, h//factor), interpolation=cv2.INTER_AREA)
    # 放大回原尺寸
    large = cv2.resize(small, (w, h), interpolation=cv2.INTER_NEAREST)
    return large

# 2. 降低量化（灰度级数）
def reduce_quantization(img, levels):
    # 量化公式：new_value = round(old_value / (256/levels)) * (256/levels)
    factor = 256 // levels
    return (img // factor) * factor

# 对比效果
fig, axes = plt.subplots(2, 3, figsize=(15, 10))

axes[0, 0].imshow(img, cmap='gray')
axes[0, 0].set_title('原始图像')

axes[0, 1].imshow(reduce_sampling(img, 4), cmap='gray')
axes[0, 1].set_title('采样降低 4 倍')

axes[0, 2].imshow(reduce_sampling(img, 8), cmap='gray')
axes[0, 2].set_title('采样降低 8 倍')

axes[1, 0].imshow(img, cmap='gray')
axes[1, 0].set_title('原始图像')

axes[1, 1].imshow(reduce_quantization(img, 16), cmap='gray', vmin=0, vmax=255)
axes[1, 1].set_title('量化到 16 级')

axes[1, 2].imshow(reduce_quantization(img, 4), cmap='gray', vmin=0, vmax=255)
axes[1, 2].set_title('量化到 4 级')

plt.tight_layout()
plt.show()
```

---

## 2.5 像素间的基本关系

### 🔗 像素邻域

对于像素 p 在坐标 (x, y)：

**4-邻域 (N₄)**：上下左右
```
    (x,y-1)
(x-1,y)  p  (x+1,y)
    (x,y+1)
```

**8-邻域 (N₈)**：4-邻域 + 四个对角
```
(x-1,y-1) (x,y-1) (x+1,y-1)
(x-1,y)    p      (x+1,y)
(x-1,y+1) (x,y+1) (x+1,y+1)
```

### 🔗 连通性 (Connectivity)

**定义**：两个像素是否"相连"的判断标准

| 连通类型 | 条件 | 应用 |
|----------|------|------|
| **4-连通** | 灰度相似且在 N₄ 邻域 | 简单场景 |
| **8-连通** | 灰度相似且在 N₈ 邻域 | 复杂场景 |
| **m-连通** | 混合连通，消除歧义 | 精确分割 |

**连通性示例**：
```
4-连通路径：只能上下左右走
8-连通路径：可以走对角线
```

### 📏 距离度量

像素 p(x,y) 和 q(s,t) 之间的距离：

**欧氏距离**：
```
Dₑ = √[(x-s)² + (y-t)²]
```

**城区距离 (D₄/曼哈顿距离)**：
```
D₄ = |x-s| + |y-t|
```

**棋盘距离 (D₈)**：
```
D₈ = max(|x-s|，|y-t|)
```

**距离可视化**：
```
中心像素到各点的 D₄距离：    中心像素到各点的 D₈距离：
    2 1 2                        2 2 2
    1 0 1                        2 1 2
    2 1 2                        2 2 2
```

---

## 2.6 线性与非线性操作

### 📐 线性操作

**定义**：满足**叠加原理**的操作

```
H(a·f₁ + b·f₂) = a·H(f₁) + b·H(f₂)
```

**常见线性操作**：
- 傅里叶变换
- 卷积滤波（均值滤波、高斯滤波）
- 几何变换（平移、旋转、缩放）

**优势**：数学分析方便，可预测

### 📈 非线性操作

**定义**：不满足叠加原理的操作

**常见非线性操作**：
- 直方图均衡化
- 中值滤波（去椒盐噪声）
- 形态学操作（腐蚀、膨胀）
- 伽马校正

**优势**：处理复杂场景更有效

---

## 💻 第 2 章实践任务

### 任务 1：理解采样定理
```python
import numpy as np
import matplotlib.pyplot as plt

# 生成正弦波信号
x = np.linspace(0, 10, 1000)
y = np.sin(x)

# 不同采样率
sample_rates = [100, 20, 10, 5]  # 采样点数量

fig, axes = plt.subplots(2, 2, figsize=(12, 8))
axes = axes.flatten()

for i, rate in enumerate(sample_rates):
    sample_x = np.linspace(0, 10, rate)
    sample_y = np.sin(sample_x)
    
    axes[i].plot(x, y, 'b-', alpha=0.3, label='原始信号')
    axes[i].plot(sample_x, sample_y, 'ro-', label=f'采样 {rate}点')
    axes[i].legend()
    axes[i].set_title(f'采样率：{rate}')
    axes[i].grid(True)

plt.tight_layout()
plt.show()
```

### 任务 2：像素邻域操作
```python
import cv2
import numpy as np

def get_neighbors(img, x, y, connectivity=8):
    """获取像素的邻域值"""
    h, w = img.shape
    neighbors = []
    
    # 遍历 3x3 区域
    for dx in [-1, 0, 1]:
        for dy in [-1, 0, 1]:
            if dx == 0 and dy == 0:
                continue  # 跳过中心像素
            
            nx, ny = x + dx, y + dy
            
            # 边界检查
            if 0 <= nx < w and 0 <= ny < h:
                if connectivity == 8 or (dx == 0 or dy == 0):
                    neighbors.append(img[ny, nx])
    
    return neighbors

# 测试
img = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE)
neighbors = get_neighbors(img, 100, 100, connectivity=8)
print(f"8-邻域像素值：{neighbors}")
print(f"邻域均值：{np.mean(neighbors):.2f}")
```

### 任务 3：距离度量可视化
```python
import numpy as np
import matplotlib.pyplot as plt

def distance_map(size, center, metric='euclidean'):
    """生成距离图"""
    h, w = size
    cy, cx = center
    dist = np.zeros((h, w))
    
    for y in range(h):
        for x in range(w):
            if metric == 'euclidean':
                dist[y, x] = np.sqrt((x-cx)**2 + (y-cy)**2)
            elif metric == 'manhattan':
                dist[y, x] = abs(x-cx) + abs(y-cy)
            elif metric == 'chessboard':
                dist[y, x] = max(abs(x-cx), abs(y-cy))
    
    return dist

size = (21, 21)
center = (10, 10)

fig, axes = plt.subplots(1, 3, figsize=(15, 5))

im0 = axes[0].imshow(distance_map(size, center, 'euclidean'), cmap='hot')
axes[0].set_title('欧氏距离')
plt.colorbar(im0, ax=axes[0])

im1 = axes[1].imshow(distance_map(size, center, 'manhattan'), cmap='hot')
axes[1].set_title('城区距离 (D₄)')
plt.colorbar(im1, ax=axes[1])

im2 = axes[2].imshow(distance_map(size, center, 'chessboard'), cmap='hot')
axes[2].set_title('棋盘距离 (D₈)')
plt.colorbar(im2, ax=axes[2])

plt.tight_layout()
plt.show()
```

---

## 📝 本章小结

### ✅ 你应该掌握
- [ ] 理解人眼视觉系统和颜色感知原理
- [ ] 掌握采样定理和混叠现象
- [ ] 理解量化的概念和灰度级数选择
- [ ] 能够解释像素的邻域、连通性、距离度量
- [ ] 区分线性和非线性操作
- [ ] 完成采样、量化、邻域操作的代码实践

### 🤔 思考题
1. 为什么手机拍照时快速移动会产生模糊？（提示：采样定理）
2. 医学 CT 图像为什么常用 16 位量化而不是 8 位？
3. 4-连通和 8-连通在图像分割中会产生什么不同结果？
4. 中值滤波为什么是非线性操作？

### 📖 关键公式总结
```
采样定理：f_sample > 2 × f_max
欧氏距离：Dₑ = √[(x-s)² + (y-t)²]
城区距离：D₄ = |x-s| + |y-t|
棋盘距离：D₈ = max(|x-s|，|y-t|)
```

---

_第 2 章完 | 下一章：第 3 章 灰度变换与空间滤波_
# 第 3 章 灰度变换与空间滤波 (Intensity Transformations and Spatial Filtering)

## 📌 本章知识点概览

1. 背景知识
2. **灰度变换函数**（图像增强基础）
3. **直方图处理**（核心重点 ⭐⭐⭐）
4. **空间滤波基础**（核心重点 ⭐⭐⭐）
5. 平滑空间滤波器
6. 锐化空间滤波器

---

## 3.1 背景知识

### 📐 空间域处理的基本公式

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

- f(x, y)：输入图像
- g(x, y)：输出图像
- T：操作符（变换函数）

### 🎯 处理策略分类

| 类型 | 作用范围 | 例子 |
|------|----------|------|
| **点操作** | 单个像素 | 灰度变换、对比度调整 |
| **邻域操作** | 像素 + 周围邻域 | 空间滤波、卷积 |
| **全局操作** | 整幅图像 | 直方图均衡化、傅里叶变换 |

---

## 3.2 灰度变换函数

### 📈 基本灰度变换

#### 1. 图像反转 (Image Negatives)

**公式**：
```
s = L - 1 - r
```
- r：输入灰度值
- s：输出灰度值
- L：灰度级数（通常 256）

**效果**：黑白颠倒，类似底片

**应用**：增强白色/灰色细节（如 X 光片中的骨骼）

```python
import cv2
import numpy as np

def invert_image(img):
    return 255 - img

# 或使用 OpenCV
inverted = cv2.bitwise_not(img)
```

#### 2. 对数变换 (Log Transformations)

**公式**：
```
s = c × log(1 + r)
```
- c：常数，c = 255 / log(1 + max_r)

**效果**：扩展低灰度值，压缩高灰度值

**应用**：显示频谱图、增强暗部细节

```python
def log_transform(img, c=1):
    img_float = img.astype(np.float32)
    transformed = c * np.log(1 + img_float)
    return np.uint8(255 * transformed / transformed.max())
```

#### 3. 幂次变换 (伽马校正)

**公式**：
```
s = c × r^γ
```
- γ < 1：扩展低灰度值（图像变亮）
- γ > 1：扩展高灰度值（图像变暗）
- γ = 1：恒等变换

**应用**：显示器校正、对比度调整

```python
def gamma_transform(img, gamma=1.0):
    invGamma = 1.0 / gamma
    img_float = img.astype(np.float32) / 255.0
    corrected = np.power(img_float, invGamma)
    return np.uint8(corrected * 255)

# 示例
brighter = gamma_transform(img, gamma=0.5)   # 变亮
darker = gamma_transform(img, gamma=2.0)     # 变暗
```

#### 4. 对比度拉伸 (Contrast Stretching)

**目的**：扩展灰度动态范围

**分段线性变换**：
```
s = T(r) = 
  { (r1/r2) × r,           0 ≤ r < r1
  { [(s2-s1)/(r2-r1)]×(r-r1)+s1,  r1 ≤ r < r2
  { [(L-1-s2)/(L-1-r2)]×(r-r2)+s2, r2 ≤ r < L-1
```

```python
def contrast_stretch(img, r1=50, r2=200, s1=0, s2=255):
    img_float = img.astype(np.float32)
    
    # 分段线性变换
    transformed = np.piecewise(
        img_float,
        [img_float < r1, (img_float >= r1) & (img_float < r2), img_float >= r2],
        [lambda x: (s1/r1) * x,
         lambda x: ((s2-s1)/(r2-r1)) * (x-r1) + s1,
         lambda x: ((255-s2)/(255-r2)) * (x-r2) + s2]
    )
    
    return np.uint8(np.clip(transformed, 0, 255))
```

---

## 3.3 直方图处理 ⭐⭐⭐

### 📊 什么是直方图？

**定义**：统计图像中每个灰度级出现的频率

**直方图函数**：
```
h(rₖ) = nₖ
```
- rₖ：第 k 个灰度级
- nₖ：灰度级为 rₖ 的像素数量

**归一化直方图**：
```
p(rₖ) = nₖ / N
```
- N：图像总像素数
- p(rₖ)：灰度级 rₖ 出现的概率

### 💻 绘制直方图

```python
import cv2
import matplotlib.pyplot as plt

def plot_histogram(img):
    plt.figure(figsize=(10, 5))
    
    # 计算直方图
    hist = cv2.calcHist([img], [0], None, [256], [0, 256])
    
    # 绘制
    plt.plot(hist, color='black')
    plt.xlabel('灰度级')
    plt.ylabel('像素数量')
    plt.title('图像直方图')
    plt.xlim([0, 256])
    plt.grid(True, alpha=0.3)
    plt.show()

# 使用
plot_histogram(img)
```

### 🎯 直方图均衡化 (Histogram Equalization)

**目的**：自动增强对比度，使直方图均匀分布

**原理**：
```
sₖ = T(rₖ) = (L-1) × Σ(p(rⱼ)), j=0 to k
```

**步骤**：
1. 计算原始直方图
2. 计算累积分布函数 (CDF)
3. 映射到新的灰度值
4. 四舍五入取整

```python
def histogram_equalization(img):
    # 方法 1：使用 OpenCV
    equalized = cv2.equalizeHist(img)
    
    # 方法 2：手动实现（帮助理解）
    hist, bins = np.histogram(img.flatten(), 256, [0, 256])
    cdf = hist.cumsum()
    cdf_normalized = (cdf - cdf.min()) * 255 / (cdf.max() - cdf.min())
    equalized_manual = cdf_normalized[img].astype(np.uint8)
    
    return equalized

# 使用
enhanced = cv2.equalizeHist(img)
```

**适用场景**：
- ✅ X 光片、卫星图像
- ✅ 背景过亮或过暗的图像
- ❌ 已经对比度良好的图像（可能过增强）

### 🎨 自适应直方图均衡化 (CLAHE)

**问题**：全局均衡化可能过度增强噪声

**解决**：局部自适应均衡化 (CLAHE - Contrast Limited AHE)

```python
def clahe_equalization(img, clipLimit=2.0, tileGridSize=(8, 8)):
    clahe = cv2.createCLAHE(
        clipLimit=clipLimit,      # 对比度限制（防止噪声放大）
        tileGridSize=tileGridSize # 局部区域大小
    )
    return clahe.apply(img)

# 使用
enhanced = clahe_equalization(img, clipLimit=3.0, tileGridSize=(8, 8))
```

**参数说明**：
- `clipLimit`：越大对比度越强，但噪声也越多（推荐 2-4）
- `tileGridSize`：越小局部性越强，计算量越大

---

## 3.4 空间滤波基础 ⭐⭐⭐

### 🔍 什么是空间滤波？

**定义**：在图像空间域中，用像素邻域的值来计算新像素值

**滤波过程**：
```
1. 滤波器模板在图像上滑动
2. 对每个位置，计算模板覆盖区域内像素的加权和
3. 将结果赋给中心像素
```

### 📐 卷积 (Convolution)

**公式**：
```
g(x, y) = Σ Σ w(s, t) × f(x+s, y+t)
          s   t
```
- w：滤波器模板（核/掩模）
- f：输入图像
- g：输出图像

**卷积步骤**：
1. 翻转滤波器（180°旋转）
2. 滑动窗口
3. 对应位置相乘后求和

```python
import numpy as np
import cv2

def convolve2d(img, kernel):
    """手动实现 2D 卷积（帮助理解）"""
    kh, kw = kernel.shape
    pad_h, pad_w = kh // 2, kw // 2
    
    # 填充边界
    padded = cv2.copyMakeBorder(
        img, pad_h, pad_h, pad_w, pad_w,
        cv2.BORDER_REFLECT
    )
    
    h, w = img.shape
    output = np.zeros_like(img, dtype=np.float32)
    
    # 滑动窗口
    for y in range(h):
        for x in range(w):
            region = padded[y:y+kh, x:x+kw]
            output[y, x] = np.sum(region * kernel)
    
    return np.uint8(np.clip(output, 0, 255))
```

### 🎯 相关 (Correlation)

与卷积类似，但**不翻转**滤波器

**OpenCV 中的滤波函数**：
```python
# 方框滤波
result = cv2.boxFilter(img, -1, (3, 3))

# 归一化滤波
result = cv2.blur(img, (3, 3))

# 自定义滤波
kernel = np.array([[0, -1, 0],
                   [-1, 5, -1],
                   [0, -1, 0]])
result = cv2.filter2D(img, -1, kernel)
```

---

## 3.5 平滑空间滤波器

### 🎯 用途
- 模糊（去除细节）
- 降噪（平滑噪声）

### 1. 均值滤波 (Mean Filter)

**模板**：所有系数相等

```
1 1 1
1 1 1  →  除以 9（归一化）
1 1 1
```

**公式**：
```
g(x,y) = (1/M) × Σ f(x+i, y+j)
```
- M：模板像素总数

```python
# 3×3 均值滤波
blurred = cv2.blur(img, (3, 3))

# 5×5 均值滤波
blurred = cv2.blur(img, (5, 5))
```

**特点**：
- ✅ 简单快速
- ❌ 模糊边缘，噪声去除不彻底

### 2. 高斯滤波 (Gaussian Filter)

**模板**：高斯分布权重（中心大，边缘小）

**3×3 高斯核示例**：
```
1 2 1
2 4 2  →  除以 16
1 2 1
```

**5×5 高斯核**：
```
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
```

```python
# 高斯滤波
blurred = cv2.GaussianBlur(img, (5, 5), sigmaX=0)

# 参数说明：
# (5, 5): 核大小（必须是奇数）
# sigmaX: 标准差（0 表示自动计算）
```

**特点**：
- ✅ 保留边缘优于均值滤波
- ✅ 符合人眼视觉特性
- ❌ 计算量稍大

### 3. 中值滤波 (Median Filter)

**原理**：取邻域像素的中值

```python
# 中值滤波
denoised = cv2.medianBlur(img, 5)

# 参数：邻域大小（必须是奇数）
```

**特点**：
- ✅ 去除椒盐噪声效果极佳
- ✅ 保护边缘不模糊
- ❌ 对高斯噪声效果一般
- ❌ 非线性滤波（不能频域分析）

### 📊 滤波器对比

```python
import cv2
import numpy as np
import matplotlib.pyplot as plt

# 添加椒盐噪声
def add_salt_pepper_noise(img, prob=0.05):
    noisy = img.copy()
    h, w = img.shape
    num_noise = int(h * w * prob)
    
    # 盐噪声（白色）
    for _ in range(num_noise):
        y, x = np.random.randint(0, h), np.random.randint(0, w)
        noisy[y, x] = 255
    
    # 椒噪声（黑色）
    for _ in range(num_noise):
        y, x = np.random.randint(0, h), np.random.randint(0, w)
        noisy[y, x] = 0
    
    return noisy

# 测试
noisy = add_salt_pepper_noise(img, prob=0.05)

mean_filtered = cv2.blur(noisy, (5, 5))
gauss_filtered = cv2.GaussianBlur(noisy, (5, 5), 0)
median_filtered = cv2.medianBlur(noisy, 5)

fig, axes = plt.subplots(2, 2, figsize=(12, 12))
axes[0, 0].imshow(noisy, cmap='gray')
axes[0, 0].set_title('含椒盐噪声')
axes[0, 1].imshow(mean_filtered, cmap='gray')
axes[0, 1].set_title('均值滤波')
axes[1, 0].imshow(gauss_filtered, cmap='gray')
axes[1, 0].set_title('高斯滤波')
axes[1, 1].imshow(median_filtered, cmap='gray')
axes[1, 1].set_title('中值滤波')
plt.tight_layout()
plt.show()
```

---

## 3.6 锐化空间滤波器

### 🎯 用途
- 突出边缘和细节
- 补偿图像模糊

### 1. 拉普拉斯算子 (Laplacian)

**二阶微分算子**，各向同性

**模板**：
```
0 -1  0
-1 4 -1   或   -1 -1 -1
0 -1  0        -1  8 -1
               -1 -1 -1
```

**锐化公式**：
```
g(x,y) = f(x,y) - ∇²f(x,y)
```

```python
# 拉普拉斯锐化
laplacian = cv2.Laplacian(img, cv2.CV_64F)
sharpened = img - laplacian
sharpened = np.uint8(np.clip(sharpened, 0, 255))

# 或使用 filter2D
kernel = np.array([[0, -1, 0],
                   [-1, 5, -1],
                   [0, -1, 0]])
sharpened = cv2.filter2D(img, -1, kernel)
```

### 2. 非锐化掩蔽 (Unsharp Masking)

**步骤**：
1. 模糊原图
2. 原图减模糊图得到掩蔽
3. 原图加掩蔽得到锐化图

**公式**：
```
g(x,y) = f(x,y) + k × [f(x,y) - f_blur(x,y)]
```
- k：增强强度（k>1 为高提升滤波）

```python
def unsharp_mask(img, k=1.5, kernel_size=(5, 5)):
    blurred = cv2.GaussianBlur(img, kernel_size, 0)
    mask = img - blurred
    sharpened = img + k * mask
    return np.uint8(np.clip(sharpened, 0, 255))

# 使用
sharpened = unsharp_mask(img, k=1.5)
```

### 3. 梯度算子（边缘检测）

#### Sobel 算子

**x 方向模板**：
```
-1 0 1
-2 0 2
-1 0 1
```

**y 方向模板**：
```
-1 -2 -1
 0  0  0
 1  2  1
```

```python
# Sobel 边缘检测
sobel_x = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobel_y = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)

# 梯度幅值
gradient_magnitude = np.sqrt(sobel_x**2 + sobel_y**2)
gradient_magnitude = np.uint8(255 * gradient_magnitude / gradient_magnitude.max())

# 或使用
edges = cv2.Sobel(img, cv2.CV_8U, 1, 1, ksize=3)
```

#### Prewitt 算子

```python
# Prewitt 算子（OpenCV 无内置，需自定义核）
prewitt_x = np.array([[-1, 0, 1],
                      [-1, 0, 1],
                      [-1, 0, 1]])
prewitt_y = np.array([[-1, -1, -1],
                      [ 0,  0,  0],
                      [ 1,  1,  1]])

edges_x = cv2.filter2D(img, -1, prewitt_x)
edges_y = cv2.filter2D(img, -1, prewitt_y)
```

---

## 💻 第 3 章综合实践

### 项目：图像增强工具箱

```python
import cv2
import numpy as np
import matplotlib.pyplot as plt

class ImageEnhancer:
    """图像增强工具箱"""
    
    def __init__(self, img_path):
        self.img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
        self.results = {}
    
    def gamma_correction(self, gamma=1.0):
        """伽马校正"""
        invGamma = 1.0 / gamma
        img_float = self.img.astype(np.float32) / 255.0
        corrected = np.power(img_float, invGamma)
        self.results['gamma'] = np.uint8(corrected * 255)
        return self.results['gamma']
    
    def histogram_equalize(self):
        """直方图均衡化"""
        self.results['hist_eq'] = cv2.equalizeHist(self.img)
        return self.results['hist_eq']
    
    def clahe(self, clipLimit=3.0):
        """自适应直方图均衡化"""
        clahe = cv2.createCLAHE(clipLimit=clipLimit, tileGridSize=(8, 8))
        self.results['clahe'] = clahe.apply(self.img)
        return self.results['clahe']
    
    def gaussian_blur(self, kernel_size=(5, 5)):
        """高斯模糊"""
        self.results['gauss_blur'] = cv2.GaussianBlur(
            self.img, kernel_size, 0
        )
        return self.results['gauss_blur']
    
    def median_filter(self, kernel_size=5):
        """中值滤波"""
        self.results['median'] = cv2.medianBlur(self.img, kernel_size)
        return self.results['median']
    
    def sharpen(self, k=1.5):
        """锐化"""
        blurred = cv2.GaussianBlur(self.img, (5, 5), 0)
        mask = self.img - blurred
        self.results['sharpen'] = np.uint8(
            np.clip(self.img + k * mask, 0, 255)
        )
        return self.results['sharpen']
    
    def edge_detect(self):
        """边缘检测"""
        sobel_x = cv2.Sobel(self.img, cv2.CV_64F, 1, 0, ksize=3)
        sobel_y = cv2.Sobel(self.img, cv2.CV_64F, 0, 1, ksize=3)
        magnitude = np.sqrt(sobel_x**2 + sobel_y**2)
        self.results['edges'] = np.uint8(
            255 * magnitude / magnitude.max()
        )
        return self.results['edges']
    
    def show_all(self):
        """显示所有结果"""
        n = len(self.results) + 1
        cols = 3
        rows = (n + cols - 1) // cols
        
        fig, axes = plt.subplots(rows, cols, figsize=(15, 5*rows))
        axes = axes.flatten()
        
        axes[0].imshow(self.img, cmap='gray')
        axes[0].set_title('原始图像')
        
        for i, (name, result) in enumerate(self.results.items(), 1):
            axes[i].imshow(result, cmap='gray')
            axes[i].set_title(name.replace('_', ' ').title())
            axes[i].axis('off')
        
        for j in range(i+1, len(axes)):
            axes[j].axis('off')
        
        plt.tight_layout()
        plt.show()

# 使用示例
enhancer = ImageEnhancer('test.jpg')
enhancer.gamma_correction(gamma=0.8)
enhancer.histogram_equalize()
enhancer.clahe(clipLimit=3.0)
enhancer.sharpen(k=1.5)
enhancer.show_all()
```

---

## 📝 本章小结

### ✅ 你应该掌握
- [ ] 理解灰度变换的四种基本类型
- [ ] 掌握直方图均衡化的原理和实现
- [ ] 理解空间滤波和卷积的概念
- [ ] 能够区分均值、高斯、中值滤波的特点
- [ ] 掌握拉普拉斯和非锐化掩蔽锐化方法
- [ ] 能够使用 Sobel 算子进行边缘检测
- [ ] 完成图像增强工具箱项目

### 🤔 思考题
1. 为什么对数变换能增强暗部细节？
2. 直方图均衡化为什么能增强对比度？
3. 中值滤波为什么能去除椒盐噪声但保留边缘？
4. 拉普拉斯算子为什么是二阶微分？
5. 高斯滤波的σ参数对滤波效果有什么影响？

### 📖 关键公式总结
```
图像反转：s = L - 1 - r
对数变换：s = c × log(1 + r)
伽马校正：s = c × r^γ
卷积：g(x,y) = ΣΣ w(s,t) × f(x+s, y+t)
锐化：g(x,y) = f(x,y) - ∇²f(x,y)
非锐化掩蔽：g = f + k × (f - f_blur)
```

---

_第 3 章完 | 下一章：第 4 章 频率域滤波_
# 第 4-12 章 知识点详解

---

## 第 4 章 频率域滤波 (Filtering in the Frequency Domain) ⭐⭐⭐

### 📌 核心知识点

#### 4.1 傅里叶变换基础

**一维傅里叶变换**：
```
F(u) = Σ f(x) × e^(-j2πux), x=0 to N-1
```

**二维傅里叶变换**：
```
F(u,v) = ΣΣ f(x,y) × e^(-j2π(ux/M + vy/N))
```

**物理意义**：将图像从**空间域**转换到**频率域**
- 低频分量：图像的平滑区域、整体轮廓
- 高频分量：图像的边缘、细节、噪声

**逆变换**：
```
f(x,y) = (1/MN) × ΣΣ F(u,v) × e^(j2π(ux/M + vy/N))
```

#### 4.2 频域滤波步骤

```
1. 计算图像的傅里叶变换 F(u,v)
2. 乘以滤波器 H(u,v)
3. 计算逆傅里叶变换得到结果
```

**公式**：
```
g(x,y) = F⁻¹[H(u,v) × F(u,v)]
```

#### 4.3 常见频域滤波器

| 滤波器 | 公式 | 特点 |
|--------|------|------|
| **理想低通** | H(u,v)=1 if D≤D₀, else 0 | 截止频率外完全阻断，产生振铃 |
| **高斯低通** | H(u,v)=e^(-D²/2D₀²) | 平滑过渡，无振铃 |
| **巴特沃斯低通** | H(u,v)=1/[1+(D/D₀)^2n] | 可调节陡峭程度 |
| **理想高通** | H(u,v)=0 if D≤D₀, else 1 | 边缘检测 |
| **高斯高通** | H(u,v)=1-e^(-D²/2D₀²) | 锐化 |

#### 4.4 代码实现

```python
import cv2
import numpy as np
import matplotlib.pyplot as plt

def gaussian_lowpass_filter(shape, cutoff):
    """生成高斯低通滤波器"""
    rows, cols = 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)
    H = np.exp(-(D**2) / (2 * cutoff**2))
    
    return H

def frequency_domain_filter(img, cutoff, filter_type='lowpass'):
    """频域滤波"""
    # FFT 变换
    f = np.fft.fft2(img)
    fshift = np.fft.fftshift(f)  # 零频移到中心
    
    # 生成滤波器
    H = gaussian_lowpass_filter(img.shape, cutoff)
    
    if filter_type == 'highpass':
        H = 1 - H  # 高通 = 1 - 低通
    
    # 滤波
    fshift_filtered = fshift * H
    
    # 逆变换
    f_ishift = np.fft.ifftshift(fshift_filtered)
    img_back = np.fft.ifft2(f_ishift)
    img_back = np.abs(img_back)
    
    return img_back

# 使用
img = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE)
filtered = frequency_domain_filter(img, cutoff=50, filter_type='lowpass')
```

---

## 第 5 章 图像复原与重建 (Image Restoration and Reconstruction)

### 📌 核心知识点

#### 5.1 噪声模型

| 噪声类型 | 概率密度函数 | 特点 | 适用场景 |
|----------|--------------|------|----------|
| **高斯噪声** | p(z) = (1/σ√2π)e^(-(z-μ)²/2σ²) | 对称分布 | 电子电路噪声 |
| **椒盐噪声** | 双峰分布 | 随机黑白点 | 传输错误 |
| **瑞利噪声** | p(z) = (2/b²)(z-a)e^(-(z-a)²/b²) | 偏态分布 | 距离成像 |
| **伽马噪声** | p(z) = (b^a/Γ(a))z^(a-1)e^(-bz) | 正偏态 | 激光成像 |
| **泊松噪声** | p(z) = e^(-λ)λ^z/z! | 离散分布 | 光子计数 |

#### 5.2 退化模型

```
g(x,y) = h(x,y) * f(x,y) + η(x,y)
```
- g：退化图像
- f：原始图像
- h：退化函数（点扩散函数 PSF）
- η：加性噪声
- *：卷积

#### 5.3 复原方法

**1. 逆滤波**：
```
F̂(u,v) = G(u,v) / H(u,v)
```
- 问题：H(u,v)接近 0 时放大噪声

**2. 维纳滤波**（最小均方误差）：
```
F̂(u,v) = [H*(u,v) / (|H(u,v)|² + Sη(u,v)/Sf(u,v))] × G(u,v)
```
- Sη：噪声功率谱
- Sf：原始图像功率谱

**3. 约束最小二乘滤波**：
```
引入拉格朗日乘子，平衡复原和平滑
```

#### 5.4 代码实现

```python
from scipy.signal import wiener

# 维纳滤波（简化版）
def wiener_filter(img, noise_var=0.01):
    return wiener(img, mysiz=(5,5), noise=noise_var)

# 使用 OpenCV 进行去卷积
def richardson_lucy_deconvolution(blurred, psf, iterations=10):
    """Richardson-Lucy 盲去卷积"""
    img = blurred.astype(np.float32)
    psf = psf.astype(np.float32)
    
    for _ in range(iterations):
        convolved = cv2.filter2D(img, -1, psf)
        ratio = blurred / (convolved + 1e-10)
        img *= cv2.filter2D(ratio, -1, psf[::-1, ::-1])
    
    return img.astype(np.uint8)
```

---

## 第 6 章 彩色图像处理 (Color Image Processing)

### 📌 核心知识点

#### 6.1 颜色模型

| 模型 | 分量 | 特点 | 应用 |
|------|------|------|------|
| **RGB** | 红、绿、蓝 | 加色模型，设备相关 | 显示器、相机 |
| **CMY/CMYK** | 青、品红、黄、黑 | 减色模型 | 打印 |
| **HSV/HSI** | 色调、饱和度、亮度/强度 | 符合人眼感知 | 图像分析 |
| **YUV/YCbCr** | 亮度、色度 | 分离亮度和色度 | 视频压缩 |
| **Lab** | 亮度、a 轴、b 轴 | 设备无关，均匀色空间 | 颜色匹配 |

#### 6.2 RGB 到 HSV 转换

```python
# OpenCV 颜色空间转换
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
ycrcb = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
```

#### 6.3 彩色图像滤波

**策略**：
1. 转换到 HSV/Lab 空间
2. 只对亮度通道滤波（避免颜色失真）
3. 转换回 RGB

```python
def color_preserving_blur(img):
    """保持颜色的模糊"""
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    h, s, v = cv2.split(hsv)
    
    # 只对 V 通道模糊
    v_blur = cv2.GaussianBlur(v, (5, 5), 0)
    
    hsv_blur = cv2.merge([h, s, v_blur])
    return cv2.cvtColor(hsv_blur, cv2.COLOR_HSV2BGR)
```

#### 6.4 基于颜色的分割

```python
def segment_by_color(img, lower_color, upper_color):
    """基于颜色范围分割"""
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    lower = np.array(lower_color)
    upper = np.array(upper_color)
    
    mask = cv2.inRange(hsv, lower, upper)
    result = cv2.bitwise_and(img, img, mask=mask)
    
    return mask, result

# 提取红色物体
mask, red_objects = segment_by_color(img, 
    lower_color=[0, 100, 100], 
    upper_color=[10, 255, 255]
)
```

---

## 第 7 章 小波和多分辨率处理 (Wavelets and Multiresolution Processing)

### 📌 核心知识点

#### 7.1 多分辨率分析

**思想**：在不同尺度下观察图像
- 粗尺度：整体结构
- 细尺度：局部细节

#### 7.2 图像金字塔

**高斯金字塔**：
```python
def gaussian_pyramid(img, levels=4):
    """构建高斯金字塔"""
    pyramid = [img]
    for _ in range(levels-1):
        img = cv2.pyrDown(img)
        pyramid.append(img)
    return pyramid

# 使用
pyramid = gaussian_pyramid(img, levels=4)
```

**拉普拉斯金字塔**：
```python
def laplacian_pyramid(img, levels=4):
    """构建拉普拉斯金字塔"""
    gaussian = gaussian_pyramid(img, levels)
    laplacian = []
    
    for i in range(levels-1):
        expanded = cv2.pyrUp(gaussian[i+1])
        diff = cv2.subtract(gaussian[i], expanded)
        laplacian.append(diff)
    
    laplacian.append(gaussian[-1])  # 最顶层
    return laplacian
```

#### 7.3 小波变换

**Haar 小波**（最简单）：
- 尺度函数：φ(x) = 1 (0≤x<1), else 0
- 小波函数：ψ(x) = 1 (0≤x<0.5), -1 (0.5≤x<1)

**二维小波分解**：
```
原始图像 → LL(近似) LH(水平细节)
           HL(垂直细节) HH(对角细节)
```

```python
import pywt

# 二维小波分解
coeffs = pywt.dwt2(img, 'haar')
LL, (LH, HL, HH) = coeffs

# 重构
img_reconstructed = pywt.idwt2((LL, (LH, HL, HH)), 'haar')
```

---

## 第 8 章 图像压缩 (Image Compression)

### 📌 核心知识点

#### 8.1 压缩原理

**冗余类型**：
1. **编码冗余**：码字长度未优化
2. **像素间冗余**：相邻像素相关
3. **心理视觉冗余**：人眼不敏感的信息

**压缩比**：
```
CR = n₁ / n₂
```
- n₁：原始数据量
- n₂：压缩后数据量

#### 8.2 编码方法

**1. 霍夫曼编码**（变长编码）：
```python
import heapq
from collections import Counter

def huffman_encode(data):
    freq = Counter(data)
    heap = [[weight, [symbol, ""]] for symbol, weight in freq.items()]
    heapq.heapify(heap)
    
    while len(heap) > 1:
        lo = heapq.heappop(heap)
        hi = heapq.heappop(heap)
        for pair in lo[1:]:
            pair[1] = '0' + pair[1]
        for pair in hi[1:]:
            pair[1] = '1' + pair[1]
        heapq.heappush(heap, [lo[0] + hi[0]] + lo[1:] + hi[1:])
    
    return sorted(heapq.heappop(heap)[1:], key=lambda p: len(p[0]))
```

**2. 游程编码 (RLE)**：
```
AAAAA BBB CC → (A,5) (B,3) (C,2)
```

**3. 算术编码**：比霍夫曼更高效，接近熵极限

#### 8.3 JPEG 压缩标准

**步骤**：
```
1. 颜色空间转换 (RGB → YCbCr)
2. 下采样色度通道
3. 分块 (8×8)
4. DCT 变换
5. 量化
6. 熵编码 (Zigzag + 霍夫曼)
```

```python
from skimage.transform import rescale
import numpy as np

def dct2(block):
    """二维离散余弦变换"""
    return scipy.fftpack.dct(scipy.fftpack.dct(block.T, norm='ortho').T, norm='ortho')

def idct2(block):
    """二维逆 DCT"""
    return scipy.fftpack.idct(scipy.fftpack.idct(block.T, norm='ortho').T, norm='ortho')
```

---

## 第 9 章 形态学图像处理 (Morphological Image Processing) ⭐⭐

### 📌 核心知识点

#### 9.1 基本形态学操作

**1. 腐蚀 (Erosion)**：
```
A ⊖ B = {z | B_z ⊆ A}
```
- 效果：物体缩小，去除小物体
- 应用：分离粘连物体、去除噪声

```python
eroded = cv2.erode(img, kernel, iterations=1)
```

**2. 膨胀 (Dilation)**：
```
A ⊕ B = {z | B_z ∩ A ≠ ∅}
```
- 效果：物体扩大，填充孔洞
- 应用：填补裂缝、连接断裂

```python
dilated = cv2.dilate(img, kernel, iterations=1)
```

**3. 开运算 (Opening)**：
```
A ○ B = (A ⊖ B) ⊕ B
```
- 先腐蚀后膨胀
- 应用：去除小物体、平滑边界

```python
opened = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
```

**4. 闭运算 (Closing)**：
```
A • B = (A ⊕ B) ⊖ B
```
- 先膨胀后腐蚀
- 应用：填充孔洞、连接邻近物体

```python
closed = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
```

#### 9.2 形态学应用

**1. 边界提取**：
```python
def extract_boundary(img, kernel):
    eroded = cv2.erode(img, kernel)
    boundary = cv2.subtract(img, eroded)
    return boundary
```

**2. 孔洞填充**：
```python
def fill_holes(img):
    # 创建标记（边界为 1，内部为 0）
    marker = np.zeros_like(img)
    marker[1:-1, 1:-1] = img[1:-1, 1:-1]
    marker = cv2.bitwise_not(marker)
    
    # 形态学重建
    filled = marker.copy()
    kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
    
    while True:
        prev = filled.copy()
        filled = cv2.dilate(filled, kernel)
        filled = cv2.bitwise_and(filled, marker)
        if np.array_equal(filled, prev):
            break
    
    return cv2.bitwise_not(filled)
```

**3. 骨架提取**：
```python
def skeletonize(img):
    """形态学骨架化"""
    skeleton = np.zeros_like(img)
    element = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
    
    while True:
        eroded = cv2.erode(img, element)
        temp = cv2.dilate(eroded, element)
        temp = cv2.subtract(img, temp)
        skeleton = cv2.bitwise_or(skeleton, temp)
        img = eroded.copy()
        
        if cv2.countNonZero(img) == 0:
            break
    
    return skeleton
```

---

## 第 10 章 图像分割 (Image Segmentation) ⭐⭐⭐

### 📌 核心知识点

#### 10.1 阈值分割

**1. 全局阈值**：
```python
# 简单阈值
_, thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

# Otsu 自动阈值
_, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
```

**2. 自适应阈值**：
```python
# 局部自适应阈值
adaptive = cv2.adaptiveThreshold(
    img, 255,
    cv2.ADAPTIVE_THRESH_GAUSSIAN_C,  # 或 MEAN_C
    cv2.THRESH_BINARY,
    blockSize=11,  # 邻域大小
    C=2  # 常数偏移
)
```

#### 10.2 边缘分割

**Canny 边缘检测**：
```python
edges = cv2.Canny(
    img,
    threshold1=100,  # 低阈值（连接弱边缘）
    threshold2=200,  # 高阈值（强边缘）
    apertureSize=3,
    L2gradient=False
)
```

#### 10.3 区域分割

**1. 区域生长**：
```python
def region_growing(img, seed_point, threshold=10):
    """区域生长算法"""
    h, w = img.shape
    segmented = np.zeros_like(img, dtype=np.uint8)
    y, x = seed_point
    
    seed_value = img[y, x]
    stack = [(y, x)]
    
    while stack:
        y, x = stack.pop()
        if segmented[y, x]:
            continue
        
        if abs(int(img[y, x]) - int(seed_value)) < threshold:
            segmented[y, x] = 255
            
            # 添加 4-邻域
            for dy, dx in [(-1,0), (1,0), (0,-1), (0,1)]:
                ny, nx = y + dy, x + dx
                if 0 <= ny < h and 0 <= nx < w and not segmented[ny, nx]:
                    stack.append((ny, nx))
    
    return segmented
```

**2. 分水岭算法**：
```python
def watershed_segmentation(img):
    """分水岭分割"""
    # 二值化
    _, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    
    # 形态学操作获取确定背景
    kernel = np.ones((3,3), np.uint8)
    sure_bg = cv2.dilate(thresh, kernel, iterations=3)
    
    # 距离变换获取确定前景
    dist = cv2.distanceTransform(thresh, cv2.DIST_L2, 5)
    _, sure_fg = cv2.threshold(dist, 0.7*dist.max(), 255, 0)
    sure_fg = np.uint8(sure_fg)
    
    # 未知区域
    unknown = cv2.subtract(sure_bg, sure_fg)
    
    # 标记
    _, markers = cv2.connectedComponents(sure_fg)
    markers = markers + 1
    markers[unknown==255] = 0
    
    # 分水岭
    markers = cv2.watershed(cv2.cvtColor(img, cv2.COLOR_GRAY2BGR), markers)
    
    return markers
```

---

## 第 11 章 表示与描述 (Representation and Description)

### 📌 核心知识点

#### 11.1 边界表示

**1. 链码 (Chain Code)**：
- Freeman 链码：8 方向编码
- 差分链码：对旋转不敏感

**2. 多边形近似**：
- 最小周长多边形
- 合并分裂算法

#### 11.2 区域描述子

**1. 纹理描述**：
- 灰度共生矩阵 (GLCM)
- 局部二值模式 (LBP)

```python
from skimage.feature import graycomatrix, graycoprops

# GLCM 特征
glcm = graycomatrix(img, distances=[1], angles=[0], levels=256)
contrast = graycoprops(glcm, 'contrast')
correlation = graycoprops(glcm, 'correlation')
energy = graycoprops(glcm, 'energy')
homogeneity = graycoprops(glcm, 'homogeneity')
```

**2. 矩描述子**：
```python
# Hu 矩（平移、缩放、旋转不变）
moments = cv2.moments(img)
huMoments = cv2.HuMoments(moments)
```

---

## 第 12 章 目标识别 (Object Recognition)

### 📌 核心知识点

#### 12.1 模式识别基础

**识别流程**：
```
图像 → 预处理 → 特征提取 → 特征选择 → 分类 → 识别结果
```

#### 12.2 分类器

**1. 最小距离分类器**：
```python
def min_distance_classifier(features, class_means):
    """最小距离分类"""
    distances = [np.linalg.norm(features - mean) for mean in class_means]
    return np.argmin(distances)
```

**2. 相关匹配**：
```python
# 模板匹配
result = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)
_, max_val, _, max_loc = cv2.minMaxLoc(result)
```

#### 12.3 深度学习简介

**CNN 基本结构**：
```
输入 → 卷积层 → 激活 (ReLU) → 池化 → ... → 全连接 → Softmax → 输出
```

**使用预训练模型**：
```python
import tensorflow as tf

# 加载预训练模型
model = tf.keras.applications.ResNet50(weights='imagenet')

# 预测
from tensorflow.keras.applications.resnet50 import preprocess_input, decode_predictions
img = cv2.resize(img, (224, 224))
img = preprocess_input(img)
predictions = model.predict(np.expand_dims(img, axis=0))
label = decode_predictions(predictions, top=1)[0][0]
```

---

## 📖 学习建议

### 难度分级
- ⭐⭐⭐ 核心必学：第 2、3、4、10 章
- ⭐⭐ 重要：第 5、6、9、11 章
- ⭐ 选读：第 7、8、12 章（根据兴趣）

### 实践建议
1. **每章至少完成 1 个代码项目**
2. **建立自己的图像处理工具库**
3. **用实际数据集测试算法**
4. **参与 Kaggle 图像相关竞赛**

### 进阶方向
- **医学图像分析**：重点学习第 5、10 章
- **工业检测**：重点学习第 3、9、10 章
- **计算机视觉**：重点学习第 10、11、12 章 + 深度学习
- **图像压缩**：重点学习第 7、8 章

---

_教程完 | 祝学习顺利！🌱_
