计算机视觉(opencv)实战三十——摄像头实时风格迁移,附多种风格转换
图像风格迁移(Neural Style Transfer)是计算机视觉中非常有趣的一个应用,它能够将一张图像的风格“迁移”到另一张图像上,比如把摄像头捕获的视频实时转换为梵高的《星空》风格。本篇文章将通过 OpenCV 的dnn模块和预训练的 Torch 模型,来实现。
OpenCV DNN 实时风格迁移:原理与完整代码
图像风格迁移(Neural Style Transfer)是计算机视觉中非常有趣的一个应用,它能够将一张图像的风格“迁移”到另一张图像上,比如把摄像头捕获的视频实时转换为梵高的《星空》风格。本篇文章将通过 OpenCV 的 dnn 模块和预训练的 Torch 模型,来实现实时风格迁移。
1. 环境准备与摄像头读取
相比于处理单张图片,我们需要使用 cv2.VideoCapture() 打开摄像头并逐帧读取输入:
import cv2
# 打开默认摄像头
cap = cv2.VideoCapture(0)
# 加载预训练的风格迁移模型
net = cv2.dnn.readNetFromTorch(r'.\model\starry_night.t7')
# 检查摄像头是否成功打开
if not cap.isOpened():
print("摄像头启动失败")
exit()
要点:
-
cv2.VideoCapture(0)表示打开默认摄像头,0 通常是电脑的内置摄像头。 -
net = cv2.dnn.readNetFromTorch()用来加载 Torch 格式的风格迁移模型。
2. 实时图像处理与 blob 构建
在循环中逐帧读取图像,并将其转换为神经网络可以接受的输入格式:
while True:
ret, frame = cap.read() # 读取一帧
if not ret:
print("不能读取摄像头")
break
(h, w) = frame.shape[:2]
# 预处理:转换成符合网络输入的四维blob
blob = cv2.dnn.blobFromImage(
frame,
scalefactor=1,
size=(w, h),
mean=(0, 0, 0),
swapRB=True,
crop=False
)
这里用到了 cv2.dnn.blobFromImage(),它的参数含义如下:
-
image:输入图像,必须是 NumPy 数组。
-
scalefactor:缩放因子,对像素值进行乘法缩放,默认 1 表示不缩放。
-
size:调整图像尺寸,必须与模型训练时的输入大小一致。
-
mean:通道均值,用于减去图像的平均值以进行归一化。设置为
(0,0,0)表示不做均值减法。 -
swapRB:是否交换 R 和 B 通道。因为 OpenCV 默认是 BGR 通道,而许多深度学习模型训练时采用的是 RGB。
-
crop:是否在缩放后裁剪图像,通常设为 False。
最终返回的 blob 是一个 四维张量,格式为 NCHW:
-
N:批量大小(batch size)
-
C:通道数(通常 3)
-
H:高度
-
W:宽度
| 参数名 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| image | numpy.ndarray |
输入图像 | 必填 |
| scalefactor | float |
缩放因子,像素值会乘以该值 | 1.0 |
| size | (w,h) |
调整图像到网络需要的尺寸 | 不缩放 |
| mean | (R,G,B) |
每个通道减去的均值 | (0,0,0) |
| swapRB | bool |
是否交换 R 和 B 通道(BGR → RGB) | False |
| crop | bool |
是否居中裁剪 | False |
| ddepth | int |
输出数据类型 | CV_32F |
3. 前向传播与风格化处理
将 blob 设置为网络输入,并执行前向传播得到风格化结果:
# 推理
net.setInput(blob)
out = net.forward()
# 调整输出形状
out_new = out.reshape(out.shape[1], out.shape[2], out.shape[3])
cv2.normalize(out_new, out_new, norm_type=cv2.NORM_MINMAX)
result = out_new.transpose(1, 2, 0)
关键步骤说明:
-
reshape:去掉 batch 维度,从(1,C,H,W)→(C,H,W)。 -
cv2.normalize:将像素值归一化到指定范围(0-1 或 0-255)。 -
transpose:将通道维度换到最后,得到 HWC 格式,方便用 OpenCV 显示。
4. 显示实时结果与按键控制
将风格化结果显示在窗口中,并监听键盘按键,实现实时预览和退出功能:
cv2.imshow(winname='result', mat=result)
key_pressed = cv2.waitKey(1)
if key_pressed == 27: # ESC 键退出
break
cap.release()
cv2.destroyAllWindows()
要点:
-
cv2.imshow()每次显示最新的风格化帧。 -
cv2.waitKey(1)设置显示刷新频率,参数越小延迟越低。 -
key_pressed == 27判断用户是否按下 ESC 键,如果按下就结束循环。
5. 模型加载函数速查表
| 模型类型 | model 文件 | config 文件 | 调用函数 |
|---|---|---|---|
| Caffe | .caffemodel |
.prototxt |
cv2.dnn.readNetFromCaffe() |
| TensorFlow | .pb |
.pbtxt |
cv2.dnn.readNetFromTensorFlow() |
| Torch | .t7 或 .net |
无 | cv2.dnn.readNetFromTorch() |
| Darknet (YOLO) | .weights |
.cfg |
cv2.dnn.readNetFromDarknet() |
| OpenVINO | .bin |
.xml |
cv2.dnn.readNetFromModelOptimizer() |
| ONNX | .onnx |
无 | cv2.dnn.readNetFromONNX() |
6. 运行效果与优化建议
运行程序后,你将看到摄像头捕获的视频实时被转换成梵高的星空风格,边移动边变化,效果十分炫酷。
优化建议:
-
提高帧率:使用更高性能的 GPU,可调用
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)和net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)。 -
降低分辨率:适当缩小
size,提升推理速度。 -
多模型切换:可以加载多种风格模型,按键切换不同艺术风格。
扩展:按1/2/3/4实现多种风格转换:
import cv2 # 定义可选风格模型 style_models = { '1': r'.\model\starry_night.t7', # 梵高星空 '2': r'.\model\la_muse.t7', # 莫奈风格 '3': r'.\model\the_scream.t7', # 蒙克呐喊 '4': r'.\model\udnie.t7' # 抽象画风格 } # 默认加载第一种风格 current_model_key = '1' net = cv2.dnn.readNetFromTorch(style_models[current_model_key]) cap = cv2.VideoCapture(0) if not cap.isOpened(): print("摄像头启动失败") exit() print("按键切换风格:1=星空, 2=莫奈, 3=呐喊, 4=抽象, ESC=退出") while True: ret, frame = cap.read() if not ret: print("不能读取摄像头") break (h, w) = frame.shape[:2] blob = cv2.dnn.blobFromImage( frame, scalefactor=1, size=(w, h), mean=(0, 0, 0), swapRB=True, crop=False ) net.setInput(blob) out = net.forward() out_new = out.reshape(out.shape[1], out.shape[2], out.shape[3]) cv2.normalize(out_new, out_new, norm_type=cv2.NORM_MINMAX) result = out_new.transpose(1, 2, 0) cv2.imshow('Stylized Result', result) key_pressed = cv2.waitKey(1) if key_pressed == 27: # ESC退出 break elif chr(key_pressed & 0xFF) in style_models.keys(): # 切换风格模型 current_model_key = chr(key_pressed & 0xFF) print(f"切换到风格:{current_model_key}") net = cv2.dnn.readNetFromTorch(style_models[current_model_key]) cap.release() cv2.destroyAllWindows()
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)