PYNQ-ComputerVIsionを試したメモ(USBカメラ→Sobelフィルタ→HDMI)

PYNQ-Z1ボードとUSBカメラ(logicool c270m)を使って、カメラ画像のSobelフィルタ結果をHDMIに出力してみた。

XilinxがOpenCVベースの画像処理をハードウェアを充実させてきているようで、以下をPYNQボードに入れ込むと簡単に画像処理の高速化を実装できる。
結果として、USBカメラの取り込みスピードに律速されてしまい、ハードウェアでのSobelフィルタによる高速化の恩恵が得られない結果になってしまった。
以下のコードを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)

コメント

タイトルとURLをコピーしました