前言
相信很多接触计算机视觉的同学都听过风格迁移------ 这项技术能把一张名画的艺术风格 "移植" 到普通照片上,让你的随手拍秒变世界名画同款画风。
很多同学会觉得风格迁移需要搭建复杂的深度学习网络、准备 GPU 训练环境、处理海量数据集,门槛很高。但其实,我们只用 OpenCV 自带的DNN 深度神经网络模块,无需安装 TensorFlow/PyTorch,CPU 就能运行,几十行代码就能实现高质量的图像风格迁移,新手也能零门槛上手。
先给大家看一下本文代码最终实现的效果,左侧是我输入的氛围感人像原图,右侧是经过抽象艺术风格迁移后的输出结果,完美复刻了油画的笔触质感与色彩张力,同时完整保留了人像的核心轮廓与特征:

本文就带大家从零实现基于 OpenCV DNN 的图像风格迁移,包含完整可运行代码、核心 API 逐参详解、踩坑避坑指南、预训练模型资源,看完就能直接跑出和上图一致的效果。
一、核心原理简介
我们本次使用的是快速神经风格迁移(Fast Neural Style Transfer) 方案,出自论文《Perceptual Losses for Real-Time Style Transfer and Super-Resolution》,和传统的迭代优化风格迁移相比,它有两大核心优势:
- 提前训练好针对特定风格的模型,推理时只需一次前向传播,速度极快,CPU 也能毫秒级出结果;
- 无需复杂的深度学习框架,OpenCV 的 DNN 模块可直接加载预训练模型,环境配置极简。
简单来说,整个流程就是:
- 读取输入的内容图像,做预处理适配神经网络输入格式;
- 加载对应风格的预训练模型;
- 把预处理后的图像输入模型,执行前向传播得到风格化结果;
- 对模型输出的结果做后处理,还原成可显示的图像格式。
二、环境准备
本文的方案环境配置极其简单,仅需安装基础的 OpenCV 库即可:
# 安装opencv-python,建议4.0及以上版本,对DNN模块支持更完善
pip install opencv-python==4.5.5.62
- Python 版本:建议 3.7~3.10,兼容性最佳
- 运行环境:无需 GPU,普通家用电脑 CPU 即可流畅运行
三、核心 API 详解
本文代码核心用到了 OpenCV DNN 模块的两个核心 API,这里先给大家讲透每个参数的含义,避免后续踩坑。
3.1 cv2.dnn.blobFromImage:图像预处理函数
这个函数的作用是把普通的 OpenCV 图像,转换成神经网络能接受的输入格式(四维 blob 块),是深度学习推理前的核心预处理步骤。
函数原型:
blob = cv2.dnn.blobFromImage(
image,
scalefactor=None,
size=None,
mean=None,
swapRB=None,
crop=None
)
各参数详解:
| 参数名 | 作用说明 | 本文取值 |
|---|---|---|
| image | 输入的原始图像,cv2.imread 读取的结果 | 人像原图 |
| scalefactor | 像素值缩放因子,每个像素值会乘以该系数,默认值为 1 | 1(不缩放像素值) |
| size | 输出 blob 的宽高,对应神经网络要求的输入尺寸 | (w, h) 和原图尺寸一致 |
| mean | 每个通道要减去的均值,用于消除光照影响,格式为 (B,G,R) | (0, 0, 0) 不做均值减法 |
| swapRB | 是否交换 R 通道和 B 通道。OpenCV 默认是 BGR 通道顺序,很多模型训练用的是 RGB,需通过该参数适配 | False 不交换通道 |
| crop | 调整尺寸后是否居中裁剪 | False 不裁剪,保持原图比例 |
返回值blob是一个四维张量,格式为N(批次)×C(通道数)×H(高度)×W(宽度),这是深度学习框架通用的输入格式。
3.2 cv2.dnn.readNetFromTorch:Torch 模型加载函数
我们使用的预训练风格模型是 Torch 框架的.t7格式,通过这个函数可以直接加载模型,无需安装 Torch/PyTorch 环境。
函数原型:
net = cv2.dnn.readNetFromTorch(modelPath)
- 参数
modelPath:预训练模型.t7文件的路径 - 返回值
net:加载完成的神经网络模型对象,后续可直接用于推理
除此之外,OpenCV DNN 模块还支持 TensorFlow、Caffe、ONNX、Darknet 等几乎所有主流框架的模型,兼容性极强,大家后续可以自行拓展。
四、完整代码逐段解析
下面我们把完整代码拆分成 6 个模块,逐行讲解每一步的作用,大家可以跟着一步步写,也可以直接复制完整代码运行,就能跑出和前文一致的效果。
4.1 库导入与图像读取
首先导入 OpenCV 库,读取我们要风格化的内容图像,并显示原图,确认图像读取正常。
import cv2
# 读取输入图像(内容图),这里替换成你自己的图片路径
image = cv2.imread('test_man.png')
# 显示输入的原图
cv2.imshow('yuan tu', image)
# 等待按键按下后再执行后续代码,0表示无限等待
cv2.waitKey(0)
⚠️ 踩坑提醒:如果cv2.imread返回 None,大概率是图像路径错误、文件名拼写错误,或者路径包含中文,建议优先使用英文绝对路径。
4.2 图像预处理(生成神经网络输入 blob)
获取图像尺寸,通过cv2.dnn.blobFromImage把原图转换成神经网络接受的输入格式。
'''-----------图片预处理-------------------'''
# 获取图像的高度h和宽度w
(h, w) = image.shape[:2]
# 生成神经网络输入的四维blob
blob = cv2.dnn.blobFromImage(
image,
scalefactor=1,
size=(w, h),
mean=(0, 0, 0),
swapRB=False,
crop=False
)
这里我们保持了和原图一致的尺寸,无需固定输入大小,预训练模型支持任意尺寸的图像输入,适配性极强。
4.3 预训练模型加载
加载我们提前下载好的风格迁移预训练模型,本文提供了 6 种经典艺术风格的模型,大家可以按需切换。本次展示的效果,使用的是康定斯基《Composition VII》抽象艺术风格模型。
'''''''''''加载模型'''''''''''''''''
# 加载预训练的风格迁移模型,本次效果使用的抽象艺术风格
net=cv2.dnn.readNetFromTorch(r'.\model\composition_vii.t7')
# 其他风格模型,取消注释即可切换
# net=cv2.dnn.readNetFromTorch(r'.\model\la_muse.t7') # 缪斯艺术风格
# net=cv2.dnn.readNetFromTorch(r'.\model\starry_night.t7') # 梵高星空风格
# net=cv2.dnn.readNetFromTorch(r'.\model\candy.t7') # 糖果色彩风格
# net=cv2.dnn.readNetFromTorch(r'.\model\the_scream.t7') # 呐喊风格
# net=cv2.dnn.readNetFromTorch(r'.\model\udnie.t7') # 抽象涂鸦风格
⚠️ 路径提醒:Windows 系统路径建议加r前缀,避免反斜杠转义问题;建议在项目根目录新建model文件夹,把所有.t7模型文件放进去,路径对应即可。
4.4 模型推理(前向传播)
把预处理好的 blob 输入模型,执行前向传播,得到风格化后的输出结果。
# 设置神经网络的输入
net.setInput(blob)
# 执行前向传播,得到模型输出结果
out = net.forward()
这里的out是一个四维张量,格式为1×3×H×W,分别对应批次、通道数、高度、宽度,无法直接用 OpenCV 显示,需要做后处理。
4.5 推理结果后处理
这一步是新手最容易踩坑的地方,我们需要把模型输出的四维张量,还原成 OpenCV 能显示的图像格式,分为 3 步:
# ======输出处理=======
# 步骤1:4维降3维,忽略批次维度,把BCHW格式转为CHW格式
out_new = out.reshape(out.shape[1], out.shape[2], out.shape[3])
# 步骤2:归一化处理,把像素值缩放到0-1之间,适配cv2.imshow的float图像显示要求
cv2.normalize(out_new, out_new, norm_type=cv2.NORM_MINMAX)
# 步骤3:维度转置,把CHW(通道×高度×宽度)转为HWC(高度×宽度×通道),这是OpenCV要求的图像格式
result = out_new.transpose(1, 2, 0)
⚠️ 关键说明:
- OpenCV 的
cv2.imshow显示图像,要求格式必须是H×W×C,而模型输出是C×H×W,必须通过transpose转置维度,否则会报错或显示异常; - 模型输出的像素值不是 0-255 的整数,需要通过
normalize缩放到 0-1 之间,才能正常显示。
4.6 结果显示与资源释放
最后显示风格化后的图像,释放所有窗口资源。
# 显示风格转换后的图像
cv2.imshow('Stylized Image', result)
# 等待按键按下
cv2.waitKey(0)
# 释放所有OpenCV窗口
cv2.destroyAllWindows()
五、完整可直接运行代码
这里给大家整理了无注释精简版,大家可以直接复制运行,替换图片和模型路径即可:
import cv2
# 1. 读取输入图像
image = cv2.imread('test_man.png')
cv2.imshow('yuan tu', image)
cv2.waitKey(0)
# 2. 图片预处理
(h, w) = image.shape[:2]
blob = cv2.dnn.blobFromImage(image, scalefactor=1, size=(w, h), mean=(0, 0, 0), swapRB=False, crop=False)
# 3. 加载预训练模型
net=cv2.dnn.readNetFromTorch(r'.\model\composition_vii.t7')
# 4. 模型推理
net.setInput(blob)
out = net.forward()
# 5. 输出结果后处理
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)
# 6. 显示结果
cv2.imshow('Stylized Image', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
六、效果细节说明
本次我使用的是康定斯基的《Composition VII》抽象艺术风格模型,针对人像照片做风格迁移,最终效果有两个核心亮点:
- 风格还原度高:完美复刻了原作的色彩碰撞、几何线条和油画笔触质感,整体艺术氛围拉满,和原作的艺术风格高度统一;
- 内容保留完整:人像的五官轮廓、动作姿态、光影层次都完整保留,没有因为风格迁移出现内容失真、五官错位的问题,实现了风格与内容的平衡。
大家可以根据自己的图片内容,选择不同的风格模型:人像照片推荐使用 la_muse、composition_vii 风格;风景照片推荐使用 starry_night、candy 风格;街拍照片推荐使用 udnie、the_scream 风格。
七、预训练模型下载
本文用到的 6 种经典风格预训练模型,均来自官方开源项目,大家可以通过以下链接下载:
- 官方项目地址:https://github.com/jcjohnson/fast-neural-style
- 模型直链下载:
- la_muse.t7:https://cs.stanford.edu/people/jcjohns/fast-neural-style/models/la_muse.t7
- starry_night.t7:https://cs.stanford.edu/people/jcjohns/fast-neural-style/models/starry_night.t7
- candy.t7:https://cs.stanford.edu/people/jcjohns/fast-neural-style/models/candy.t7
- the_scream.t7:https://cs.stanford.edu/people/jcjohns/fast-neural-style/models/the_scream.t7
- udnie.t7:https://cs.stanford.edu/people/jcjohns/fast-neural-style/models/udnie.t7
- composition_vii.t7:https://cs.stanford.edu/people/jcjohns/fast-neural-style/models/composition_vii.t7
下载完成后,把所有.t7文件放到项目的model文件夹下即可。
八、常见踩坑与解决方案
问题 1:图像读取失败,imread 返回 None
- 原因:路径包含中文、文件名拼写错误、相对路径错误
- 解决方案:使用英文绝对路径,比如
r'C:\project\test_man.png',确保文件存在
问题 2:模型加载失败,报错 "Can't open model file"
- 原因:模型路径错误,或者模型文件下载不完整
- 解决方案:检查路径拼写,重新下载模型文件,确保文件大小正常
问题 3:imshow 显示黑屏 / 全白 / 异常图像
- 原因 1:维度没有转置,CHW 没有转为 HWC
- 解决方案:必须执行
transpose(1, 2, 0)转换维度 - 原因 2:像素值没有归一化,超出 0-1 范围
- 解决方案:用
cv2.NORM_MINMAX把像素值缩放到 0-1 之间
问题 4:运行速度慢,卡顿
- 原因:默认使用 CPU 推理,大尺寸图像速度较慢
- 解决方案:
- 缩小输入图像尺寸,比如把 size 设为 (640, 480)
- 开启 OpenCL 加速,添加代码
net.setPreferableTarget(cv2.dnn.DNN_TARGET_OPENCL)
九、拓展延伸
- 批量处理图像:可以通过 os 模块遍历文件夹,批量处理文件夹内的所有图片,自动保存风格化后的结果;
- 视频风格迁移:通过 cv2.VideoCapture 读取视频,逐帧做风格迁移,再写入视频文件,实现视频画风转换;
- 实时摄像头风格迁移:调用电脑摄像头,实时处理每一帧画面,实现实时滤镜效果;
- 更多风格模型:可以自己训练专属风格的模型,导出为 t7/onnx 格式,用本文的代码直接加载使用。
总结
本文带大家用几十行 Python 代码,基于 OpenCV DNN 模块实现了高质量的图像风格迁移,无需复杂的深度学习环境,CPU 就能运行,新手也能零门槛上手,最终实现的人像风格迁移效果也非常惊艳。
OpenCV 的 DNN 模块给我们提供了极其便捷的深度学习推理方案,无需关注复杂的网络结构,只需做好预处理和后处理,就能快速落地深度学习应用,非常适合计算机视觉入门和快速项目开发。
如果本文对你有帮助,欢迎点赞、收藏、评论,有任何问题都可以在评论区留言,我会一一解答!