Rust图像处理第8节-暗角 & 复古胶片特效:四周衰减中心高亮

58 阅读4分钟

暗角 & 复古胶片特效:四周衰减中心高亮

🦀 Rust + WASM 实战系列 第 8 篇 阅读时间:约 5 分钟 | 实战可运行

📌 写在前面

有没有觉得,专业相机拍的照片四周总有一圈暗影?这不是镜头脏了,这是"暗角(Vignette)"——艺术效果,不是缺陷。

这一篇实现两种:

  • 暗角:四周变暗,中心高亮
  • 复古胶片:暗角 + 暖色调 + 颗粒(老电影味道)

🚀 TL;DR

原图:               暗角后:              复古胶片:
┌──────────┐        ┌──────────┐         ┌──────────┐
│  200 200 │        │  200 200 │         │  220 220 │
│ 200 200  │   →    │ 200 180  │    →    │ 200 180  │ + 颗粒
│          │        │   ▓▓▓▓   │         │  ▓  ▓ ▓▓ │
└──────────┘        └──────────┘         └──────────┘
(均匀)             (中心亮,四角暗)    (+ 暖色 + 噪点)
模式公式额外效果
暗角factor = 1 - strength × t²
复古胶片在暗角基础上:暖色调 + 颗粒噪点R 增强、B 减弱、随机 ±5

📖 目录

  1. 暗角的物理原理
  2. 核心算法:3 个数学概念
  3. 关键代码
  4. 前端效果展示
  5. 进阶:衰减函数选型
  6. 复古胶片:暖色 + 颗粒
  7. 应用场景
  8. 参考资料

一、暗角的物理原理

真实相机的暗角来自镜头边缘光线衰减

镜头中心  ←─── 光圈最大,光线最足
镜头边缘  ←─── 光线被遮挡,亮度下降

照片平面上看:

   ┌─────────────────┐
   │  ▓▓▓▓▓▓▓▓▓▓▓▓▓  │
   │ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │  中心:满亮度 1.0
   │▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓│  边缘:~0.6(变暗 40%)
   │ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │
   │  ▓▓▓▓▓▓▓▓▓▓▓▓▓  │  对角:~0.4(最暗)
   └─────────────────┘

算法本质离中心越远,越暗


二、核心算法:3 个数学概念

1. 到中心的距离

let dx = x as f32 - cx;          // 水平距离
let dy = y as f32 - cy;          // 垂直距离
let dist = (dx * dx + dy * dy).sqrt();  // 欧氏距离

2. 归一化到 0~1

let t = dist / max_dist;
// t = 0  →  正在中心
// t = 1  →  在对角

3. 二次衰减函数

let factor = 1.0 - strength * t * t;
// factor = 1.0  → 不变(中心)
// factor = 0.0  → 全黑(对角,strength=1 时)

d20247ce-435a-4749-9640-257bbe14f5e8.png

三、关键代码

for y in 0..height {
    for x in 0..width {
        // 1. 算距中心比
        let dx = x as f32 - cx;
        let dy = y as f32 - cy;
        let dist = (dx * dx + dy * dy).sqrt();
        let t = dist / max_dist;

        // 2. 衰减因子
        let factor = 1.0 - strength * t * t;

        // 3. 应用到 RGB(alpha 保留)
        let i = ((y * width + x) * 4) as usize;
        result[i]     = (pixels[i]     as f32 * factor) as u8;
        result[i + 1] = (pixels[i + 1] as f32 * factor) as u8;
        result[i + 2] = (pixels[i + 2] as f32 * factor) as u8;
        result[i + 3] = pixels[i + 3];
    }
}

四、前端效果展示

738c4af5-d3db-44bd-8500-4fbc9edda9d4.png

f43489e8-5bfe-4878-88ba-060cbcf01165.png

五、进阶:衰减函数选型

不同函数 → 不同暗角效果:

函数效果公式
二次(本文)边缘渐暗,自然1 - t²
线性太硬,像切角1 - t
平方根太亮1 - √t
三次方边缘更暗1 - t³
指数可调衰减快慢1 - e^(-kt)

实际工程中二次最常用,效果最自然。


六、复古胶片:暖色 + 颗粒

vintage 模式在暗角基础上额外做 3 件事

1. 暖色调(Sepia-like)

r *= 1.1;   // 红色增强
b *= 0.9;   // 蓝色减弱
g *= 1.0;   // 绿色不变

效果:偏黄、偏红 → 老电影味道。

2. 颗粒噪点(Grain)

let noise = pseudo_rand(x, y, 42) as f32 - 128.0;  // -128 ~ 127
let grain = noise * 0.15;                          // 缩到 ±19
r = (r + grain).clamp(0.0, 255.0);

为什么用伪随机? 不用引入 rand 库,编译更快、WASM 更小,且相同 (x, y) 永远返回相同值(保证多次调用结果一致)。

3. 暗角照常应用

复古胶片 = 暖色 + 颗粒 + 暗角,三者叠加。


七、应用场景

场景推荐参数
人像特写(聚焦主体)强度 0.6~0.8,纯暗角
风景(聚焦中央景物)强度 0.3~0.5,纯暗角
怀旧照片强度 0.5,复古胶片
电影感强度 0.7,复古胶片
抽象艺术强度 1.0,复古胶片

八、参考资料

  • Wikipedia - Vignetting:暗角的物理原理
  • Photoshop 文档:Filter → Lens Correction → Vignette
  • Lightroom 文档:Effects → Vignette
  • GIMP 文档:Filters → Light and Shadow → Vignette

🎁 写在最后

暗角是"廉价"但有效的艺术手段

  • 实现简单(10 行代码)
  • 效果立竿见影
  • 任何照片加了都有"专业感"

下篇预告:《Sobel 边缘检测:3×3 卷积核提取图像轮廓》—— 第一个真正用卷积的算法,敬请期待。


📦 项目地址pixel-math-wasm 🦀 Rust + WebAssembly 实战系列


🏷️ 标签#Rust #WebAssembly #图像处理 #暗角 #复古胶片 #Vignette #算法