圆上之圆 · 轮廓傅里叶绘图工具

FOURIER CONTOUR · DOC ⇄ ANIMATION

01参数文档JSON

02图像说明description

(尚未载入文档)
—傅里叶项数
—采样点数
—频率范围 n
—振幅覆盖率
—轮廓尺寸
—截断重建误差

03动画控制

48
10.0 s
1.6
1.00×
画布:滚轮缩放 · 按住拖动平移 · 双击复位
快捷键:空格 播放/暂停 · ↑↓ 调速 · ←→ 逐步

04当前绘制的参数—

#n 频率amp 振幅phase 相位占比
项数 0 t = 0.000 速度 0.10 圈/秒 缩放 1.00×
0.00 / 1.00

01图像来源

02轮廓提取

320 px
128
1 ×
512
3

03轮廓范围含内部孔洞

0.2 %
12
轮廓按面积从大到小排序;每个轮廓的项数 = K·√(面积比),小孔洞自动少画几个圆。

04傅里叶展开

128
—轮廓数量(外+孔)
—振幅覆盖率
—重建最大偏差
—重建 RMS 偏差
—实际阈值
提取的轮廓(多轮廓分色) K 项重建轨迹(虚线)
把图片拖到这里,或点左上角「选择图片」
也可以用内置示例图

05生成的参数文档—

参数文档格式速查

参数文档是一份纯 JSON 文本,描述「一个图像轮廓」的傅里叶展开。开头是图像说明, 然后是元信息,最后是每一项参数。文件扩展名建议 .json。

{
  "format": "fourier-contour",
  "version": 1,
  "description": "心形轮廓:512 点等弧长采样,保留振幅最大的 128 项。",
  "meta": {
    "name": "心形 heart",
    "source": "builtin:heart",
    "createdAt": "2026-01-01T00:00:00.000Z",
    "pointCount": 512,
    "termCount": 128,
    "amplitudeCoverage": 0.999999,
    "phaseUnit": "rad",
    "origin": "center",
    "yAxis": "down",
    "unit": "px",
    "coordinate": { "width": 400, "height": 398, "minX": -200, "minY": -199, "maxX": 200, "maxY": 199 },
    "notes": "p(t) = Σ amp·e^{i(2π·n·t + phase)},t∈[0,1)。"
  },
  "terms": [
    { "n": 0,  "amp": 3.2041,  "phase": 0 },
    { "n": 1,  "amp": 178.9,   "phase": -1.5708 },
    { "n": -1, "amp": 178.9,   "phase": 1.5708 },
    { "n": 2,  "amp": 62.31,   "phase": 0.7854 }
  ]
}

字段说明

字段必填说明
description建议图像说明。文档开头的自然语言描述,会显示在界面「图像说明」卡片里。
format / version否格式标识与版本号,当前为 "fourier-contour" / 1。
meta否元信息:来源、采样点数、覆盖率、误差、坐标系等。仅用于展示与溯源,不影响绘制。
meta.phaseUnit否"rad"(默认,弧度)或 "deg"(角度)。角度制文档会被自动换算。
terms[].n是整数频率,可为负。负频率表示反向旋转,n=0 项不旋转,就是轮廓的中心偏移。
terms[].amp二选一圆的半径(振幅)。
terms[].phase二选一初相(弧度)。省略按 0 处理。它与 amp 一起等价于复数系数。
terms[].re / im二选一直接给复数系数 c = re + im·i,此时无需 amp / phase。
points否也可以直接给轮廓点数组 [[x,y],…],工具会在线做傅里叶展开(保留 meta.termCount 项,默认 128)。

多轮廓文档(version 2):包含图像内部的孔洞

一个图形往往不止一条轮廓:字母「O」有内孔、同心圆环有多层、logo 里可能有多个独立形状。 当图像提取到一条以上轮廓时,文档改用顶层 contours 数组,每条轮廓各自带一组 terms:

{
  "description": "由图像「示例图:target」提取轮廓生成:共提取 5 个轮廓(含 2 个内部孔洞)……",
  "meta": {
    "contourCount": 5,
    "outerCount": 3,
    "holeCount": 2,
    "termCount": 410,
    "termCountPolicy": "每个轮廓的项数 = K·√(该轮廓面积/最大轮廓面积),下限 6 项",
    "contours": [
      { "index": 0, "role": "outer", "name": "外轮廓 1", "area": 48717.4, "termCount": 160, "amplitudeCoverage": 0.999998 },
      { "index": 1, "role": "hole",  "name": "内部孔洞 2", "area": 27455.1, "termCount": 120, "amplitudeCoverage": 0.999991 }
    ]
  },
  "contours": [
    { "role": "outer", "name": "外轮廓 1", "terms": [ { "n": 0, "amp": 160.4, "phase": -2.356 }, … ] },
    { "role": "hole",  "name": "内部孔洞 2", "terms": [ { "n": 0, "amp": 160.0, "phase": -2.356 }, … ] },
    { "role": "outer", "name": "外轮廓 3", "terms": [ … ] }
  ]
}
字段说明
contours[].role"outer"(外轮廓)或 "hole"(内部孔洞)。只影响标注与配色,不影响绘制。
contours[].name轮廓名称,显示在界面的参数表标题与图例里。
contours[].terms与单轮廓文档的 terms 格式完全一致。
meta.termCountPolicy项数分配策略的说明文本,便于溯源。

单轮廓文档(顶层 terms)依然完全兼容:两种结构可以混用,解析器会自动识别。 动画中每条轮廓都是独立的一条「圆上之圆」链条,按面积分配圆的数量,同时旋转、各画各的轨迹。

自己写多轮廓文档时,只要保证 contours 里每一项都有 terms 即可; role 和 meta 都可以省略。想只画外轮廓,删掉 role: "hole" 的项即可。

数学约定

轮廓被看作复平面上的闭合曲线 z(t) = x(t) + i·y(t),t ∈ [0,1):

z(t) = Σ_k  c_k · e^{ i·2π·n_k·t }
c_k  = (1/N) Σ_{j=0}^{N-1} z_j · e^{ -i·2π·n_k·j/N }      ← 离散采样点的展开系数

文档中的每一项 { n, amp, phase } 对应 c = amp·e^{i·phase},它对轨迹的贡献是

amp · e^{ i·(2π·n·t + phase) }

也就是:半径 amp、初相 phase、角速度 2π·n 的一个匀速旋转矢量。 把它们首尾相接(每一项的起点是前一项的终点)就得到经典的「圆上之圆」动画,最后一项的终点即为笔尖。

画布坐标使用图像坐标系:原点在左上角、y 轴向下。若希望得到数学课本里 y 轴向上的观感, 勾选界面上的「Y 轴翻转」即可,它只影响显示,不影响文档数值。

参数文档的 terms 建议按 amp 从大到小排序:这样只画前若干个圆时, 轨迹已经是轮廓的合理近似(界面上的「按振幅排序」开关默认打开)。

容错与简写

  • 键名可用中文:说明 / 参数 / 频率 / 振幅 / 相位。
  • 每一项可以简写成数组:[n, amp, phase]。
  • 根对象可以再包一层 {"doc": { … }}。
  • 相位单位可用 "deg" 或中文 "度",会自动换算成弧度。
  • 解析失败会给出中文提示,指明是第几项、缺什么字段。

最小可用文档

两项就能画出一个圆(n=0 决定圆心,n=1 决定半径):

{
  "description": "半径 100、圆心 (200,150) 的圆",
  "terms": [
    { "n": 0, "amp": 250, "phase": 0.6435 },
    { "n": 1, "amp": 100, "phase": 1.5708 }
  ]
}

其中圆心 (200,150) 写成复数 200+150i,其极坐标即 amp=√(200²+150²)=250、phase=atan2(150,200)=0.6435。

从图像自动生成文档的流程

  1. 缩放:按「处理分辨率」把图片等比缩放到长边 N 像素(默认 320),减少噪点与计算量。
  2. 二值化:按前景判定方式(深色 / 浅色 / 透明通道)与阈值(默认 Otsu 自动)生成掩膜。
  3. 闭运算:可选地先膨胀后腐蚀,把断裂的线条、网点连成整体。
  4. 连通域分析:分别标记前景与背景的连通域。落在图像内部、不与边框相连的背景连通域,就是内部孔洞。
  5. 边界跟踪:对每个前景连通域和每个孔洞做 Moore 邻域跟踪,得到多条有序轮廓像素链, 并按面积从大到小排序(可用「最小轮廓面积」「最多轮廓数」过滤碎轮廓)。
  6. 等弧长重采样:每条轮廓均匀取 N 个点(默认 512),并做环形平滑削掉像素锯齿。
  7. 傅里叶展开:每条轮廓各自 DFT,按振幅从大到小保留前 K 项(K = 设定值 × √面积比,下限 6), 写出多轮廓参数文档。
抽稀与偏置说明:孔洞轮廓跟踪的是孔洞区域的边界像素中心,因此内轮廓比真实内边缘约大半个像素; 外轮廓则约小半个像素。对傅里叶展开无实质影响。

用这份工具做什么

  • 把任意 logo、签名、线稿(含内孔、多层镂空)丢进「图像 → 参数文档」,得到一份可读、可手改、可版本管理的参数文档。
  • 把参数文档丢进「参数文档 → 动图」,看圆上之圆如何一笔画完整个轮廓;多轮廓时是几条链条同时作画。
  • 拖动「绘制的圆数量」,直观看到低频圆搭出大致形体、高频圆补出细节尖角的过程。
  • 用「一圈用时」滑块或 0.5×–20× 预设调速:慢速看每个圆怎么转,高速看整体的「一笔画」效果。
  • 在画布上滚轮缩放、按住拖动平移、双击复位,放大看某个小圆如何一点点补出尖角。