当前位置: 首页 > news >正文

计算机视觉(opencv)实战三十——摄像头实时风格迁移,附多种风格转换


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]# 预处理:转换成符合网络输入的四维blobblob = 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:宽度

参数名类型说明默认值
imagenumpy.ndarray输入图像必填
scalefactorfloat缩放因子,像素值会乘以该值1.0
size(w,h)调整图像到网络需要的尺寸不缩放
mean(R,G,B)每个通道减去的均值(0,0,0)
swapRBbool是否交换 R 和 B 通道(BGR → RGB)False
cropbool是否居中裁剪False
ddepthint输出数据类型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 键退出breakcap.release()
cv2.destroyAllWindows()

要点:

  • cv2.imshow() 每次显示最新的风格化帧。

  • cv2.waitKey(1) 设置显示刷新频率,参数越小延迟越低。

  • key_pressed == 27 判断用户是否按下 ESC 键,如果按下就结束循环。


5. 模型加载函数速查表

模型类型model 文件config 文件调用函数
Caffe.caffemodel.prototxtcv2.dnn.readNetFromCaffe()
TensorFlow.pb.pbtxtcv2.dnn.readNetFromTensorFlow()
Torch.t7.netcv2.dnn.readNetFromTorch()
Darknet (YOLO).weights.cfgcv2.dnn.readNetFromDarknet()
OpenVINO.bin.xmlcv2.dnn.readNetFromModelOptimizer()
ONNX.onnxcv2.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退出breakelif 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()

http://www.dtcms.com/a/394189.html

相关文章:

  • 【数据分享】《中国农村统计年鉴》(1985-2024年)全pdf和excel
  • 2025年中国研究生数学建模竞赛“华为杯”C题 围岩裂隙精准识别与三维模型重构完整高质量成品 思路 代码 结果分享!全网首发!
  • [Linux]文件与 fd
  • FFmpeg 深入精讲(二)FFmpeg 初级开发
  • 睡眠脑电技术文章大纲
  • 计算机等级考试Python语言程序设计备考•第二练
  • 【Python】面向对象(一)
  • Jetson 设备监控利器:Jtop 使用方式(安装、性能模式、常用页面)
  • 「数据获取」《商洛统计年鉴》(2001-2024)
  • 链表的探索研究
  • 2025年工程项目管理软件全面测评
  • JAVA算法练习题day17
  • Nacos:服务注册和配置中心
  • Linux 命令行快捷键
  • EasyClick JavaScript Number
  • LeetCode:42.将有序数组转化为二叉搜索树
  • 海外代理IP网站有哪些?高并发场景海外代理IP服务支持平台
  • JavaScript数据交互
  • 11.2.5 自定义聊天室
  • 力扣:字母异味词分组
  • Linux视频学习笔记
  • 2014/12 JLPT听力原文 问题四
  • Elasticsearch面试精讲 Day 21:地理位置搜索与空间查询
  • 华为数字化实战指南:从顶层设计到行业落地的系统方法论
  • 外部 Tomcat 部署详细
  • 【回文数猜想】2022-11-9
  • 216. 组合总和 III
  • Bugku-请攻击这个压缩包
  • 2. NumPy数组属性详解:形状、维度与数据类型
  • 【css特效】:实现背景色跟随图片相近色处理