目录

计算机视觉opencv实战二十九图像风格迁移

计算机视觉(opencv)实战二十九——图像风格迁移


OpenCV DNN 模块实现图像风格迁移:原理与代码详解

在计算机视觉中,图像风格迁移(Neural Style Transfer)是一项非常有趣的应用。它可以将一幅图像的风格迁移到另一幅图像上,比如把一张人脸图像转换成梵高的《星空》风格。本篇文章将通过 OpenCV 的 dnn 模块,结合预训练的 PyTorch 模型,实现一个简易的风格迁移程序。


1. 环境准备与图像读取

原图和结果:

https://i-blog.csdnimg.cn/direct/fab9d6dbb7c14ebab6973236e7133d44.png

首先,我们需要安装 OpenCV,并加载一张输入图像作为测试对象。


import cv2

# 获取输入图像
image = cv2.imread('face1.jpg')  # 读取本地图像
# 如果需要使用摄像头实时输入,可以改为:cap = cv2.VideoCapture(0)

# 显示原始图像
cv2.imshow('yuan tu', image)
cv2.waitKey(0)

要点:

  • cv2.imread() 用于读取本地图像,返回一个 NumPy 数组。
  • cv2.imshow() 可以显示图像,cv2.waitKey(0) 表示无限等待用户按键,否则窗口立即关闭。

2. 图像预处理:blobFromImage

在将图像输入到神经网络之前,我们需要将其转化为网络所需的输入格式。OpenCV 提供了 cv2.dnn.blobFromImage 函数,帮助我们完成这一过程。


(h, w) = image.shape[:2]
blob = cv2.dnn.blobFromImage(image, 1, (w, h), (0, 0, 0), swapRB=False, crop=False)

参数详解

  • 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缩放因子,将图像像素值缩放到神经网络所需范围,最终结果是 像素值 * scalefactor1.0
size(width, height)输出图像的大小(宽,高)。必须与模型训练时的输入尺寸匹配,否则可能导致推理失败或效果不佳。不缩放
mean(meanR, meanG, meanB)从每个通道减去的均值,用于归一化。可帮助消除光照影响。(0, 0, 0)
swapRBbool是否交换 R 和 B 通道。OpenCV 默认图像通道为 BGR,如果模型训练时使用 RGB,则需设为 TrueFalse
cropbool是否在调整大小后居中裁剪图像。如果设为 False,直接按比例缩放到目标尺寸。False
ddepthint输出数据的深度,常用 cv2.CV_32F(32 位浮点)。CV_32F

3. 加载预训练神经网络

接下来,我们需要加载一个预训练的神经网络模型。OpenCV 提供了 cv2.dnn.readNet,支持多种主流深度学习框架。


# 加载模型
net = cv2.dnn.readNet(r"model\starry_night.t7")

参数说明

  • model:模型文件,包含神经网络的权重和计算图。
  • config:可选配置文件,定义网络架构。
  • framework:可选参数,指定模型的框架(如 caffe、tensorflow、onnx 等),不指定时 OpenCV 会自动推断。
模型类型model 文件config 文件读取函数
Caffe*.caffemodel*.prototxtreadNetFromCaffe
TensorFlow*.pb*.pbtxtreadNetFromTensorFlow
Torch*.t7 / *.netreadNetFromTorch
Darknet*.weights*.cfgreadNetFromDarknet
OpenVINO*.bin*.xmlreadNetFromModelOptimizer
ONNX*.onnxreadNetFromONNX

这里使用的是一个基于 Torch 训练的风格迁移模型 starry_night.t7,它能将输入图像转换为梵高星空的风格。


4. 前向传播与结果计算

有了模型和输入数据,我们就可以进行前向推理:


# 设置输入
net.setInput(blob)
# 前向传播
out = net.forward()

此时 out 是一个四维张量,形状为 (B, C, H, W)

为了便于显示,我们需要对其进行 reshape、归一化和转置:


# 调整形状,去掉 batch 维度
out_new = out.reshape(out.shape[1], out.shape[2], out.shape[3])

# 归一化到 0~1 或 0~255 范围
cv2.normalize(out_new, out_new, norm_type=cv2.NORM_MINMAX)

# 转置回 HWC 格式(OpenCV 图像格式)
result = out_new.transpose(1, 2, 0)

5. 显示风格迁移后的图像

最后,将处理好的图像显示出来:


cv2.imshow('Stylized Image', result)
cv2.waitKey(0)

运行后,你将看到一幅带有梵高星空风格的图像。


6. 注意事项与优化建议

  1. 图像尺寸:预处理时的 (w, h) 应与模型输入尺寸一致,否则可能失真。
  2. 归一化处理:有些模型要求像素值范围在 [-1,1],需要调整 scalefactormean
  3. 性能优化:若处理视频流,可以把 cv2.imshow() 放在循环中,实时显示风格化结果。
  4. GPU 加速:可以用 net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA) 开启 GPU 推理,速度会提升显著。

总结

本文通过 OpenCV 的 dnn 模块实现了一个简易的风格迁移程序,完整流程包括:

  1. 读取输入图像
  2. 使用 blobFromImage 进行预处理
  3. 加载预训练模型
  4. 前向推理得到风格化结果
  5. 归一化与维度变换
  6. 显示结果图像

这种方法可以快速实现艺术风格迁移,同时可以推广到目标检测、人脸识别等其他深度学习任务。