PYNQ-Z1ボードとUSBカメラ(logicool c270m)を使って、カメラ画像のSobelフィルタ結果をHDMIに出力してみた。
XilinxがOpenCVベースの画像処理をハードウェアを充実させてきているようで、以下をPYNQボードに入れ込むと簡単に画像処理の高速化を実装できる。
結果として、USBカメラの取り込みスピードに律速されてしまい、ハードウェアでのSobelフィルタによる高速化の恩恵が得られない結果になってしまった。
以下のコードをJupyter Notebookに貼って実行していけば確認できる。
※PYNQ-ComputerVisionのインストールは先にしておく必要あり。
以下のコードをJupyter Notebookに貼って実行していけば確認できる。
※PYNQ-ComputerVisionのインストールは先にしておく必要あり。
環境
- PYNQ-Z1ボード(PYNQイメージはv2.3)
- USBカメラ(logicool c270m)
A.HDMIとカメラの設定コード
# Load filter2D + dilate overlay from pynq import Overlay bareHDMI = Overlay("/usr/local/lib/python3.6/dist-packages/" "pynq_cv/overlays/xv2Filter2DDilate.bit") import pynq_cv.overlays.xv2Filter2DDilate as xv2 # Load xlnk memory mangager from pynq import Xlnk Xlnk.set_allocator_library("/usr/local/lib/python3.6/dist-packages/" "pynq_cv/overlays/xv2Filter2DDilate.so") mem_manager = Xlnk() hdmi_out = bareHDMI.video.hdmi_out from pynq.lib.video import * frame_in_w = 1280 #Webcam maxsize=1280x720 frame_in_h = 720 Mode = VideoMode(frame_in_w,frame_in_h,8) hdmi_out = bareHDMI.video.hdmi_out hdmi_out.configure(Mode) hdmi_out.cacheable_frames = False hdmi_out.start() mymode = hdmi_out.mode print("My mode: "+str(mymode)) height = hdmi_out.mode.height width = hdmi_out.mode.width bpp = hdmi_out.mode.bits_per_pixel import cv2 videoIn = cv2.VideoCapture(0) videoIn.set(cv2.CAP_PROP_FRAME_WIDTH, frame_in_w); videoIn.set(cv2.CAP_PROP_FRAME_HEIGHT, frame_in_h); print("capture device is open: " + str(videoIn.isOpened()))
B.グレースケールにしてHDMIに出力する
import numpy as np import cv2 from threading import Thread import time #Through: Camera input to HDMI output def loop_hw1_app(): global outframe numframes = 100 readt = 0 glayt = 0 start=time.time() for _ in range(numframes): readst = time.time() ret, inframe = videoIn.read() readet = time.time() readt += (readet-readst) if (not ret): # Release the Video Device if ret is false videoIn.release() # Message to be displayed after releasing the device print("Release camera resource") break else: outframe = hdmi_out.newframe() glayst = time.time() outframe[:] = cv2.cvtColor(inframe, cv2.COLOR_BGR2GRAY) glayet = time.time() glayt = (glayet- glayst) hdmi_out.writeframe(outframe) end=time.time() print("Frames per second: " + str(numframes / (end - start))) print("Camera read time(Avg.): "+ str(readt/numframes*1000) + " ms") print("Glayscale conv. time(Avg.): "+ str(glayt/numframes*1000) + " ms") t = Thread(target=loop_hw1_app) t.start()
プロファイリングの結果:
Frames per second: 10.595073612489498
Camera read time(Avg.): 71.09943151473999 ms
Glayscale conv. time(Avg.): 0.2248096466064453 ms
カメラのリードに律速されることがわかる。
C. Sobelフィルタをかけてから出力(ハードウェアで高速化) ※Aのコードは共通
import numpy as np import cv2 from threading import Thread import time xFin = mem_manager.cma_array((frame_in_h,frame_in_w),np.uint8) xFout = mem_manager.cma_array((frame_in_h,frame_in_w),np.uint8) kernel_g = np.array([[1.0,0.0,-1.0],[2.0,0.0,-2.0],[1.0,0.0,-1.0]],np.float32) def loop_hw2_app(): global kernel_g global outframe numframes = 100 start=time.time() for _ in range(numframes): ret, inframe = videoIn.read() if (not ret): # Release the Video Device if ret is false videoIn.release() # Message to be displayed after releasing the device print("Release camera resource") break else: outframe = hdmi_out.newframe() frame_in_gray = cv2.cvtColor(inframe, cv2.COLOR_BGR2GRAY) xFin[:] = frame_in_gray[:] xv2.filter2D(xFin, -1, kernel_g, dst=outframe, borderType=cv2.BORDER_CONSTANT) hdmi_out.writeframe(outframe) end=time.time() print("Frames per second: " + str(numframes / (end - start))) t = Thread(target=loop_hw2_app) t.start()
USBカメラの設定等変えれば高速化できるのだろうか?
結果は残念なことになってしまったが、こういうのが公開されているのを見ると、ソフトウェア屋がハードウェアをPoC目的等で高速化を試せるようなオープンソース環境が増えてきていると感じる(僕はハードウェア屋)。
どんどんやって欲しい。ハード屋でもソフトとのI/Fをどうすれば良いかとかHLSの書き方とか参考になるし。
おまけ:常時画像出力するコード(Jupyterの停止ボタンで出力停止)
while True: ret, inframe = videoIn.read() if (not ret): # Release the Video Device if ret is false videoIn.release() # Message to be displayed after releasing the device print("Release camera resource") break else: outframe = hdmi_out.newframe() frame_in_gray = cv2.cvtColor(inframe, cv2.COLOR_BGR2GRAY) xFin[:] = frame_in_gray[:] xv2.filter2D(xFin, -1, kernel_g, dst=outframe, borderType=cv2.BORDER_CONSTANT) hdmi_out.writeframe(outframe)
コメント