前言
DNN(Deep Neural Network,深度神经网络)风格迁移是一种利用深度神经网络技术,将一张图像的风格(如色彩、笔触、纹理等)迁移到另一张图像(内容图像)上,使内容图像呈现出风格图像的风格,同时保留其自身内容的技术。
一、DNN风格迁移
DNN模块是 OpenCV 中专门用来实现 DNN(Deep Neural Networks,深度神经网络) 模块的相关功能,其作用是载入别的深度学习框架(如 TensorFlow、Caffe、Torch 等)中已经训练好的模型,然后用该模型完成预测等工作。 DNN模块的特点:
● 轻量: OpenCV 的深度学习模块只实现了模型推理功能,不涉及模型训练,这使得相关程序非常精简,加速了安装和编译过程。
● 外部依赖性低:重新实现一遍深度学习框架使得 DNN 模块对外部依赖性极低,极大地方便了深度学习应用的部署。
● 方便:在原有 OpenCV 开发程序的基础上,通过 DNN 模块可以非常方便地加入对神经网络推理的支持。
● 集成:若网络模型来自多个框架,如一个来自 TensorFlow,另外一个来自 Caffe,则 DNN 模块可以方便地对网络进行整合。
● 通用性:DNN 模块提供了统一的接口来操作网络模型,内部做的优化和加速适用于所有网络模型格式,支持多种设备和操作系统。
DNN 模块使用的主要函数及流程:
1、图像预处理的功能 将需要处理的图像转换成可以传入人工神经网络的数据形式。 DNN 模块中的函数 blobFromlmage 完成图像预处理,从原始图像构建一个符合人工神经网络输入格式的四维块。 它通过调整图像尺寸和裁图像、减均值、按比例因子缩放、交换 B 通道和R通道等可选操作完成对图像的预处理,得到符合人工神经网络输入的目标值。
效果展示:
使用不同的已训练好的模型可以得到不同的效果。
2、DNN风格迁移模型
模型下载地址链接: https://github.com/jcjohnson/fast-neural-style/blob/master/models/download_style_transfer_models.sh
这里跳转网站速度会很慢,因为GitHub是国外网站。
二、DNN 风格迁移的使用
1、对图片做DNN风格迁移
(1)读取并显示即将做风格迁移的图片
import cv2
# 读取输入图像
image = cv2.imread('car.png')
# 显示输入图像
cv2.imshow('yuan tu', image)
cv2.waitKey(0)
(2)图片预处理
需要对图片做预处理,使神经网络能识别出图片。
函数cv2.dnn.blobFromImage:实现图像预处理,从原始图像构建一个符合人工神经网络输入格式的四维块。
blob = cv2.dnn.blobFromImage(image, scalefactor=None, size=None, mean=None, swapRB=None, crop=None)
参数:
image:表示输入图像。
scalefactor:表示对图像内的数据进行缩放的比例因子。具体运算是每个像素值*scalefactor,该值默认为 1。
size:用于控制blob的宽度、高度。
mean:表示从每个通道减去的均值。 (0, 0, 0):表示不进行均值减法。即,不对图像的B、G、R通道进行任何减法操作。
若输入图像本身是B、G、R通道顺序的,并且下一个参数swapRB值为True,
则mean值对应的通道顺序为R、G、B。· opencv BGR RGB
swapRB:表示在必要时交换通道的R通道和B通道。一般情况下使用的是RGB通道。而OpenCV通常采用的是BGR通道。
因此可以根据需要交换第1个和第3个通道。该值默认为 False。
crop:布尔值,如果为 True,则在调整大小后进行居中裁剪。
返回值:blob: 表示在经过缩放、裁剪、减均值后得到的符合人工神经网络输入的数据。该数据是一个四维数据,
布局通常使用N(表示batch size)、C(图像通道数,如RGB图像具有三个通道)、H(图像高度)、W(图像宽度)表示
(h, w) = image.shape[:2] # 获取图像尺寸
blob = cv2.dnn.blobFromImage(image, 1, (w, h), (0, 0, 0), swapRB=False, crop=False)
(3)读取加载模型
加载模型net=cv2.dnn.readNet( model[, config[, framework]] )
各参数的含义如下:
model:神经网络的实际结构和功能,它定义了数据如何通过网络流动,如何进行训练,如何进行推理。
config:一组超参数和设置,帮助控制模型的行为,包括网络架构、训练过程、优化器等内容。
framework:DNN框架,可省略,DNN模块会自动推断框架种类。
net:返回值,返回网络模型对象。
支持的模型格式有Torch,TensorFlow,Caffe,DartNet,ONNX和Intel OpenVINO
model参数 | config参数 | framework参数 | 函数名称
*.caffemodel | *.prototxt | caffe | readNetFremoCaffe
*.pd | *.pbtxt | tensorflow | readNetFromTensorFlow
*.t7 | *.net | torch | readNetFromTorch
*.weight | *.cfg | darknet | readNetFromDarknet
*.bin | *.xml | dldt | readNetFromModelOptimizer
*.onnx | | onnx | readNetFromONNX
模型下载链接: https://cs.stanford.edu/people/jcjohns/fast-neural-style/models/eccv16/composition_vii.t7
net = cv2.dnn.readNet(r'model\starry_night.t7') #得到一个pytorch训练之后的星空模型
# net=cv2.dnn.readNetFromTorch(r'.\model\la_muse.t7')
# net=cv2.dnn.readNetFromTorch(r'.\model\candy.t7')
# net=cv2.dnn.readNetFromTorch(r'.\model\composition_vii.t7')
# net=cv2.dnn.readNetFromTorch(r'.\model\feathers.t7')
# net=cv2.dnn.readNetFromTorch(r'.\model\udnie.t7')
# net=cv2.dnn.readNetFromTorch(r'.\model\the_scream.t7')
(4)网络输入
# 设置神经网络的输入
net.setInput(blob)
# 对输入图像进行前向传播,得到输出结果
out = net.forward()
(5)网络输出
# 重塑形状(忽略第1维),4维变3维
# 调整输出out的形状,模型推理输出out是四维BCHW形式的,调整为三维CHW形式
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 Image', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
(6)完整代码
import cv2
image=cv2.imread('../data/man.png')
cv2.imshow('yuantu',image)
cv2.waitKey(0)
#__________________________图片预处理__________________________________
(h,w)=image.shape[:2]
blob= cv2.dnn.blobFromImage(image,1,(w,h),(0,0,0),swapRB=False,crop=False)
#__________________________加载模型__________________________________
net=cv2.dnn.readNet(r'../data/model/candy.t7')
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 Image',result)
cv2.waitKey(0)
cv2.destroyAllWindows()
三、将DNN风格迁移应用到视频
import cv2
cap = cv2.VideoCapture('cxk.mp4') # 0
net=cv2.dnn.readNetFromTorch(r'.\model\starry_night.t7')
if not cap.isOpened(): # 打开失败
print("摄像头启动失败")
exit()
while True:
ret, frame = cap.read() # 如果正确读取帧,ret为True
if not ret: # 读取失败,则退出循环
print("不能读取摄像头")
break
# gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 图像处理-转换为灰度图
(h, w) = frame.shape[:2]
blob = cv2.dnn.blobFromImage(frame, 1, (w, h), (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('result', result)
key_pressed = cv2.waitKey(10) #60
if key_pressed == 27: # 如果按下esc键,就退出循环
break
cap.release() # 释放捕获器
cv2.destroyAllWindows() # 关闭图像窗口
同理,将视频改为摄像头就可以实时对摄像头读取的每一帧画面做DNN风格迁移。
效果展示:
总结
DNN风格迁移通过预训练网络的特征空间分离内容与风格,利用优化算法调和两者的统计特性,最终生成艺术化图像。这一方法结合了深度学习特征表达的强大能力与优化理论的灵活性,成为计算机视觉与艺术创作的桥梁。