本日は
Julia上でカメラ画像を扱うというモチベーションで昔PyCall経由で呼び出した方法を書きましたが,OpenCVなどを明示的に呼び出さずにJulia単体でも行けることに気づいたので書いておきます.
VideoIO.jl
VideoIO.jl がありまして https://github.com/JuliaIO/VideoIO.jl これを使うと良いことがわかりました.
install
julia> using Pkg
julia> Pkg.add("VideoIO")
はい.これでOK
USBカメラをつけておけばすぐに使えます.
Quick Start
動作確認をしてみましょう.VideoIO.jl が提供しているAPIとして Makie.jl を用いた撮像結果を描画するデモがあるのでそれを使ってみましょう.
julia> using VideoIO
julia> using Makie
julia> viewcam()
そうするとMakieのsceneオブジェクト上にOpenCVの cv2.imshow
で出力するような結果が出ます.
動作確認できたハード
コードを見るとWindows Mac Linux で使えるようにはなっているようです.バージョンが1.1のJulia上でですが
- Jetson nano (USBカメラ接続で)
- Raspberry Pi 3 (ラズパイ公式カメラで)
- Mac Book Air (2018)
では動作確認できてます.
- ただし,ラズパイの場合はOpenCVなどでも必要な呪文として実行前に
$ sudo modprobe bcm2835-v4l2
が必要です. (/etc/modules
にbcm2835-v4l2
を書いておけば呪文唱えなくても多分大丈夫)- あくまでも
f=opencamera()
をしてread(f)
の結果しか確かめて居ません.描画用のソフトはJulia on Raspberry Pi では充実してないのでJulia以外の方法を検討する方が今のところ近道です.
- あくまでも
- iMac 2019 だとなぜか認識しない.OpenCVやffmpeg からカメラは見えてるのに.MacBookだとできるのに.なぜかほんとうにわからない.ナゾイ.iMacでできた方いらっしゃいましたら教えてください.
Usage
viewcam()
だとナンもできないので opencamera()
を使いましょう.
julia> using VideoIO
julia> f = opencamera() # Pythonであれば import cv2; cv2.VideoCapture()相当
julia> img=read(f) # RGB を要素にもつArrayが得られる
julia> close(f) # カメラを閉じる
デフォルトのカメラデバイスが何かは VideoIO.DEFAULT_CAMERA_DEVICE
で見ることができます.
VideoIO.CAMERA_DEVICES
で候補を調べることができます.Macだと例えば下記のような出力になりますね.
julia> VideoIO.DEFAULT_CAMERA_DEVICE
Base.RefValue{String}("FaceTime HD Camera (Built-in)")
julia> VideoIO.CAMERA_DEVICES
3-element Array{String,1}:
"FaceTime HD Camera (Built-in)"
"Capture screen 0"
"Capture screen 1"
上で出てきたどれかの文字列を opencamera
関数の引数に渡すことで対応するデバイスの情報を捉えることができます.
Capture screen は実際にはカメラデバイスではなくスクリーンショットを取得する物と対応しているようです.
close
でカメラを閉じます.カメラを開いてる間にエラー・例外が発生してしまうとカメラの撮像をJuliaが止めてしまいますが,再びオープンさせる時に失敗します.ですのでいったん exit してJuliaのREPLを再起動するか例外をキャッチしてclose
させるようなコードを書いておく必要がありますね.
サンプルコード
# Usage:
# REPL 開いて上記のコードを読み込んで main_makie() を実行させる
# または main_plots() を実行させる.
import VideoIO
import Plots
import AbstractPlotting
import Makie
using Images, CoordinateTransformations, OffsetArrays
function main_makie()
f = VideoIO.opencamera()
img = read(f)
tfm = recenter(RotMatrix(pi/2), Images.center(img))
img=parent(warp(img,tfm))
scene = Makie.Scene(resolution = size(img))
makieimg = Makie.image!(
scene,
img,
show_axis = false,
scale_plot = true
)[end]
display(scene)
while !eof(f)
# OffsetArrays -> Array
img=parent(warp(read(f),tfm))
@info size(img)
makieimg[1] = img
sleep(1/f.framerate)
end
end
function main_plots()
f = VideoIO.opencamera()
img = read(f)
p=Plots.plot(img) |> display
for i in 1:100
@info i
read!(f,img)
Plots.plot(img, title="$i") |> display
end
end
Makieが使えない場合でも Plots の方で画像を plot させればいけるんじゃないかなっと思って作りました.(動きます).
ですがMakieの方が応用を考えるとパフォーマンスが出そうな感触です.
多分上記のコードよりは VideoIO.jl の中に定義されている viewcam()
のソースコードを読んでコードを抽出した方が綺麗なコードになって居ます.Sceneオブジェクトを90度回転するか img オブジェクトを rot させるかの違いですが,こうせざるを得ないのはMakieの画像描画仕様がアレだからです.
まとめ
- VideoIO.jl でカメラ画像を読み込めた.
- iMacで動かないけれど手持ちのデバイスでは動作させられた.
- ラズパイとかJetson-nanoで動いたのでJuliaでの画像認識デモの可能性が出てきましたね.