计算机视觉(opencv)实战二十九——图像风格迁移
OpenCV DNN 模块实现图像风格迁移:原理与代码详解
在计算机视觉中,图像风格迁移(Neural Style Transfer)是一项非常有趣的应用。它可以将一幅图像的风格迁移到另一幅图像上,比如把一张人脸图像转换成梵高的《星空》风格。本篇文章将通过 OpenCV 的 dnn
模块,结合预训练的 PyTorch 模型,实现一个简易的风格迁移程序。
1. 环境准备与图像读取
原图和结果:
首先,我们需要安装 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:宽度
参数名 | 类型 | 说明 | 默认值 |
---|---|---|---|
image | numpy.ndarray | 输入图像,支持单张图像或多张图像列表。 | 必填 |
scalefactor | float | 缩放因子,将图像像素值缩放到神经网络所需范围,最终结果是 像素值 * scalefactor 。 | 1.0 |
size | (width, height) | 输出图像的大小(宽,高)。必须与模型训练时的输入尺寸匹配,否则可能导致推理失败或效果不佳。 | 不缩放 |
mean | (meanR, meanG, meanB) | 从每个通道减去的均值,用于归一化。可帮助消除光照影响。 | (0, 0, 0) |
swapRB | bool | 是否交换 R 和 B 通道。OpenCV 默认图像通道为 BGR,如果模型训练时使用 RGB,则需设为 True 。 | False |
crop | bool | 是否在调整大小后居中裁剪图像。如果设为 False ,直接按比例缩放到目标尺寸。 | False |
ddepth | int | 输出数据的深度,常用 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 | *.prototxt | readNetFromCaffe |
TensorFlow | *.pb | *.pbtxt | readNetFromTensorFlow |
Torch | *.t7 / *.net | 无 | readNetFromTorch |
Darknet | *.weights | *.cfg | readNetFromDarknet |
OpenVINO | *.bin | *.xml | readNetFromModelOptimizer |
ONNX | *.onnx | 无 | readNetFromONNX |
这里使用的是一个基于 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. 注意事项与优化建议
图像尺寸:预处理时的
(w, h)
应与模型输入尺寸一致,否则可能失真。归一化处理:有些模型要求像素值范围在 [-1,1],需要调整
scalefactor
和mean
。性能优化:若处理视频流,可以把
cv2.imshow()
放在循环中,实时显示风格化结果。GPU 加速:可以用
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
和net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)
开启 GPU 推理,速度会提升显著。
总结
本文通过 OpenCV 的 dnn
模块实现了一个简易的风格迁移程序,完整流程包括:
读取输入图像
使用
blobFromImage
进行预处理加载预训练模型
前向推理得到风格化结果
归一化与维度变换
显示结果图像
这种方法可以快速实现艺术风格迁移,同时可以推广到目标检测、人脸识别等其他深度学习任务。