面部模糊补丁在导出时如何保持对齐
Source: Dev.to
模糊人脸在只需要静态演示时很容易实现。
当用户可以重新检测人脸、扩大填充、移动贴片、调整大小、禁用单个人脸、改变模糊强度,然后导出最终图像而不让所有内容漂移错位时,情况就变得更有趣了。
对我们来说,最稳妥的架构是 基于贴片(patch‑based)。
完整的配套指南请参见此处:
首先构建一张模糊的源图像
编辑器不是对每个贴片单独模糊,而是先对整张源图像进行模糊处理:
ctx.filter = `blur(${blurStrength}px)`;
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
ctx.filter = "none";
这样编辑器就拥有了一张可供所有检测到的人脸重复使用的模糊源图像。
实际优势
- 改变模糊强度只需重新生成一张源图像。
- 已有贴片保持其几何形状不变。
- 人脸交互保持快速响应。
每个人脸都是一个裁剪后的图像贴片
每个检测到的人脸都会成为指向模糊源图像的 FabricImage 贴片:
const patch = new FabricImage(this.blurredSourceElement!, {
left: region.left + region.width / 2,
top: region.top + region.height / 2,
width: region.width,
height: region.height,
cropX: region.left,
cropY: region.top,
});
编辑器并不是按需模糊任意矩形,而是显示预先计算好的模糊图像中的裁剪窗口。
几何形状与裁剪源必须同步移动
当用户拖动或缩放模糊贴片时,贴片的可视矩形与模糊源图像内部的裁剪窗口必须保持对齐。实现方式是将贴片归一化回真实几何形状,并在更新位置和尺寸的同时同步更新 cropX 与 cropY:
patch.set({
left: geometry.left + geometry.width / 2,
top: geometry.top + geometry.height / 2,
width: geometry.width,
height: geometry.height,
cropX: geometry.left,
cropY: geometry.top,
scaleX: 1,
scaleY: 1,
});
此重置将临时的拖拽/缩放变换转换回稳定的源图像坐标。
编辑前先处理填充
人脸检测的框通常过于紧凑,因此代码会在将检测结果转换为贴片之前,以可配置的比例扩大每个检测框。这为用户提供了更好的起始点,并减少了需要手动调整贴片以覆盖人脸边缘的次数。虽然是一个小步骤,却让模糊工具的使用体验大幅提升。
导出时应重新播放当前的贴片集合
用户导出时,编辑器会在原始尺寸上创建一个全新的 StaticCanvas,先添加未修改的底图,然后重新加入每个可见的模糊贴片及其当前的几何形状和裁剪源。保存的文件因此能够反映:
- 当前的模糊强度
- 当前的贴片位置
- 当前的贴片尺寸
- 当前的启用/禁用状态
所有内容都不依赖于屏幕视口。
为什么基于贴片的模糊有效
在真实编辑压力下,这种模型易于理解:
- 一张模糊源图像
- 多个可编辑的裁剪窗口
- 交互后归一化的几何形状
- 从源像素重新构建的导出
正是这些因素保证了即使经过多轮检测、调整和导出,模糊区域仍能保持对齐。
更多实现细节请参见: