イベントカメラっぽい画像処理してみた


概要

イベントカメラっていうカメラがあります。
このイベントカメラ風に通常動画を変換してみたいと思います。
なんかに使えないかな〜。

成果物

動画はなんでもよかったんですが、固定カメラだときれいにとれます。今回はGolfDBのデータからタイガーウッズのショットをやってみました

イベントカメラとは

イベントカメラは、一般的なカメラと根本的に仕組みが異なります。
一般的なカメラは、ある高さH、ある幅W、RGBのどれかCからH×W×Cの次元の数値を持ちます。
動画であれば、(T×H×W×C)になります。

一方で、イベントカメラは、あくまでイベントしか記録しません。ここで、イベントとは、「輝度値の変化」です。つまり時間方向で見て輝度値が閾値以上変化した「点」だけを記録していきます。記録するのはT×(X,Y,P)です。Pは輝度値が増えたら1、減ったら-1が入ります。変化がないところは記録されないのが特徴です。

イベントカメラの特徴

さて、イベントしか記録しないこのカメラですが、以下のような特徴があります。

・超高フレームレート
・低消費電力
・非同期的

普通のカメラが60FPS程度なのに対し、イベントカメラは1000FPSを超えていきます。RGBカメラでは、FPSをあげるほど、カメラに入ってくる光の量が減って暗くなってしまうなどありますが、イベントカメラは入ってくる光の量が変わるか変わらないかなので高いFPSを保てます。
記録するデータが少ないので、低電力です。また、通常のカメラでは0.03秒目で1F、0.06秒目で2Fと一定のペースを開けてデータがありますが、イベントカメラの場合は
0.0012秒目で(100,200)で変化あり
0.0581秒目で(250,50)で変化あり
と変化があった時間でだけ記録されていきます。

低電力で高い時間分解能をもつことから自動運転などにも応用が考えられます。

本題

簡単なコードですが、イベントカメラっぽいことをやってみます。
動画で変化があったフレームだけを残してみます。

本当は「差分のあった点だけを取得する」のがイベントカメラの本質的なデータ構造です。
np.where使うと簡単にその形式に変換できます
イベントカメラは一般的に点群データ形式です。なので時間方向で点を集計して可視化することが多いので、画像からその可視化映像っぽいのだけ作ってみます。

コード

今回は1画像前の各チャネルで差分をとって閾値以上の場合はイベントとして画素を残します

import numpy as np
import cv2

def img2event_image(base_img, img, th = 10, plus = 128, minus = 255):
    img3 = base_img.astype(float) - img.astype(float)

    index1 = img3 > th
    img3[index1] = plus

    index2 = img3 < -1 * th
    img3[index2] = minus

    img3[~(index1) & ~(index2)] = 0 
    return img3.astype(np.uint8)

def video2event_video():
    stack = True
    path = "96.mp4"
    # output_name = "output.mp4"
    output_name = "output_stack.mp4"

    cap = cv2.VideoCapture(path)
    fourcc = cv2.VideoWriter_fourcc(*"mp4v")
    w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

    if stack:
        w *= 2
    fps = cap.get(cv2.CAP_PROP_FPS)
    fps = 30
    out = cv2.VideoWriter(output_name, fourcc, fps, (w, h)) 

    success, image = cap.read()
    # image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    base_image = image[:]
    while success:
        b_img = img2event_image(base_image.copy(), image.copy())
        if stack:
            b_img = cv2.hconcat([image, b_img])

        out.write(b_img)
        base_image = image[:]
        success, image = cap.read()
        # image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    cap.release()
    cv2.destroyAllWindows()

参考

イベントカメラ DAVIS346
https://nanoxeed.co.jp/product/eventcamera/

イベントカメラの話
https://qiita.com/minomonter/items/6d71029f6c860da60740