实验步骤
工程文件总览
1 运行sh文件,下载dnn模型
需要事先下好提供预先训练好的模型文件路径,OpenCV 没有提供下载。下面的sh文件给出了具体的下载路径和代码:其中candy、la_muse、mosaic等等都代表风格。一共有十种风格。
BASE_URL="https://cs.stanford.edu/people/jcjohns/fast-neural-style/models/"
mkdir -p models/instance_norm
cd models/instance_norm
curl -O "$BASE_URL/instance_norm/candy.t7"
curl -O "$BASE_URL/instance_norm/la_muse.t7"
curl -O "$BASE_URL/instance_norm/mosaic.t7"
curl -O "$BASE_URL/instance_norm/feathers.t7"
curl -O "$BASE_URL/instance_norm/the_scream.t7"
curl -O "$BASE_URL/instance_norm/udnie.t7"
mkdir -p ../eccv16
cd ../eccv16
curl -O "$BASE_URL/eccv16/the_wave.t7"
curl -O "$BASE_URL/eccv16/starry_night.t7"
curl -O "$BASE_URL/eccv16/la_muse.t7"
curl -O "$BASE_URL/eccv16/composition_vii.t7"
cd ../../
在终端terminal里输入以下命令即可运行sh文件
sh download_style_transfer_models.sh
运行即开始下载模型,终端会显示下面的界面,十种风格的模型下载完成✅
2 测试模型是否可用
下面是一个测试风格模型是否可用的测试程序:
import cv2
# 此处可更换各种模型
net = cv2.dnn.readNetFromTorch('models/instance_norm/candy.t7')
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
image = cv2.imread('timg.jpeg')
(h, w) = image.shape[:2]
blob = cv2.dnn.blobFromImage(image, 1.0, (w, h), (103.939, 116.779, 123.680), swapRB=False, crop=False)
net.setInput(blob)
out = net.forward()
out = out.reshape(3, out.shape[2], out.shape[3])
out[0] += 103.939
out[1] += 116.779
out[2] += 123.68
out /= 255
out = out.transpose(1, 2, 0)
cv2.imshow('Styled image', out)
cv2.waitKey(0)
测试结果:(原图+各种风格迁移后的图片)
原图 | candy | feather |
---|---|---|
![]() |
![]() |
![]() |
udnie | starry_night | |
![]() |
![]() |
以上测试通过,我们可以开始使用摄像头来进行实时风格转换了。(虽然测试这一步不是特别有必要,但是可以为之后摄像头程序铺路,可以提前排除我们的模型的问题,之后程序有问题可能就是其他方面的了。)
3 摄像头实时多种风格转换
关键代码如下:
下面的程序实现了摄像头实时显示5种风格的转换,都定义在了models里,组建了一个nets
nets = []
models = [
'/eccv16/the_wave.t7',
'/eccv16/starry_night.t7',
'/eccv16/la_muse.t7',
'/eccv16/composition_vii.t7'
'/instance_norm/feathers.t7'
]
for i in range(len(models)):
net = cv2.dnn.readNetFromTorch('models/' + models[i])
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
nets.append(net)
cap = cv2.VideoCapture(0)
用程序调用摄像头,分别对摄像头捕捉到的画面进行不同的风格转换,代码与测试代码主体相似:
画面显示的宽、高都是可以定义的,尽量不要选太大,不然会很卡。
while cv2.waitKey(1) < 0:
hasFrame, frame = cap.read()
if not hasFrame:
cv2.waitKey()
break
inWidth = 300
inHeight = 200
inp = cv2.dnn.blobFromImage(frame, 1.0, (inWidth, inHeight),
(103.939, 116.779, 123.68), swapRB=False, crop=False)
for i in range(len(nets)):
net = nets[i]
net.setInput(inp)
out = net.forward()
out = out.reshape(3, out.shape[2], out.shape[3])
out[0] += 103.939
out[1] += 116.779
out[2] += 123.68
out /= 255
out = out.transpose(1, 2, 0)
实验结果
下面是一个测试实验结果的录屏,风格转换效果还不错,但是实时性还是较差,视频有些卡顿。但这也可能是我同时转换太多了,一个的话效果要好很多。
问题解决
这次遇到了一个很坑的问题,在运行摄像头实时转换代码的时候报这样的错误:❌
pycharm中运行程序**:Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
terminal中运行程序: **Abort Trap6
**
- 找了很久的解决方法,网上说有以下几种原因会导致以上的错误:
1.内存不足 https://www.jianshu.com/p/8eee2c7af229
2.配置有问题 https://blog.csdn.net/jizhidexiaoming/article/details/80918868
**
经过我的排查,上述两种方法均对我无效,后来突然想到是不是摄像头不能调用导致的报错,于是写了一个调用摄像头的小程序,果然,一调用摄像头就会报错。
后来查了查,原因是:pycharm2019.3以前的版本和mac的系统之间因为安全协议的问题,pycharm不会向系统发出调用摄像头的请求,因此程序没法运行。据说2020.3版本的pycharm已经解决这个问题了,不过我没有更新,用了另一种解决方案:
-1.在终端运行一下调用摄像头的程序,同意终端调用camera的请求,此时设置里面:终端已经被勾选上。
**
-2.从终端运行pycharm