4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JuliaからPyCall経由でカメラを起動する。

Last updated at Posted at 2018-10-07

本日は

JuliaとPythonとOpenCVを仲良し連携する話です。

JuliaからOpenCV呼び出しはできるか?

OpenCV.jl というパッケージがあるみたいですね。 できそうな感じはしますが、世の中そんなに甘くなく,このパッケージは Cxx.jl に依存しているようです。Cxx.jl は Julia の REPL 上で C++ のコードを書いてそれを呼び出すという若干黒魔術なことができるものですがJulia1.0は愚かJulia0.7でも動きません。メンテナンスがおいつていないないのが現状です。Ubuntu+Julia0.6では Cxx.jl の動作は確認していますが、Julia1.0が出て他のパッケージが0.6を捨てて1.0対応を進めている現状を考えると固執して0.6を続けるのは長い目で見ると現実的ではありません。

(まぁ直接共有ライブラリ呼ぶとかあると思いますが。)

Python「うちに任せとき(龍驤風味)」

ということでJulia単体で何かをするのは諦めて PyCall 経由で Pythonの cv2 を呼び出す方針をとってみます。

ここでは次のようなことをしてみようと思います。

  • PCのカメラから画像を持ってくる
  • その画像を90度回転させる処理をJulia側で書く
  • 元々の画像と上記で処理した画像を幅方向に連結した結果を表示する

環境の前提としては

  • Julia1.0 および PyCallは動作できていること
  • Python および import cv2 が正常にできて、Python上でOpenCVのカメラ操作をすること

はできているものとします。

実装例

camera.jl
using PyCall: pyimport
using Images: warp, colorview, channelview, RGB, imresize
using CoordinateTransformations: LinearMap, RotMatrix

np = pyimport("numpy")
cv2 = pyimport("cv2")

function arr2rgb(img)
    img = Float32.(img ./ 255.0)
    #BGR2RGB
    img = img[:, :, reverse(1:end)]
    img = permutedims(img, (3,1,2))
    img = colorview(RGB, img)
    return img
end

function rgb2arr(img)
    img = channelview(img)
    img = permutedims(img, (2,3,1))
    #RGB2BGR
    img = img[:, :, reverse(1:end)]
    img = np[:asarray](255. .* img, dtype=np[:uint8])
    return img
end

function rotate(img, degree)
    rad = degree * pi / 180
    tfm = LinearMap(RotMatrix(rad))
    return warp(img, tfm)
end

function process_something(img)
    rot_img = rotate(img, 90)
    rot_img = imresize(rot_img, (224,224))
    return rot_img
end

function video()
    cap = cv2[:VideoCapture](0)
    if !cap[:isOpened]()
        print("Error opening video stream or file")
        exit(1)
    end

    while cap[:isOpened]()
        ret_val, img = cap[:read]()
        img = arr2rgb(img)
        img = imresize(img,(224,224))
        # do something on Julia
        new_img = process_something(img)
        # concat original and processed images
        concatenated = cat([img, new_img]..., dims=2)
        out = rgb2arr(concatenated)
        cv2[:imshow]("julia app press enter esc", out)
        if cv2[:waitKey](1) == 27
            #press `esc` key to exit
            break
        end
    end
end

video()

何をやっているか

カメラから画像を得る

まず、PyCallの関数 pyimport で Python を呼び出せるようにしています。
ここでは numpy cv2 が使えるようにしておきます。 video 関数の中に入ってPythonでやっていたように cap オブジェクトを作る手続きをJulia上でも行います。

ret_val, img = cap[:read]()

でカメラから撮ってきた画像を img として持たせます。

Images.jlの形式に直す。

Images.jl のAPIを用いて画像を処理したいのでarr2rgb関数にてその形式に合わせます。

  • Juliaの場合は 0から1の間の値に正規化された状態でデータを持たせる必要があります。
  • OpenCVで得た画像はBGRの順番なのでチャンネルの順番を変えてRGBに直します。
  • (np.transpose に相当する permutedimsにて)データ形式をHWCからCHWに直します。
    このあとは Juliaの関数の colorview で  Images.jl 上でハンドルできるようにします。各画素の位置に対してR,G,B の色情報を持ったデータが格納されるようですね。ですので size(img) とかすると (224,224) と帰って来ます。

回転とかの何かの処理をする

何か書いてみます。 Images.jl を眺めて適当な例を書いてみます。

function rotate(img, degree)
    rad = degree * pi / 180
    tfm = LinearMap(RotMatrix(rad))
    return warp(img, tfm)
end

function process_something(img)
    rot_img = rotate(img, 90)
    rot_img = imresize(rot_img, (224,224))
    return rot_img
end

回転前に(224,224)にリサイズしているはずなんですけれども回転後に1ピクセル単位で幅が増えてしまうのでリサイズし直します(闇)

画像の連結は

concatenated = cat([img, new_img]..., dims=2)

のようにします。

Python側に渡す。

基本的にImages.jlに合わせるの逆をしていきます。

channelview(img)で多次元の配列に直して(厳密にいうとviewらしいですが)
軸を直して値を0から255の幅にします。データのキャストはPython側で処理させました。

最後は

cv2[:imshow]("julia app press enter esc", out)

で出力したいデータを表示させます。

実行方法書いてありませんでしたが、

$ julia camera.jl

でOKです。ちゃんと動いてびっくりしました。

まとめ

  • JuliaからPyCall経由でOpenCVを呼び出す方法でカメラを起動することができました。
  • Juliaで完結できなくても豊富なPythonの資産を使ってみんな仲良くできることがわかりました。
  • 今回は例のために画像の処理をJuliaでやりましたが、Python側でのデータ構造とJulia側でのデータ構造の整合性をとるのに苦労してました。実際にはこういう処理もなれているPython側でやったほうがいいんじゃないかなという気はしています。
  • PyCallありがとう。

おまけ

ちなみにNimはNimからOpenCVを呼びだせました。やりますね。

4
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?