实验步骤

工程文件总览

image.png

1 运行sh文件,下载dnn模型

需要事先下好提供预先训练好的模型文件路径,OpenCV 没有提供下载。下面的sh文件给出了具体的下载路径和代码:其中candy、la_muse、mosaic等等都代表风格。一共有十种风格。

  1. BASE_URL="https://cs.stanford.edu/people/jcjohns/fast-neural-style/models/"
  2. mkdir -p models/instance_norm
  3. cd models/instance_norm
  4. curl -O "$BASE_URL/instance_norm/candy.t7"
  5. curl -O "$BASE_URL/instance_norm/la_muse.t7"
  6. curl -O "$BASE_URL/instance_norm/mosaic.t7"
  7. curl -O "$BASE_URL/instance_norm/feathers.t7"
  8. curl -O "$BASE_URL/instance_norm/the_scream.t7"
  9. curl -O "$BASE_URL/instance_norm/udnie.t7"
  10. mkdir -p ../eccv16
  11. cd ../eccv16
  12. curl -O "$BASE_URL/eccv16/the_wave.t7"
  13. curl -O "$BASE_URL/eccv16/starry_night.t7"
  14. curl -O "$BASE_URL/eccv16/la_muse.t7"
  15. curl -O "$BASE_URL/eccv16/composition_vii.t7"
  16. cd ../../

在终端terminal里输入以下命令即可运行sh文件

  1. sh download_style_transfer_models.sh

运行即开始下载模型,终端会显示下面的界面,十种风格的模型下载完成✅

Pasted Graphic 1.png

2 测试模型是否可用

下面是一个测试风格模型是否可用的测试程序:

  1. import cv2
  2. # 此处可更换各种模型
  3. net = cv2.dnn.readNetFromTorch('models/instance_norm/candy.t7')
  4. net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
  5. image = cv2.imread('timg.jpeg')
  6. (h, w) = image.shape[:2]
  7. blob = cv2.dnn.blobFromImage(image, 1.0, (w, h), (103.939, 116.779, 123.680), swapRB=False, crop=False)
  8. net.setInput(blob)
  9. out = net.forward()
  10. out = out.reshape(3, out.shape[2], out.shape[3])
  11. out[0] += 103.939
  12. out[1] += 116.779
  13. out[2] += 123.68
  14. out /= 255
  15. out = out.transpose(1, 2, 0)
  16. cv2.imshow('Styled image', out)
  17. cv2.waitKey(0)

测试结果:(原图+各种风格迁移后的图片)

原图 candy feather
timg.jpeg

image.png image.png
udnie starry_night
image.png image.png

以上测试通过,我们可以开始使用摄像头来进行实时风格转换了。(虽然测试这一步不是特别有必要,但是可以为之后摄像头程序铺路,可以提前排除我们的模型的问题,之后程序有问题可能就是其他方面的了。)

3 摄像头实时多种风格转换

关键代码如下:

下面的程序实现了摄像头实时显示5种风格的转换,都定义在了models里,组建了一个nets

  1. nets = []
  2. models = [
  3. '/eccv16/the_wave.t7',
  4. '/eccv16/starry_night.t7',
  5. '/eccv16/la_muse.t7',
  6. '/eccv16/composition_vii.t7'
  7. '/instance_norm/feathers.t7'
  8. ]
  9. for i in range(len(models)):
  10. net = cv2.dnn.readNetFromTorch('models/' + models[i])
  11. net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
  12. nets.append(net)
  13. cap = cv2.VideoCapture(0)

用程序调用摄像头,分别对摄像头捕捉到的画面进行不同的风格转换,代码与测试代码主体相似:
画面显示的宽、高都是可以定义的,尽量不要选太大,不然会很卡。

  1. while cv2.waitKey(1) < 0:
  2. hasFrame, frame = cap.read()
  3. if not hasFrame:
  4. cv2.waitKey()
  5. break
  6. inWidth = 300
  7. inHeight = 200
  8. inp = cv2.dnn.blobFromImage(frame, 1.0, (inWidth, inHeight),
  9. (103.939, 116.779, 123.68), swapRB=False, crop=False)
  10. for i in range(len(nets)):
  11. net = nets[i]
  12. net.setInput(inp)
  13. out = net.forward()
  14. out = out.reshape(3, out.shape[2], out.shape[3])
  15. out[0] += 103.939
  16. out[1] += 116.779
  17. out[2] += 123.68
  18. out /= 255
  19. out = out.transpose(1, 2, 0)

实验结果

下面是一个测试实验结果的录屏,风格转换效果还不错,但是实时性还是较差,视频有些卡顿。但这也可能是我同时转换太多了,一个的话效果要好很多。

屏幕录制 2020-04-13 下午4.05.31.mov (6.67MB)

问题解决

这次遇到了一个很坑的问题,在运行摄像头实时转换代码的时候报这样的错误:❌
pycharm中运行程序**:Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
terminal中运行程序: **Abort Trap6
**

2.配置有问题 https://blog.csdn.net/jizhidexiaoming/article/details/80918868
**
经过我的排查,上述两种方法均对我无效,后来突然想到是不是摄像头不能调用导致的报错,于是写了一个调用摄像头的小程序,果然,一调用摄像头就会报错。

后来查了查,原因是:pycharm2019.3以前的版本和mac的系统之间因为安全协议的问题,pycharm不会向系统发出调用摄像头的请求,因此程序没法运行。据说2020.3版本的pycharm已经解决这个问题了,不过我没有更新,用了另一种解决方案:

-1.在终端运行一下调用摄像头的程序,同意终端调用camera的请求,此时设置里面:终端已经被勾选上。

image.png
**
-2.从终端运行pycharm

image.png