Enhance 自动增强
Enhance 做的是自动色阶拉伸:找出每个通道实际用到的最小值和最大值,
把这个区间线性拉伸到满量程 0–255。用来抢救褪色、发灰、欠曝的照片。
node.cache();
node.filters([Konva.Filters.Enhance]);
node.enhance(1); // 0 ~ 1,默认 0(0 表示不拉伸)
enhance 是拉伸的程度:0 完全不动,1 拉满,中间值按比例插值。
它对多数照片毫无作用
这是使用这个滤镜前必须知道的一点,而且很容易白白排查半天。
Enhance 的前提是"图像没有占满整个动态范围"。
如果某个通道的实际范围已经是 0–255,那就没有任何可拉伸的空间,
滤镜什么也不做。
本站用三张示例图做过实测,逐像素比对滤镜前后的差异:
| 图片 | 通道最小值 | 通道最大值 | enhance(1) 改变的像素数 |
|---|---|---|---|
lion.png | 0/0/0 | 255/255/255 | 0 |
darth-vader.jpg | 0/0/0 | 255/255/255 | 0 |
yoda.jpg | 0/0/0 | 255/255/255 | 0 |
三张图一个像素都没变。原因就是它们各自的通道都已经触及了 0 和 255 两端—— 只要图里有一个纯黑像素和一个纯白像素,这个通道就没有拉伸余地了。
绝大多数正常拍摄或设计出来的图片都满足这个条件。所以如果你加了 Enhance
发现毫无变化,这多半不是 bug,是你的图本来就不需要它。
上面的演示特意把原图以 32% 不透明度叠在中灰底上,
把通道范围压到约 94–176,Enhance 才有东西可以拉伸——
这时 enhance(1) 改变了 9421 个像素,最大差值 94。
常见问题
怎么判断一张图适不适合用 Enhance?
算一下通道的实际范围。范围越窄,Enhance 的效果越明显:
const ctx = node.getLayer().getContext()._context;
const d = ctx.getImageData(0, 0, w, h).data;
let min = [255, 255, 255], max = [0, 0, 0];
for (let i = 0; i < d.length; i += 4) {
if (d[i + 3] === 0) continue; // 跳过全透明像素
for (let k = 0; k < 3; k++) {
if (d[i + k] < min[k]) min[k] = d[i + k];
if (d[i + k] > max[k]) max[k] = d[i + k];
}
}
console.log('范围', min, max);
如果 min 接近 0 且 max 接近 255,别用 Enhance,
改用 Contrast 手动调。
单个异常像素会毁掉效果吗?
会,而且这是这类"自动拉伸"算法的通病。
Enhance 取的是极值,不是分位数。一张整体灰蒙蒙的图,
只要角落里有一个纯黑的水印像素和一个纯白的高光点,
算出来的范围就是 0–255,滤镜直接失效。
专业图像软件的自动色阶通常会裁掉最暗和最亮的 0.5% 再算范围,
Enhance 没有这一步。遇到这种情况只能自己写
自定义滤镜,用分位数代替极值。
Enhance 和 Contrast 该选哪个?
Enhance 是自适应的,它根据每张图自己的情况决定拉伸多少,
适合批量处理一堆来源不一的图片,不需要逐张调参。
Contrast 是固定量的,同一个参数对所有图施加同样的变换,
适合你已经知道想要什么效果、要保持一致风格的场景。
一个实际的组合是:先 Enhance 把各图拉到统一的动态范围,
再用固定的 Contrast 施加统一的风格。
透明区域会影响结果吗?
会。Enhance 统计范围时如果把全透明像素也算进去,
那些像素的 RGB 通常是 0,会把最小值拉到 0,从而让滤镜失效。
带透明背景的 PNG 用 Enhance 常常没效果,这是一个原因。
如果必须处理这类图,先把它画到一个不透明的底色上再缓存。
与其他方案的取舍
自动增强这件事,Konva 的 Enhance 只是最基础的一档。
只想要"看起来更清楚" → 先试 Enhance,免费且不需要调参,
对褪色的老照片、扫描件、低质量截图效果不错。
要可控、要统一风格 → Contrast +
Brightness 手动组合。
多花一点调参时间,换来所有图表现一致。
要专业级的自动色阶 → Enhance 的极值算法不够稳,
自己写自定义滤镜实现分位数裁剪,或者干脆在服务端用
ImageMagick / Sharp 之类的工具预处理——
它们的 auto-level 实现要成熟得多,而且不占用户的 CPU。
只是想让图片在页面上更亮眼 → 别用滤镜,用 CSS。
CSS 滤镜字符串走浏览器原生实现,
不需要 cache(),也不占 JS 主线程。