本项目使用 C++ 、Python 和 ImGui 实现了一个二维多边形形状渐变(morphing)算法。算法的核心基于1996年 Zhang 提出的“基于模糊数学的二维多边形形状渐变”方法。
它能够自动计算两个(拓扑上相似的)轮廓之间的顶点对应关系,并使用仿射变换插值来平滑地计算中间帧。
-
自动顶点对应:使用 ==基于模糊数学的图论求解方法== 和
$O(m^2n)$ 动态规划来自动寻找两个多边形之间的最佳顶点匹配。 -
平滑插值:使用基于局部仿射变换和矩阵分解的插值方法,以避免线性插值导致的“收缩”和“枯萎”问题。
-
轮廓提取:包含一个 Python 脚本,使用 OpenCV 自动从黑白轮廓图中提取多边形顶点。
-
实时交互界面:使用 ImGui 构建,允许用户:
- 实时拖动时间滑块(
t)查看渐变。 - 实时调整
sim_t和smooth_a算法的权重,以观察对匹配结果的影响。 - 动态加载不同的多边形文件。
- 实时拖动时间滑块(
ShapeBlenderProject/
├── assets/ # 存放输入/输出数据
│ ├── image_*.png # 示例输入图像 A B
│ ├── poly_*.json # (由 Python 脚本生成)
│
├── build/ # (CMake 生成的文件,需要自己构建)
│
├── include/ # C++ 头文件 (.h)
│ ├── Application.h # 封装 ImGui 和 GLFW 窗口
│ ├── Polygon.h # 多边形数据结构
│ └── ShapeBlender.h # 核心算法类
│
├── lib/ # 外部依赖库 (作为子模块或源码)
│ ├── eigen/ # Eigen (线性代数)
│ ├── glfw/ # GLFW (窗口和输入) [源代码]
│ ├── imgui/ # ImGui (GUI) [源代码]
│ └── json/ # nlohmann/json.hpp (JSON 解析)
│
├── scripts/ # 预处理脚本
│ ├── extract_contours.py # 轮廓提取脚本
│ └── requirements.txt # (opencv-python, numpy)
│
├── src/ # C++ 源文件 (.cpp)
│ ├── Application.cpp
│ ├── main.cpp
│ ├── Polygon.cpp
│ └── ShapeBlender.cpp
│
└── CMakeLists.txt # 主构建脚本
本项目通过 Git 子模块和 CMake 在本地编译所有依赖项,实现了完全可移植。
-
C++ 核心:
- Eigen (v3.4+): 用于所有线性代数(矩阵、向量)运算。
- Dear ImGui (v1.89+): 用于创建图形用户界面。
- nlohmann/json (v3.11+): 用于解析 Python 脚本生成的
.json顶点文件。 - GLFW (v3.3+): 作为
add_subdirectory由 CMake 在本地编译,用于创建窗口和处理 OpenGL 上下文。
-
Python 脚本 (
scripts/):- OpenCV-Python: 用于从图像中读取和提取轮廓。
- NumPy: 用于辅助 OpenCV 的数据操作。
请按以下步骤运行本项目。
在运行 C++ 程序之前,必须先生成 .json 顶点文件。
- 安装 Python 依赖:
# 安装 requirements.txt 中的包
pip install -r scripts/requirements.txt- 运行提取脚本:
python scripts/extract_contours.py- 脚本会弹出两个 GUI 窗口,请依次选择“图像 A”和“图像 B”。
- 脚本会自动处理顶点密度,并强制保证
poly_a.json的顶点数 (m) 大于等于poly_b.json的顶点数 (n)。 - 它会在
assets/目录中生成poly_a.json和poly_b.json。
- 脚本会自动处理顶点密度,并强制保证
- 配置与编译项目:
mkdir build
cd build
cmake ..
make- 运行:
- 可执行文件
ShapeBlender会在build/目录中生成。 - 重要:
assets文件夹位于build/目录的上一级(../)。 Application.cpp中默认的m_pathABuf和m_pathBBuf路径(../assets/poly_a.json)是正确的。
- 可执行文件
./ShapeBlender-
程序启动后,应自动加载
../assets/poly_a.json和../assets/poly_b.json。在程序打开伊始,"Viewport"窗口和"Controls"窗口可能会黏在一起,因此需要调节一下。 -
在 "Viewport" 窗口中(可以拖动靠边形成DockSpace),可以看到红色的为源图像,蓝色的为目标图像,白色的为中间图像。
-
在 "Controls" 窗口中,将 "Render Scale" 滑块从
1.0向下拖动到0.1或0.05,直到您能看到三个多边形。 -
拖动 "Time (t)" 滑块来查看渐变。
-
在 "Controls" 窗口中调节
sim_t和smooth_a权重,然后点击 "Load & Recompute" 来查看算法匹配结果的变化。sim_t权重会影响 DP 算法的匹配结果。smooth_a权重会影响仿射基的选择。