こちらのブログを参考にOpenCVをインストールしてみた。
はんだ日和: Raspberry Pi にOpenCV をインストール
いろんなサイトでOpenCVをインストールするのはかなり骨の折れる作業だと書いてあるんですが、こちらのサイトの「②の方法」だとあっという間にインストールが終ります。
最新のバージョンが良いのでしょうけれど、最新バージョンでしか使えないような斬新な使い方はしないので僕は楽な②の方を選択。
インストール
sudo apt-get install libopencv-dev
バージョンの確認
nano /usr/include/opencv2/core/version.hpp
僕のインストールしたバージョンは2.4.9でした。
pythonからOpenCVを使うには,追加でパッケージが必要だそうなのでインストール
これで準備完了
これらのサイトを参考にさせていただくと
金星☆ちゃんねる: Python版OpenCVでWebカメラの画像を取得する
cv2をインポートして使うようだ。
GUIで使う場合は上記リンク通りにすれば映るらしい。
ただ、僕がやりたいのはCUI環境で設定してWEBページに表示させる。とWEBカメラのような使い方だ。
RaspberryPiでWebカメラを作るには「motion」というアプリを使うのが一般的らしい。動きがあった際に自動的に画像保存してくれる優れものだ。
参考ブログ
http://divide-et-impera.org/archives/1098
しかしSSL接続したかったりWebページにスイッチを組み込んでGPIOと連携させたかったりしたいのでmotionを使わない方法を検索したがよくわからなかった。
なので無理矢理見れるようにpythonでコードを作った。
SSL接続でタイムラグが5〜10秒ほど発生するのでラジコン等の操作には実用的では無いがGPIOでオートフィーダーを目指す目的なのでペットの様子を見るには十分だ。
OpenCVでは
cv2.imwrite(セーブデータ, キャプチャしたイメージ)
で、データに指定した拡張子で保存してくれるらしい。
デーモンプログラムとして最初から起動させておいてカメラキャプチャコマンドとデータを内部メモリ(/dev/shm/cap/)でやりとりするという方法にした。
file_mngは以前作ったものを使用
動作は
- システム終了時にカメラをリリースする設定(カメラをリリースしないと次回起動時にカメラを認識してくれないから最初に設定が絶対必要)
- カメラを起動させて「standby」とcomandファイルに記録
- comandファイルを0.2秒間隔で読み込んで10秒間何もなければ「sleep」と書き込み、読み込み間隔を1秒に更新
- comandファイルに他のプログラムから「get」と入力されていればcap.jpgというファイルで画像を保存して「ok」とcomandファイルに書き込む
- 3.へ戻る
これだけ。
これでWebサーバーから0.5秒間隔ぐらいでのアクセスだと問題無く読み込まれている様子。
いろいろ試行錯誤した結果が下記のコードになった。ゴチャってるけれどとりあえず正常に動いている。
-- camerad.py --
#!/usr/bin/python
# -*- coding: utf-8 -*-
import cv2
import os,sys
import file_mng
import threading, time
import atexit
save_path = "/dev/shm/cam"
save_cap = "/cap.jpg"
save_com = "/comand"
count = 0
speed = 1.0
isCapture = False
capture = None
def chmod():
if file_mng.is_file(save_path + save_com) is True:
os.chmod(save_path + save_com,0777)
def set_comand(message = "non"):
#print message
file_mng.save(save_path + save_com,message)
chmod()
def get_comand():
lst = file_mng.load(save_path + save_com)
if 0 < len(lst):
return lst[0]
else:
return "non"
def camera_init():
global isCapture, capture
if os.path.isdir(save_path) == False:
file_mng.make_dir(save_path)
set_comand("init")
isCapture = True
set_comand("loading")
capture = cv2.VideoCapture(0)
if capture.isOpened() is False:
raise("Camera Error")
set_comand("stndby")
def camera_get():
global count,speed,isCapture
#time.sleep(0.2)
count = 0.0
speed = 0.01
if isCapture is False:
camera_init()
try:
set_comand("now")
ret, image = capture.read()
except:
ret = False
if ret is True:
file_mng.del_file(save_path + save_cap)
cv2.imwrite(save_path + save_cap, image)
set_comand("ok")
cv2.waitKey(1)
else:
set_comand("read_NG")
def camera_end():
global capture,isCapture,speed,count
count = 0.0
speed = 1.0
set_comand("sleep")
if capture is not None:
capture.release()
capture = None
isCapture = False
def loop():
global count
while 1:
count += speed
if "get" == get_comand() and 0.2 < count :
camera_get()
if 9.9 < count:
camera_end()
time.sleep(speed)
def init():
atexit.register(camera_end)
set_comand("start")
camera_get()
loop()
def fork():
pid = os.fork()
if pid > 0:
f = open('/var/run/camerad.pid','w')
f.write(str(pid)+" ")
f.close()
sys.exit()
if pid == 0:
init()
if __name__ == '__main__':
fork()
保存先ディレクトリのパーミッションも変更しているのでWebサーバーからは/dev/shm/cam/comandファイルへ「get」と書き込んでcap.jpgを読み込むだけという単純な方法で画像を取得出来る。
HTMLにはJavascriptで0.5間隔で画像を更新するようにすれば良い
Bottle用のテンプレート
<html>
<body>hello:{{name}}<br>
ライブ映像<br>
<script type="text/javascript">
var timer = window.setInterval(function() {
document.getElementById("hoge").src = "../../static/cap.jpg?" + (new Date() - 0);
}, 500);
</script><img id="hoge" src="../../static/cap.jpg" alt="ライブ画像">
</body>
</html>
今回実験で使ったカメラ↓