图像滤镜(Image Filter)

由 Rust + WebAssembly 驱动

🖼️

将图片拖放到此处

或点击选择文件

📖 原理说明

加载一张本地图片,由 WASM 逐像素处理,实时对比原图和滤镜效果。图片不会上传,所有处理都在浏览器本地完成。

🧮算法原理

Y = 0.299R + 0.587G + 0.114B灰度
G = √(Gx² + Gy²)Sobel 边缘强度
灰度
按人眼对三原色的敏感度加权求亮度 0.299R + 0.587G + 0.114B(ITU-R BT.601 标准)。
反色
每个颜色通道取 255 − 原值,透明度不变。
模糊
3×3 均值滤波,每个像素取自身和周围 8 个像素的平均值。
边缘检测
Sobel 算子。用两个 3×3 卷积核分别计算水平梯度 Gx 和垂直梯度 Gy,梯度大小 √(Gx² + Gy²) 越大,说明那里的亮度变化越剧烈,也就是边缘。
浮雕
用方向性卷积核 [−2 −1 0; −1 1 1; 0 1 2] 模拟左上方的光照,结果加 128 作为中性灰底色。

卷积类滤镜需要读取周围像素,因此图像最外面一圈像素不做处理。

🔄Rust 与 JavaScript 的分工

  1. JSJS 读取图片文件,画到 Canvas 上(最长边缩放到 400px),用 getImageData() 取出 RGBA 像素数组。
  2. JSJS 调用 apply_filter(像素, 宽, 高, 滤镜编号),像素数组被复制进 WASM 内存,在 Rust 中作为 &[u8] 读取。
  3. RustRust 计算并返回一个新的像素数组,原图数据保持不变,方便切换滤镜。
  4. JSJS 用 putImageData() 把结果画到右侧 Canvas。

⚡性能要点

  • 3×3 卷积中每个像素要读取 9 个邻居,是典型的访存加计算循环,WASM 可以稳定接近原生速度。
  • 同一个 apply_filter 函数也被「实时视频滤镜」复用,用来处理 30fps 的摄像头画面。

源码crates/media/image-filter/src/lib.rswww/image-filter/index.js