{
  "lead": "加载一张本地图片，由 WASM 逐像素处理，实时对比原图和滤镜效果。图片不会上传，所有处理都在浏览器本地完成。",
  "formulas": [
    [
      "Y = 0.299R + 0.587G + 0.114B",
      "灰度"
    ],
    [
      "G = √(Gx² + Gy²)",
      "Sobel 边缘强度"
    ]
  ],
  "terms": [
    [
      "灰度",
      "按人眼对三原色的敏感度加权求亮度 <code>0.299R + 0.587G + 0.114B</code>（ITU-R BT.601 标准）。"
    ],
    [
      "反色",
      "每个颜色通道取 <code>255 − 原值</code>，透明度不变。"
    ],
    [
      "模糊",
      "3×3 均值滤波，每个像素取自身和周围 8 个像素的平均值。"
    ],
    [
      "边缘检测",
      "Sobel 算子。用两个 3×3 卷积核分别计算水平梯度 <code>Gx</code> 和垂直梯度 <code>Gy</code>，梯度大小 <code>√(Gx² + Gy²)</code> 越大，说明那里的亮度变化越剧烈，也就是边缘。"
    ],
    [
      "浮雕",
      "用方向性卷积核 <code>[−2 −1 0; −1 1 1; 0 1 2]</code> 模拟左上方的光照，结果加 128 作为中性灰底色。"
    ]
  ],
  "terms_notes": [
    "卷积类滤镜需要读取周围像素，因此图像最外面一圈像素不做处理。"
  ],
  "flow": [
    [
      "js",
      "JS 读取图片文件，画到 Canvas 上（最长边缩放到 400px），用 <code>getImageData()</code> 取出 RGBA 像素数组。"
    ],
    [
      "js",
      "JS 调用 <code>apply_filter(像素, 宽, 高, 滤镜编号)</code>，像素数组被复制进 WASM 内存，在 Rust 中作为 <code>&amp;[u8]</code> 读取。"
    ],
    [
      "rust",
      "Rust 计算并返回一个新的像素数组，原图数据保持不变，方便切换滤镜。"
    ],
    [
      "js",
      "JS 用 <code>putImageData()</code> 把结果画到右侧 Canvas。"
    ]
  ],
  "perf": [
    "3×3 卷积中每个像素要读取 9 个邻居，是典型的访存加计算循环，WASM 可以稳定接近原生速度。",
    "同一个 <code>apply_filter</code> 函数也被「实时视频滤镜」复用，用来处理 30fps 的摄像头画面。"
  ],
  "src": [
    [
      "crates/media/image-filter/src/lib.rs",
      ""
    ],
    [
      "www/image-filter/index.js",
      ""
    ]
  ]
}
