人像背景虚化 (Portrait Bokeh)
给人像照片模拟单反相机大光圈镜头的景深虚化效果,自动检测人脸区域,分离人物与背景,生成自然的圆形光圈散景(bokeh)。
概述
本技能通过 Haar 级联分类器检测人脸区域,以此作为先验信息初始化 GrabCut 算法进行精确的前背景分割,随后使用圆盘形卷积核对背景区域施加镜头模糊(lens blur),模拟单反大光圈镜头特有的圆形散景效果。与普通高斯模糊不同,圆盘卷积核能产生更接近真实光学镜头的散景表现——高光区域呈现圆形光斑而非平滑的模糊过渡。
适用场景
- 手机拍摄的人像照片,需要模拟单反景深效果
- 背景杂乱的人像照片,需要突出主体
- 证件照、头像照片的背景柔化
- 需要模拟大光圈虚化效果的任意人像照片
- 希望获得专业人像摄影观感的照片
依赖
- Python >= 3.8
- numpy >= 1.20
- opencv-python-headless >= 4.5
安装依赖:
pip install numpy opencv-python-headless
使用流程
- 接收用户上传的人像照片或指定的图片路径
- 调用
scripts/portrait_bokeh.py进行处理 - 返回处理后的背景虚化图像
- 如有需要,可根据效果调整参数重新处理
命令行用法
python scripts/portrait_bokeh.py <input> [-o output] [--blur-size 31] [--blur-amount 1.0]
参数说明
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
input |
str | 必填 | 输入图片路径 |
-o, --output |
str | 自动生成 | 输出图片路径,默认在输入文件名后加 _bokeh |
--blur-size |
int | 31 | 模糊核大小(奇数),值越大虚化越强 |
--blur-amount |
float | 1.0 | 虚化强度系数,范围 0.0~3.0,控制整体模糊程度 |
参数调优指南
--blur-size:控制散景光斑大小。默认 31 适用于大多数手机人像。追求强烈虚化可设为 51~71,轻微柔化可设为 15~21。--blur-amount:控制虚化强度倍数。默认 1.0 为标准效果。0.5 为轻微虚化,2.0 以上为强烈虚化。
技术要点
人脸检测 (Haar Cascade)
使用 OpenCV 内置的 haarcascade_frontalface_default.xml 级联分类器检测人脸区域,作为后续分割的先验信息。
前景掩膜初始化
将检测到的人脸框按以下比例扩展为包含头肩的躯干区域,作为 GrabCut 的初始化掩膜:
- 向下扩展 50%(覆盖肩部和躯干)
- 向上扩展 30%(覆盖额头和头顶)
- 向左右各扩展 30%(覆盖肩膀两侧)
GrabCut 分割
使用 OpenCV 的 cv2.grabCut 算法(2 次迭代)对图像进行前景/背景分割。GrabCut 基于图割(Graph Cut)和高斯混合模型(GMM),能够精确地沿着人物轮廓提取前景掩膜。
掩膜精修
- 形态学闭运算:填充掩膜内部的小孔洞
- 形态学开运算:去除前景中的小噪点
圆盘形镜头模糊 (Lens Blur)
使用圆盘形(disk-shaped)卷积核替代高斯核,模拟真实镜头的散景表现:
y, x = np.ogrid[-r:r+1, -r:r+1]
kernel = (x² + y² <= r²).astype(float)
kernel /= kernel.sum()
圆盘核在处理高光点时会产生圆形光斑,更接近真实大光圈镜头的光学表现。
边缘羽化
对前景掩膜边缘施加高斯模糊进行羽化处理,避免人物轮廓处出现生硬的虚实分界线,使虚化过渡更加自然。
无人脸回退策略
当未检测到人脸时,以图像中心 60% 区域作为 GrabCut 初始化前景,对四周背景进行虚化处理。
常见调参
- 虚化效果太弱:增大
--blur-size至 51~71,或提高--blur-amount至 1.5~2.0 - 人物边缘有残留模糊:检查人脸检测是否准确,可尝试调整输入图片方向
- 人物部分被虚化:可能 GrabCut 分割不完整,确保人像主体在画面中占比较大
- 虚化过渡不自然:当前已做边缘羽化,如仍有生硬感可适当增大羽化核
- 未检测到人脸:脚本会自动回退为中心区域前景模式,仍可产生背景虚化效果
文件结构
portrait-bokeh/
├── SKILL.md # 技能说明文档(本文件)
└── scripts/
└── portrait_bokeh.py # 人像背景虚化算法实现