暗角 & 复古胶片特效:四周衰减中心高亮
🦀 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 |
📖 目录
- 暗角的物理原理
- [核心算法:3 个数学概念](#核心算法:3 个数学概念 "#%E4%BA%8C%E6%A0%B8%E5%BF%83%E7%AE%97%E6%B3%953-%E4%B8%AA%E6%95%B0%E5%AD%A6%E6%A6%82%E5%BF%B5")
- 关键代码
- 前端效果展示
- 进阶:衰减函数选型
- [复古胶片:暖色 + 颗粒](#复古胶片:暖色 + 颗粒 "#%E5%85%AD%E5%A4%8D%E5%8F%A4%E8%83%B6%E7%89%87%E6%9A%96%E8%89%B2--%E9%A2%97%E7%B2%92")
- 应用场景
- 参考资料
一、暗角的物理原理
真实相机的暗角来自镜头边缘光线衰减:
镜头中心 ←─── 光圈最大,光线最足
镜头边缘 ←─── 光线被遮挡,亮度下降
照片平面上看:
erlang
┌─────────────────┐
│ ▓▓▓▓▓▓▓▓▓▓▓▓▓ │
│ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │ 中心:满亮度 1.0
│▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓│ 边缘:~0.6(变暗 40%)
│ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │
│ ▓▓▓▓▓▓▓▓▓▓▓▓▓ │ 对角:~0.4(最暗)
└─────────────────┘
算法本质 :离中心越远,越暗。
二、核心算法:3 个数学概念
1. 到中心的距离
rust
let dx = x as f32 - cx; // 水平距离
let dy = y as f32 - cy; // 垂直距离
let dist = (dx * dx + dy * dy).sqrt(); // 欧氏距离
2. 归一化到 0~1
rust
let t = dist / max_dist;
// t = 0 → 正在中心
// t = 1 → 在对角
3. 二次衰减函数
rust
let factor = 1.0 - strength * t * t;
// factor = 1.0 → 不变(中心)
// factor = 0.0 → 全黑(对角,strength=1 时)

三、关键代码
rust
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];
}
}
四、前端效果展示


五、进阶:衰减函数选型
不同函数 → 不同暗角效果:
| 函数 | 效果 | 公式 |
|---|---|---|
| 二次(本文) | 边缘渐暗,自然 | 1 - t² |
| 线性 | 太硬,像切角 | 1 - t |
| 平方根 | 太亮 | 1 - √t |
| 三次方 | 边缘更暗 | 1 - t³ |
| 指数 | 可调衰减快慢 | 1 - e^(-kt) |
实际工程中二次最常用,效果最自然。
六、复古胶片:暖色 + 颗粒
vintage 模式在暗角基础上额外做 3 件事:
1. 暖色调(Sepia-like)
rust
r *= 1.1; // 红色增强
b *= 0.9; // 蓝色减弱
g *= 1.0; // 绿色不变
效果:偏黄、偏红 → 老电影味道。
2. 颗粒噪点(Grain)
rust
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 #算法