Supervised Descent Method for Face Alignment 的现代 Python 3.12+ 实现,专注于教学与算法理解
本项目是对 2016 年的经典面部对齐算法 SDM (Supervised Descent Method) 的全面重构与升级。虽然原项目的实际应用价值已经有限,但对于理解计算机视觉中的经典算法、对比传统方法与深度学习方法具有重要的教学意义。
- 教学示范:通过详细的 Jupyter Notebook 讲解算法原理和实现细节
- 代码现代化:使用 Python 3.12+、类型注解、现代工具链
- 对比学习:提供经典 SDM 与深度学习方法的性能对比
- 模块化设计:清晰的代码结构,易于理解和扩展
- ✅ 经典 SDM 实现:基于 HOG 特征和 Lasso 回归的完整实现
- ✅ PyTorch 深度学习版本:CNN 和 ResNet 模型用于性能对比
- ✅ 模块化设计:清晰的代码结构,可作为独立 Python 包使用
- ✅ 丰富的工具函数:数据加载、特征提取、可视化等
- 📚 8 个 Jupyter Notebooks:从理论到实践的完整教学
- 📖 详细文档:算法原理、API 文档、使用教程
- 🎨 可视化界面:Streamlit Web 应用,直观展示算法效果
- 📊 性能对比:经典方法 vs 深度学习方法的详细对比
- 🔧 现代工具链:uv 包管理、Ruff 代码检查、mypy 类型检查
- 🧪 单元测试:pytest 测试覆盖核心功能
- 📦 易于安装:一行命令完成环境配置
- Python 3.12 或更高版本
- uv 包管理器(推荐)
# 1. 克隆仓库
git clone https://github.com/Ning-Ding/SDM.git
cd SDM
# 2. 安装 uv(如果尚未安装)
curl -LsSf https://astral.sh/uv/install.sh | sh
# 3. 安装项目依赖
uv sync
# 4. 安装开发和教学依赖(可选)
uv sync --extra all下载 LFPW 数据集:
# 下载链接(来自原项目)
# 百度网盘: https://pan.baidu.com/s/1jIJNg2q 密码: f36i
# 解压后放置在项目根目录
SDM/
└── data/
├── trainset/
├── testset/
└── bounding_boxes/from sdm import SDM, SDMConfig
from sdm.data.dataset import LFPWDataset
# 创建配置
config = SDMConfig(
n_iterations=3,
alpha=0.001,
)
# 加载数据集
dataset = LFPWDataset(data_root="data", split="train", config=config)
# 训练模型
model = SDM(config)
model.train(dataset)
# 保存模型
model.save("models/sdm_model.mat")# 训练
sdm-train --data-root data/ --output models/sdm_model.mat --iterations 3
# 推理
sdm-infer --model models/sdm_model.mat --data-root data/ --output-dir results/
# 演示
sdm-demo --model models/sdm_model.mat --image test.png --output result.png# 训练经典 SDM
python examples/train.py --data-root data/ --output models/sdm_model.mat
# 训练 PyTorch 模型
python examples/train_pytorch.py --data-root data/ --model-type cnn --epochs 50
# 方法对比
python examples/compare_methods.py --data-root data/ \
--sdm-model models/sdm_model.mat \
--pytorch-model models/pytorch/best_model.pth我们提供了详细的 Jupyter Notebooks,涵盖从理论到实践的完整内容:
| Notebook | 主题 | 内容 |
|---|---|---|
| 00_setup_and_data.ipynb | 环境配置与数据准备 | 安装依赖、数据集介绍、数据加载与可视化 |
📝 注意:更多教学 Notebooks 正在开发中,将陆续覆盖算法原理、特征提取、训练过程、评估分析等内容。
# 安装 notebook 依赖
uv sync --extra notebook
# 启动 JupyterLab
jupyter labSDM/
├── sdm/ # 核心库
│ ├── core/ # SDM 核心算法
│ │ ├── model.py # 模型配置类
│ │ └── sdm.py # SDM 主类
│ ├── features/ # 特征提取
│ │ └── hog.py # HOG 特征
│ ├── data/ # 数据处理
│ │ ├── dataset.py # 数据集类
│ │ └── loader.py # 数据加载工具
│ ├── utils/ # 工具函数
│ │ ├── bbox.py # 边界框处理
│ │ ├── image.py # 图像处理
│ │ └── visualization.py # 可视化
│ └── pytorch/ # PyTorch 实现
│ ├── model.py # 神经网络模型
│ ├── trainer.py # 训练器
│ └── dataset.py # PyTorch 数据集
│
├── notebooks/ # 教学 Notebooks
├── examples/ # 示例脚本
├── tests/ # 单元测试
├── docs/ # 文档
└── pyproject.toml # 项目配置
SDM 是一种用于面部对齐的经典算法,其核心思想是:
- 初始化:使用平均形状初始化关键点位置
- 迭代优化:
- 在当前关键点位置提取特征(HOG)
- 学习回归器:
Δx = R·φ(I, x) + b - 更新关键点:
x_new = x + Δx
- 级联优化:多次迭代逐步精细化关键点位置
HOG 是一种经典的图像特征描述子:
- 计算图像梯度的方向和幅值
- 将梯度方向量化为直方图
- 在局部区域进行块归一化
- 对光照变化具有鲁棒性
| 方法 | Mean MSE | 训练时间 | 推理速度 |
|---|---|---|---|
| SDM (原始实现) | 150.2 | ~10 min | ~50 ms/img |
| SDM (重构版本) | 148.5 | ~8 min | ~45 ms/img |
| PyTorch CNN | 89.3 | ~30 min | ~5 ms/img |
| PyTorch ResNet | 62.1 | ~60 min | ~8 ms/img |
注:以上数据基于 LFPW 测试集,在单个 NVIDIA RTX 3090 上测试
# 代码格式化和检查
uv run ruff check .
uv run ruff format .
# 类型检查
uv run mypy sdm/
# 运行测试
uv run pytest tests/
# 测试覆盖率
uv run pytest --cov=sdm --cov-report=html- Fork 本仓库
- 创建功能分支 (
git checkout -b feature/AmazingFeature) - 提交更改 (
git commit -m 'Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 开启 Pull Request
📝 注意:算法原理文档、API 参考文档等正在完善中。
- 原始实现:Ning Ding (2016)
- SDM 论文:Xiong & De la Torre, CVPR 2013
- LFPW 数据集:Face Parts in the Wild
本项目采用 MIT 许可证 - 详见 LICENSE 文件
项目链接: https://github.com/Ning-Ding/SDM
如果这个项目对你有帮助,请给我们一个 Star!
原始项目 (2016) 使用说明:
- First, download the dataset used by this project, which is the lfpw dataset. Link: https://pan.baidu.com/s/1jIJNg2q pwd: f36i
- Second, get the data from data.tar that just downloaded
- Third, put main.py in the same directory with the data folder, then run the main.py
- For the first time, the main.py will run the train with a parameters, and after training process, you will get a train_data.mat file in the current directory. If you run the main.py with a train_data.mat file already there, the main.py will load the R,B,I from the file without the training process.
- After you have get the R,B,I, you simply run the function test_after_run_main(n) to test the number nth image in the testset.
原始代码已备份至 main_legacy.py。
本项目重构于 2025年,使用现代 Python 技术栈,专注于算法教学与理解。