# 第7周：图像处理基础 - 讲义

## 教学目标

| 目标 | 内容 |
|-----|------|
| 知识目标 | 理解摄像头接口原理、图像预处理概念 |
| 能力目标 | 能够使用ESP32-CAM采集并显示图像 |
| 情感目标 | 建立"机器是怎么看世界的"的直观认识 |

---

## 课程导入（10分钟）

### 7.1 开场Demo设计

**Demo名称：AI摄像头**

**演示流程：**
1. 展示：ESP32-CAM实时拍摄，显示人脸检测框
2. 演示：走到摄像头前，屏幕上框出人脸
3. 引导：这节课学完，你们也能做出来

**引导语：**
> "同学们，刚才看到摄像头能实时检测人脸——这就是机器'看见'世界的方式。今天学完图像处理基础，你们也能做出来。"

---

## 原理讲解（40分钟）

### 7.2 图像基础概念

#### 7.2.1 像素与分辨率

```
像素 = Pixel = 图像的基本单元
分辨率 = 水平像素数 × 垂直像素数

常见分辨率：
┌─────────────┬────────────────┐
│  分辨率     │   像素数       │
├─────────────┼────────────────┤
│  640×480    │   30万像素     │
│  800×600    │   48万像素     │
│  1280×720   │   92万像素 HD │
│  1920×1080  │  207万像素 FHD│
└─────────────┴────────────────┘

ESP32-CAM最大分辨率：1600×1200 (200万像素)
```

#### 7.2.2 色彩空间

```
RGB色彩空间：
• R = Red (红)   0-255
• G = Green (绿) 0-255
• B = Blue (蓝)  0-255
• 共256³ = 1677万种颜色

灰度图：
• 只有亮度信息
• 0 = 黑，255 = 白
• 存储空间是RGB的1/3
```

#### 7.2.3 图像格式

| 格式 | 特点 | 应用 |
|------|------|------|
| BMP | 无压缩，体积大 | 很少使用 |
| JPEG | 有损压缩，体积小 | 照片、网络 |
| PNG | 无损压缩，支持透明 | 图标、网页 |
| YUV | 亮度+色度分离 | 视频编码 |

**ESP32-CAM支持：JPEG输出（节省内存）**

---

### 7.3 OV2640摄像头模块

#### 7.3.1 模块介绍

```
OV2640特性：
• 200万像素 (1600×1200)
• 支持JPEG输出
• I2C配置接口
• DVP (Digital Video Port) 数据接口
• 自动曝光/白平衡/增益
```

#### 7.3.2 引脚定义

```
OV2640摄像头排线引脚（从上到下）：
┌─────────────────────────────────────────────┐
│  1. VCC  3.3V供电                          │
│  2. GND  地                                │
│  3. SIOC I2C时钟                           │
│  4. SIOD I2C数据                           │
│  5. VSYNC 帧同步                           │
│  6. HREF  行参考                           │
│  7. PCLK  像素时钟                         │
│  8. XCLK  系统时钟输入                     │
│  9-16. D0-D7 数据总线                      │
│  17. RESET 复位                            │
│  18. PWDN 掉电模式                         │
└─────────────────────────────────────────────┘
```

---

### 7.4 ESP32-CAM开发板

#### 7.4.1 板子特点

```
ESP32-CAM特性：
• ESP32 + OV2640 二合一
• WiFi + 摄像头
• 价格便宜 (~30元)
• 缺点：没有USB接口，需要用FTDI编程器
```

#### 7.4.2 引脚连接

```
ESP32-CAM GPIO对应：
• GPIO1 = TX (烧录用)
• GPIO3 = RX (烧录用)
• GPIO0 = 用于程序启动（烧录时需接地）
• GPIO2 = 摄像头D2
• GPIO4 = 摄像头D10
• GPIO12 = 摄像头D5
• GPIO13 = 摄像头D4
• GPIO14 = 摄像头D6
• GPIO15 = 摄像头D3
• GPIO16 = 摄像头D7
• GPIO17 = 摄像头D9
• GPIO18 = 摄像头D8
• GPIO21 = SDA
• GPIO22 = SCL
```

---

### 7.5 图像处理流程

#### 7.5.1 摄像头获取图像步骤

```
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  1️⃣ 初始化摄像头                                            │
│     camera_config_t config = {...};                         │
│     esp_err_t err = esp_camera_init(&config);              │
│                                                             │
│  2️⃣ 获取图像                                                │
│     camera_fb_t *fb = esp_camera_fb_get();                  │
│                                                             │
│  3️⃣ 使用图像                                                │
│     // fb->buf 包含JPEG数据                                │
│     // fb->len 数据长度                                    │
│                                                             │
│  4️⃣ 释放图像                                                │
│     esp_camera_fb_return(fb);                               │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

#### 7.5.2 摄像头配置参数

```cpp
camera_config_t config = {
    .pin_pwdn = 32,      // 电源控制引脚
    .pin_reset = -1,     // 复位引脚（-1表示不用）
    .pin_xclk = 0,      // 系统时钟
    .pin_sscb_sda = 26, // I2C数据
    .pin_sscb_scl = 27, // I2C时钟
    
    .pin_d7 = 35,
    .pin_d6 = 34,
    .pin_d5 = 5,
    .pin_d4 = 39,
    .pin_d3 = 18,
    .pin_d2 = 36,
    .pin_d1 = 19,
    .pin_d0 = 21,
    
    .pin_vsync = 25,
    .pin_href = 23,
    .pin_pclk = 22,
    .pin_fref = -1,
    
    .xclk_freq_hz = 20000000,  // 20MHz
    .ledc_timer = LEDC_TIMER_0,
    .pixel_format = PIXFORMAT_JPEG,
    .frame_size = FRAMESIZE_SVGA,  // 800×600
    .jpeg_quality = 10,  // 0-63，越小质量越好
    .fb_count = 2,  // 双缓冲
};
```

---

## 实验操作（40分钟）

### 7.6 实验：ESP32-CAM图像采集

#### 实验目的
- 掌握ESP32-CAM的基本使用方法
- 学会配置摄像头参数
- 实现图像采集和显示

#### 实验器材
- ESP32-CAM开发板 × 1
- FTDI编程器 × 1（或ESP32-CAM自带USB）
- 杜邦线若干

#### 实验步骤

**1. 硬件连接**
```
ESP32-CAM  →  FTDI编程器
-------------------------
VCC (5V)  →  VCC (5V)
GND       →  GND
U0RXD    →  FTDI TX
U0TXD    →  FTDI RX
GPIO0    →  GND (烧录模式)

注意：烧录完成后，断开GPIO0和GND的连接！
```

**2. Arduino库安装**
```
1. Arduino IDE → 工具 → 开发板 → 开发板管理器
2. 搜索"esp32" → 安装ESP32 by Espressif Systems
3. 安装完成后选择：AI Thinker ESP32-CAM
```

**3. 基础采集代码**
```cpp
#include "esp_camera.h"
#include <WiFi.h>

// 摄像头引脚定义（AI Thinker ESP32-CAM）
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM        5
#define Y4_GPIO_NUM       18
#define Y3_GPIO_NUM       19
#define Y2_GPIO_NUM       21
#define Y1_GPIO_NUM       35
#define Y0_GPIO_NUM       22
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

void setup() {
  Serial.begin(115200);
  
  camera_config_t config;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  config.frame_size = FRAMESIZE_SVGA;
  config.jpeg_quality = 10;
  config.fb_count = 2;
  
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }
  
  Serial.println("Camera init OK!");
}

void loop() {
  camera_fb_t * fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Camera capture failed");
    return;
  }
  
  Serial.printf("Captured: %dx%d, %d bytes\n", 
    fb->width, fb->height, fb->len);
  
  esp_camera_fb_return(fb);
  delay(2000);
}
```

**4. 观察输出**
- 打开串口监视器（115200）
- 看到"Camera init OK!"表示初始化成功
- 然后每2秒打印一次图像尺寸和大小

---

## 知识总结

### 7.7 ESP32-CAM vs 普通ESP32

| 特性 | ESP32 | ESP32-CAM |
|------|-------|-----------|
| 摄像头 | 无 | OV2640 (200万) |
| WiFi | 有 | 有 |
| 价格 | ~25元 | ~35元 |
| 编程 | USB直接 | 需要FTDI |
| GPIO | 多 | 较少（被摄像头占用） |

---

## 课后作业

1. **理论题**：解释像素、分辨率、色彩空间
2. **实践题**：完成ESP32-CAM图像采集实验
3. **思考题**：为什么ESP32-CAM输出JPEG而不是RGB？

---

## 延伸阅读

- ESP32-CAM官方文档：https://github.com/espressif/arduino-esp32
- OV2640数据手册
