1. 开篇段落:从像素的客观事实到矢量的几何猜想
在人类看来,一张低分辨率的图片中的“圆形”是显而易见的。但在计算机视觉的底层,并没有“圆”这个概念,只有一网格离散的像素点(Raster)。矢量化(Vectorization),或称图像追踪(Image Tracing),本质上是一个逆向重建问题:试图从离散的、有损的像素采样中,恢复出连续的、数学化的几何描述。
对于 SVG-MLLM 项目而言,本章是数据工程的基石。目前的互联网上缺乏高质量的 (Image, SVG Code) 配对数据。绝大多数研究(如 DeepSVG, IconShop)都依赖传统算法将大量位图转化为矢量图来构造预训练语料。
学习目标:
- 解构管线:深入理解从位图预处理到曲线拟合的工业级标准流程(Potrace/AutoTrace 范式)。
- 核心算法:掌握二值化(Otsu)、轮廓提取、RDP 简化与贝塞尔拟合的数学直觉。
- 模式差异:区分“轮廓追踪”(Outline/Fill)与“中心线追踪”(Centerline/Stroke)的本质区别及适用场景。
- 数据洞察:识别传统算法生成 SVG 的特征性缺陷(如无语义堆叠、碎片化),为 MLLM 的训练目标设计提供依据。
2. 文字论述:矢量化的标准工业管线
一个成熟的图像追踪引擎(如 Inkscape 内部机制)并非一步到位,而是由一系列信号处理步骤组成的流水线。
2.1 阶段一:预处理(让机器看清形状)
输入图像往往充满噪点、压缩伪影(Artifacts)和渐变色,直接追踪会产生数以万计的无意义微小路径(Path Explosion)。
- 去噪与平滑 (Denoising):
- 高斯模糊:去除高频噪点,但会模糊边缘。
- 双边滤波 (Bilateral Filter):Rule of Thumb 的首选。它能保留边缘(Edge-preserving)的同时去除平坦区域的噪点,这对提取清晰轮廓至关重要。
- 形态学操作:开运算(先腐蚀后膨胀)用于去除孤立的亮斑;闭运算(先膨胀后腐蚀)用于填补图形内部的小黑洞。
- 二值化 (Binarization):
- SVG 的
<path> 是硬边界,像素必须被划分为“内”或“外”。
- 全局阈值:选定一个 0-255 的值,一刀切。
- 大津法 (Otsu’s Method):自动寻找最佳阈值,使得前景和背景的类间方差最大。对于黑白分明的图标效果极佳。
- 自适应阈值 (Adaptive Thresholding):根据像素局部的邻域计算阈值。适合光照不均匀的扫描文档(如左边亮右边暗的纸张)。
- 色彩量化 (Color Quantization):
- 如果是彩色图片,必须先降维。通常使用 K-Means 聚类将全图颜色减少到 $K$ 种(例如 16 色)。
- 分层策略:将图片分解为 $K$ 张黑白位图(每一张代表一种颜色),分别进行追踪,最后叠加。
2.2 阶段二:轮廓提取(在迷宫中行走)
现在我们有了一张只有 0 和 1 的黑白图。目标是将像素的边缘转化为有序的坐标点列表。
- 摩尔邻域算法 (Moore-Neighbor Tracing):
想象一个机器人站在黑色像素上。它按照顺时针方向检查周围的 8 个邻居像素。一旦找到一个黑色像素,就移动过去并重复此过程。
- 拓扑结构 (Topology):
不仅仅是外轮廓,还需要识别“洞”(Holes)。算法通常输出一个树状结构(Tree of Paths):
- 根节点:画布
- 子节点:外轮廓(黑色)
- 孙节点:内部挖空(白色)
- 曾孙节点:挖空内部的孤岛(黑色)
Rule of Thumb:在这个阶段提取出的路径全是“曼哈顿阶梯”,即由水平和垂直短线组成的锯齿状路径。坐标点数量 $\approx$ 图像分辨率的周长,数据量巨大。
2.3 阶段三:路径简化(RDP 算法)
这是数据压缩的关键一步。我们需要把几千个像素点简化为几十个关键特征点。Ramer-Douglas-Peucker (RDP) 算法是该领域的标准。
算法直觉:
- 想象一条橡皮筋连接曲线的首尾。
- 找到曲线上离橡皮筋“最远”的那个点。
- 如果这个距离小于设定的阈值 $\epsilon$(Epsilon),说明这一段曲线近似于直线,中间所有点都可以丢弃。
- 如果距离大于 $\epsilon$,则保留该点,像钉钉子一样把橡皮筋钉住,然后对两边的线段递归执行此过程。
ASCII 演示 RDP 简化过程:
Step 1: 原始像素点 (X) 与首尾连线 (---)
X
/ \ <-- 距离 d > Epsilon,保留顶点
X X
/ \
S-------E
Step 2: 递归处理左边,若中间点距离连线很近
X
/ \
X---X <-- 距离 d < Epsilon,丢弃中间点,直接拉直
/
S
结果:保留了关键拐角,丢弃了直线上的冗余像素。
2.4 阶段四:曲线拟合(从折线到贝塞尔)
SVG 的灵魂在于 Cubic Bézier 曲线。此阶段将 RDP 输出的折线段转化为平滑曲线。
- 角点检测 (Corner Detection):
并非所有点都要平滑。如果三个点的夹角非常锐利(如 < 135°),则该点被标记为“角点”(Corner),曲线必须在此打断,使用
L 命令或不连续的控制点。
- 切线估计:
对于非角点,根据其前后点的坐标估算切线方向。
- 最小二乘法拟合:
在两个端点之间,寻找两个控制点 $(P_1, P_2)$,使得生成的贝塞尔曲线与原像素路径的垂直距离平方和最小。
- 错误能量与分裂:
如果拟合后的曲线与原路径误差仍然过大,算法会在误差最大的位置插入一个新的节点,将曲线一分为二重新拟合。
3. 两种核心范式:轮廓 vs. 骨架
在 SVG-MLLM 的应用场景中,必须区分两种截然不同的矢量化逻辑。
3.1 轮廓追踪 (Outline Tracing / Potrace)
- 原理:沿着黑色区域的边缘行走。
- 产物:封闭的形状(Filled Shapes)。
- 例子:画一条粗线,Potrace 会生成一个长条形的矩形路径,通过
fill 属性填充颜色。
- 适用:Logo、图标、版画、剪影。
- 现有工具:Potrace (Inkscape), Vector Magic。
- MLLM 视角:这是目前大部分训练数据(如 DeepSVG 数据集)的形态。
3.2 中心线追踪 (Centerline Tracing / Skeletonization)
- 原理:通过细化算法 (Thinning/Zhang-Suen Algorithm) 不断腐蚀黑色像素,直到只剩下一个像素宽的骨架,然后将骨架转化为路径。
- 产物:开放的线条(Stroked Paths)。
- 例子:画一条粗线,生成一条单线路径,通过
stroke-width 属性控制粗细。
- 适用:手写文字、工程制图 (CAD)、素描草图。
- 难点:交叉点(Junction points)处理极难。比如“十”字路口,骨架化后容易变成扭曲的形状。
- MLLM 视角:这更符合人类绘画的逻辑(Stroke-based),也是 SketchRNN 等生成模型的目标,但获取高质量的训练数据非常困难。
4. 传统算法的系统性缺陷(MLLM 的机会)
理解传统算法做不到什么,就是理解为什么我们需要训练一个 AI 模型来做这件事。
- 缺乏语义层级 (No Semantic Hierarchy):
- 传统算法输出的 SVG 是一堆“平铺”的碎片。它不懂“这是一只被树遮挡的猫”。它会把猫切成两半,中间挖空。
- MLLM 目标:生成完整的猫和完整的树,利用 SVG 的图层顺序(Z-order)处理遮挡。
- 过度拟合噪点 (Over-fitting Noise):
- 位图上的污渍会被忠实地追踪成一个形状。
- MLLM 目标:学习“去噪生成”,忽略非几何的视觉噪声。
- 几何正则化缺失 (Lack of Regularity):
- 一个手绘的歪歪扭扭的圆,传统算法会生成一个歪歪扭扭的
<path>。
- MLLM 目标:识别出意图是“圆”,直接生成
<circle> 标签,实现设计稿的规整化。
5. 本章小结
- 逆问题的本质:从 Raster 到 Vector 是试图从有限信息中恢复无限精度的过程,必须依赖平滑性假设。
- 关键算法链:预处理(去噪)→ 轮廓提取(Moore)→ 简化(RDP)→ 拟合(贝塞尔)。每一个环节的参数都影响最终 Token 的数量和质量。
- RDP 是核心:它决定了 SVG 是“精细但巨大”还是“抽象且轻量”。
- 数据形态:现有的大规模 SVG 数据集大多由 Potrace 类算法生成,因此充满了
path 填充而非 stroke 描边,且缺乏遮挡关系。这是训练 SVG-MLLM 时必须正视的数据偏置(Data Bias)。
6. 练习题
基础题
Q1: 贝塞尔控制点的物理意义
在曲线拟合阶段,如果将一个 Cubic Bézier 曲线的两个控制点都拉得离端点非常远,曲线的形状会发生什么变化?这在拟合尖锐转角时可能导致什么问题?
点击查看提示 (Hint)
控制点距离代表“速度”或“张力”。拉得过远会导致曲线产生自交(Loop)或剧烈的过冲(Overshoot),就像赛车过弯速度太快冲出了赛道。
Q2: 阈值对 Token 数量的影响
假设你使用 RDP 算法处理一张 1024x1024 的图片。如果将 $\epsilon$ 从 1.0 提高到 5.0,最终生成的 SVG 文件大小(及 Token 数)大概会呈什么趋势变化?为什么?
点击查看提示 (Hint)
呈反比急剧下降。$\epsilon$ 增加意味着容忍更大的误差,更多的中间点被丢弃,`` 命令中的坐标对减少,Token 数量显著降低。
</details>
**Q3: 二值化的挑战**
对于一张白纸上用铅笔写的字(对比度低,且光照不均),为什么全局阈值(Global Threshold)效果很差?应该改用什么算法?
点击查看提示 (Hint)
全局阈值无法兼顾亮处的背景和暗处的字。应使用自适应阈值(Adaptive Threshold),它根据每个像素周围小窗口的平均亮度来动态决定阈值。
### 挑战题
**Q4: 伪像消除 (Artifact Removal)**
JPEG 压缩会在物体边缘产生“振铃效应”(Ringing artifacts)。如果直接对 JPEG 图片进行追踪,SVG 边缘会充满细碎的波浪。请提出一种预处理流水线来缓解这个问题。
点击查看提示 (Hint)
JPEG 伪像通常是高频噪声。流水线:双边滤波(磨皮保留边缘) -> 适度的形态学开运算(去除微小孤岛) -> 在 RDP 阶段适当调大 $\epsilon$(忽略微小波动)。
**Q5: 思考题:从 Potrace 到 MLLM 的数据清洗**
如果你有一百万个由 Potrace 生成的 SVG 数据,用来训练 MLLM 生成可编辑图标。你会发现 Potrace 经常把一个“同心圆环”生成为“一个 Path 里面包含两个 Sub-path(利用奇偶填充规则挖空)”。
为了让 MLLM 学会生成更符合人类直觉的“两个 Circle 对象叠加(小圆盖在大圆上,颜色为背景色)”,你需要如何设计数据清洗或转换规则?
点击查看提示 (Hint)
这是一个很难的逆问题。你需要解析 Path 的拓扑结构,检测包含关系。如果发现一个 Sub-path 完全在另一个内部,且方向相反(挖空),尝试将其拆解为两个独立的形状,并将内部形状的 Fill 设为背景色。或者,依靠 MLLM 的微调阶段,用人工标注的高质量数据去纠正这种归纳偏差。
---
## 7. 常见陷阱与错误 (Gotchas)
### 1. 坐标系原点与 ViewBox 灾难
* **现象**:追踪出的 SVG 在浏览器里显示正常,但喂给模型训练时,模型学不会坐标分布。
* **原因**:传统算法生成的 SVG 往往直接使用像素坐标(如 `M 500 800`),且可能带有巨大的 `transform="translate(...)"` 偏移。
* **调试**:在作为训练数据前,必须进行 **Canonicalization(规范化)**。将所有路径应用 Transform 变换,将坐标重新缩放到 `0.0 - 1.0` 或 `0 - 256` 的统一 ViewBox 内,并去除无用的 Group 偏移。
### 2. 小数点精度爆炸
* **现象**:SVG 文件巨大,文本是 `L 10.123456789 20.987654321`。
* **原因**:浮点数计算未截断。这就相当于让 MLLM 浪费大量 Token 去记忆无意义的显微镜级精度。
* **Rule of Thumb**:对于 1024px 尺寸的图像,保留 **1 位小数** 甚至取整通常在视觉上已经足够。训练数据务必做 `round(x, 1)` 处理。
### 3. "毛刺"路径 (Spurs)
* **现象**:SVG 路径上偶尔会伸出一根极细的、肉眼几乎看不见的“刺”。
* **原因**:骨架化(Skeletonization)算法在处理物体边缘不规则突起时产生的典型错误。
* **处理**:需要后处理算法,修剪掉长度小于阈值的悬挂分支(Pruning)。
### 4. 颜色对齐的坑
* **现象**:多层彩色追踪时,色块边缘出现极细的白线(缝隙)。
* **原因**:抗锯齿渲染时,两个仅仅是几何上“挨着”的形状,在像素边缘混合时会露出背景色。
* **技巧**:在生成 SVG 时,稍微让底层的形状“膨胀”一点点(Trapping),或者让形状之间有轻微的重叠,而不是完美的数学拼接。这对于 MLLM 生成高质量可渲染 SVG 也是一个重要的 Trick。