Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion .cursor/rules/cross-platform-cpp.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,30 @@ alwaysApply: false

# C++ 跨平台编译规范

本项目支持 Linux / macOS / Windows (MSVC) 三平台。所有 C++ 代码必须在 MSVC 上编译通过。

## MSVC 禁用项

- **禁止 `M_PI` / `M_E` / `M_SQRT2` 等 POSIX 数学常量**:MSVC 默认不定义。使用 C++20 `std::numbers::pi`、`std::numbers::e` 等替代,需 `#include <numbers>`。
- **禁止 `constexpr` 中调用 `std::pow`、`std::exp`、`std::log`、`std::sin` 等**:MSVC 不将这些视为 constexpr。需要编译期求值时使用运行时初始化的 `static` 变量或 LUT。
- **禁止 VLA(变长数组)**:MSVC 不支持。使用 `std::vector` 或固定大小数组。
- **禁止 GCC/Clang 扩展**:`__attribute__`、`__builtin_*`、`__typeof__`、`__PRETTY_FUNCTION__`。使用标准等价物(如 `[[nodiscard]]`、`__FUNCSIG__` + `#ifdef` 分支)。

## MSVC OpenMP 2.0 限制

MSVC 仅支持 OpenMP 2.0,以下功能不可用:
- `#pragma omp parallel for` 的循环变量必须是 `int`(不支持 `size_t`、`unsigned`、迭代器)
- 不支持 `collapse`、`task`、`taskloop`
- 不支持自定义类型的 `reduction`:使用 per-thread 数组 + 手动合并
- OpenMP API 调用(`omp_get_thread_num()` 等)必须用 `#ifdef _OPENMP` 保护

## POSIX 函数兼容

- `popen`/`pclose` → MSVC 下用 `_popen`/`_pclose`,需 `#if defined(_WIN32)` 分支
- `localtime_r` → MSVC 下用 `localtime_s`(参数顺序不同)
- `strdup` → MSVC 下用 `_strdup`
- `strcasecmp` → MSVC 下用 `_stricmp`

## 文件系统路径

禁止硬编码 POSIX 路径,一律使用 `std::filesystem`(C++17)。
Expand All @@ -24,4 +48,4 @@ alwaysApply: false

## 变更检查

每次新增系统调用或文件操作时,必须确认跨平台兼容性
每次新增系统调用、数学常量、OpenMP 代码或文件操作时,必须确认 MSVC 兼容性
120 changes: 120 additions & 0 deletions .cursor/rules/eval-usage.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# 评估系统使用指南

当需要运行 eval 评估时,直接使用以下信息,无需重新查看文件。

## 测试图像

Manifest 路径:`test_data/images/manifest.json`

共 15 张图,分两类:

### simple(8 张)

| 简称 | 文件 | 尺寸 | 特征 |
|------|------|------|------|
| tjls | `simple/tjls.jpg` | 3071×3071 | 只有 2 种主色 |
| varesa | `simple/varesa.JPG` | 1431×1431 | 需 16-18 色保持色彩完整 |
| bcba38 | `simple/BCBA38E4139B200BF7018202BD7071DA.jpg` | 1450×2048 | 中等复杂度 |
| s_c0315 | `simple/c03155ca4f21690e44fe38b5d2e94e4a_535808916776764142.png` | 188×253 | 小图 |
| s_b8489 | `simple/b848977173910bd7f1029f89003dff75_3952281026289371623.png` | 96×96 | 小图 |
| s_0ce86 | `simple/0ce86ee140a04fd833f948a637af2283_1513181873101011224.png` | 96×96 | 小图 |
| s_64c9a | `simple/64c9aca07027becd6143bbbdb47a323a_7089473772145220523.png` | 96×96 | 黑白二值小图 |
| s_39e69 | `simple/39e69fa36571347e9300cb88dedea782_5990935446758869519.png` | 96×96 | 小图 |

### complex(6 张)

| 简称 | 文件 | 尺寸 | 特征 |
|------|------|------|------|
| miku | `complex/miku.png` | 4680×2876 | 多色区域+渐变,大图 |
| reward | `complex/reward_1002.b096a174..png` | 200×200 | 中等 |
| c_193ce | `complex/193ce3eb96bce41fc84619164cd3aed5_748736223171964553.png` | 360×376 | 中等 |
| c_5bf9c | `complex/5bf9ca7c5b342d38c8b3fbf0964e00da_6402413799256732419.png` | 450×450 | 中等 |
| c_7eda8 | `complex/7eda813e089f1bdcec4e7c7e93b101d6_6078806162773208785.png` | 450×450 | 中等 |
| c_8e8d9 | `complex/8e8d9ba7da393866262621c946642090_7081326994847318235.png` | 450×450 | 中等 |

## 常用命令

### 批量评估(14 张全跑)

```bash
# V2 管线
./build/apps/evaluate_svg \
--manifest test_data/images/manifest.json \
--svg-dir test_data/images/results/<输出目录名> \
--json test_data/images/results/<输出目录名>/report.json \
--pipeline v2 \
--log-level info \
--note "说明文字"

# V1 管线
./build/apps/evaluate_svg \
--manifest test_data/images/manifest.json \
--svg-dir test_data/images/results/<输出目录名> \
--json test_data/images/results/<输出目录名>/report.json \
--pipeline v1 \
--log-level info
```

### 单图评估

```bash
./build/apps/evaluate_svg \
--image test_data/images/simple/tjls.jpg \
--svg-dir test_data/images/results/<输出目录名> \
--json test_data/images/results/<输出目录名>/report.json \
--pipeline v2 \
--log-level debug
```

### 单图矢量化(不评估)

```bash
./build/apps/raster_to_svg \
--image test_data/images/complex/miku.png \
--out /tmp/miku.svg \
--pipeline v2 \
--log-level debug
```

### 只跑某一类

```bash
./build/apps/evaluate_svg \
--manifest test_data/images/manifest.json \
--svg-dir test_data/images/results/<输出目录名> \
--json test_data/images/results/<输出目录名>/report.json \
--pipeline v2 \
--category simple
```

## 关键参数覆盖

| 参数 | 说明 | 默认值 |
|------|------|--------|
| `--colors N` | 颜色数,0=自动 | 0 |
| `--pipeline MODE` | v1 或 v2 | v1 |
| `--log-level LEVEL` | trace/debug/info/warn/error/off | info |
| `--min-region N` | 最小区域面积 | 50 |
| `--curve-fit-error F` | 曲线拟合误差 | 0.8 |
| `--smoothing-spatial F` | Mean Shift 空间半径 | 15 |
| `--smoothing-color F` | Mean Shift 颜色半径 | 25 |
| `--max-working-pixels N` | 自动缩放阈值 | 3000000 |

## 已有评估结果目录

结果存储在 `test_data/images/results/` 下:
- `v1_eval/` — V1 管线基准
- `v2_eval/` — V2 管线初始基准
- `v2_eval_new/` — V2 修复 AutoDetectK 后(kTargetRemaining=0.02)
- `v2_eval_tuned/` — V2 调优 AutoDetectK 后(kTargetRemaining=0.005)

## 输出格式

report.json 中每张图的 metrics 包含:
- `score` — 综合得分
- `unique_colors` — 实际使用的颜色数
- `delta_e_mean` — 平均色差
- `ssim` — 结构相似度
- `coverage` — 覆盖率
- `total_shapes` — 形状总数
- `vectorize_time_ms` — 矢量化耗时
34 changes: 34 additions & 0 deletions .cursor/rules/post-algo-eval.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
description: 算法改进后必须跑 eval 验证效果
alwaysApply: true
---

# 算法改进后验证

当修改涉及以下模块的算法逻辑时,完成代码修改并确认编译通过后,必须跑一次 eval 验证效果:

- 颜色量化 (`src/quantize/`)
- 深度排序 / 形状延伸 (`src/stacking/`)
- Potrace 追踪 / 覆盖率修补 (`src/trace/`)
- 曲线拟合 / 路径优化 (`src/curve/`)
- 管线编排 (`src/pipeline.cpp`, `src/pipeline_v2.cpp`)
- SVG 输出 (`src/output/`)
- 预处理 / 分割 (`src/preprocess/`, `src/segment/`)

## 验证流程

1. 编译通过 + 单元测试通过
2. 跑 V2 批量评估(15 张全跑),与上一次结果对比:

```bash
./build/apps/evaluate_svg \
--manifest test_data/images/manifest.json \
--svg-dir test_data/images/results/<本次目录名> \
--json test_data/images/results/<本次目录名>/report.json \
--pipeline v2 \
--log-level info \
--note "<本次改动简述>"
```

3. 对比 report.json 中关键指标(score、delta_e_mean、ssim、coverage),确认无回归
4. 若改动同时影响 V1,额外跑一次 `--pipeline v1` 验证
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-22.04, macos-14, windows-latest]
python-version: ["3.10", "3.11", "3.12", "3.13"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]

steps:
- uses: actions/checkout@v4
Expand Down
24 changes: 20 additions & 4 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,33 @@ on:
jobs:
# ── Build wheels on each platform ─────────────────────────────────────────
build-wheels:
name: Wheels (${{ matrix.os }}, ${{ matrix.arch }})
name: Wheels (${{ matrix.id }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
arch: x86_64
cibw_build: "cp310-* cp311-* cp312-* cp313-* cp314-*"
id: linux-x86_64
- os: macos-14
arch: "x86_64 arm64"
arch: arm64
cibw_build: "cp310-* cp311-* cp312-* cp313-* cp314-*"
id: macos-arm64
# Split Windows into parallel groups to reduce wall time
- os: windows-latest
arch: AMD64
cibw_build: "cp310-* cp311-*"
id: windows-py310-311
- os: windows-latest
arch: AMD64
cibw_build: "cp312-* cp313-*"
id: windows-py312-313
- os: windows-latest
arch: AMD64
cibw_build: "cp314-*"
id: windows-py314

steps:
- uses: actions/checkout@v4
Expand All @@ -40,14 +55,15 @@ jobs:
key: vcpkg-win-${{ hashFiles('ci/install-deps-windows.bat', 'ci/potrace-CMakeLists.txt') }}
restore-keys: vcpkg-win-

- uses: pypa/cibuildwheel@v2.23
- uses: pypa/cibuildwheel@v3.4.0
env:
CIBW_ARCHS: ${{ matrix.arch }}
CIBW_BUILD: ${{ matrix.cibw_build }}
SETUPTOOLS_SCM_PRETEND_VERSION: ${{ env.SETUPTOOLS_SCM_PRETEND_VERSION }}

- uses: actions/upload-artifact@v4
with:
name: wheels-${{ matrix.os }}-${{ matrix.arch }}
name: wheels-${{ matrix.id }}
path: wheelhouse/*.whl
retention-days: 14

Expand Down
25 changes: 20 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,33 @@

## 项目全景

本库实现栅格到 SVG 矢量化的完整管线,按 7 个阶段组织
本库实现栅格到 SVG 矢量化的完整管线,支持两种管线模式

**V1(默认)**:边界图 + 剪切模型
```
输入图像 → [预处理] → [颜色分割] → [边界提取] → [轮廓装配] → [曲线拟合] → [轮廓追踪] → [SVG输出]
```

**V2(层叠模型)**:深度排序 + 画家算法
```
输入图像 → [预处理] → [OKLab MMCQ量化] → [小区域合并] → [连通域提取] → [深度排序] → [形状延伸] → [逐层Potrace] → [路径优化] → [同色合并] → [覆盖率修补] → [SVG输出]
```

通过 `VectorizerConfig::pipeline_mode` 选择 `PipelineMode::V1` 或 `PipelineMode::V2`。

### 目录映射

- `include/neroued/vectorizer/`:公共 API 头文件(VectorizerConfig / VectorizerResult / Vectorize)
- `src/preprocess/`:图像缩放、Mean Shift 平滑
- `src/segment/`:SLIC 超像素、K-Means 聚类、形态学清理、小区域合并
- `src/boundary/`:像素级边界图构建、亚像素细化、抗锯齿边缘检测
- `src/contour/`:链式轮廓装配、薄线矢量化
- `src/curve/`:贝塞尔工具函数、Schneider 曲线拟合
- `src/curve/`:贝塞尔工具函数、Schneider 曲线拟合、路径优化(V2)
- `src/trace/`:Potrace 位图追踪、覆盖率修补、Clipper2 拓扑修复
- `src/stacking/`:V2 层叠模型(深度排序、形状延伸)
- `src/quantize/`:V2 OKLab MMCQ 颜色量化
- `src/output/`:SVG 文档生成、同色形状合并
- `src/detail/`:内部工具(OpenCV 辅助、ICC 色彩管理)
- `src/detail/`:内部工具(OpenCV 辅助、ICC 色彩管理、VectorizedShape 核心类型
- `python/`:Python 绑定(pybind11 绑定代码、Python 包、测试)
- `eval/`:质量评估库(像素/边缘/路径指标、基线对比)
- `apps/`:CLI 工具(raster_to_svg、evaluate_svg)
Expand All @@ -47,7 +57,12 @@
| 修改 Potrace 追踪行为 | `src/trace/potrace.cpp` |
| 修改覆盖率修补逻辑 | `src/trace/coverage.cpp` |
| 修改拓扑修复策略 | `src/trace/topology.cpp` |
| 调整管线编排流程 | `src/pipeline.cpp` |
| 调整 V1 管线编排流程 | `src/pipeline.cpp` |
| 调整 V2 管线编排流程 | `src/pipeline_v2.cpp` |
| 修改 V2 深度排序逻辑 | `src/stacking/depth_order.cpp` |
| 修改 V2 形状延伸策略 | `src/stacking/shape_extend.cpp` |
| 修改 V2 OKLab 颜色量化 | `src/quantize/color_quantize.cpp`、`src/quantize/oklab.h` |
| 修改 V2 路径优化 | `src/curve/path_optimize.cpp` |
| 新增/修改公共 API | `include/neroued/vectorizer/vectorizer.h`、`src/vectorizer.cpp` |
| 新增/修改配置参数 | `include/neroued/vectorizer/config.h` |
| 修改质量评估指标 | `eval/src/pixel_metrics.cpp`、`eval/src/edge_metrics.cpp`、`eval/src/path_metrics.cpp` |
Expand All @@ -64,7 +79,7 @@
| 文件 | 内容 |
|------|------|
| `vectorizer.h` | 3 个 `Vectorize` 重载(文件路径 / 内存缓冲区 / cv::Mat) |
| `config.h` | `VectorizerConfig` — 管线完整配置 |
| `config.h` | `PipelineMode` 枚举、`VectorizerConfig` — 管线完整配置 |
| `result.h` | `VectorizerResult` — SVG 内容、尺寸、形状数、调色板 |
| `color.h` | `Rgb`、`Lab` 颜色类型及空间转换 |
| `vec2.h` / `vec3.h` | 2D/3D 向量类型 |
Expand Down
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,12 @@ add_library(neroued_vectorizer STATIC
src/trace/topology.cpp
src/output/svg_writer.cpp
src/output/shape_merge.cpp
src/detail/icc_utils.cpp)
src/detail/icc_utils.cpp
src/pipeline_v2.cpp
src/stacking/depth_order.cpp
src/stacking/shape_extend.cpp
src/quantize/color_quantize.cpp
src/curve/path_optimize.cpp)

add_library(neroued::vectorizer ALIAS neroued_vectorizer)

Expand Down
Loading
Loading