ネットワークカメラ

Raspberry Piで画像を取り込みたいと思った時に、それを実現する方法は色々とある。専用のカメラモジュールが用意されているし、以前に書いたようにUSBカメラを接続してキャプチャする事もできる。

監視用によく使われているAxisのネットワークカメラがたまたま手元に来たので、Raspberry Piでできるだけ簡単にネットワークカメラの画像を取り込む方法について試してみた。

AxisのネットワークカメラはWebサーバを内蔵しているので、ブラウザでアクセスするだけで映像をモニタする事ができるし、設定によってモニタ画面のボタンをマウスでクリックした時にその画像を保存する事ができる。と言うことはRaspberry PiでネットワークカメラのWebサーバにアクセスして、ボタンをクリックした時のCGIを実行できれば同じことができるはず。

まずはその前に、モニタ画面でボタンをクリックした時にRaspberry Piへ画像を送れるようにしてみる。FTPを使用するので、Raspberry PiにFTPサーバがインストールされていない場合は

$ sudo apt-get install vsftpd

で最初にインストール。
デフォルトではanonymousログインのみで書き込み禁止になっているので、/etc/vsftpd.conf ファイルを編集してanonymousを禁止、ローカルユーザによるログインと書込みを可にする。

anonymous_enable=NO
local_enable=YES
write_enable=YES

設定ファイルを編集したらサービスを再起動

$ sudo service vsftpd restart

カメラ画像の転送先フォルダも作成しておく。ここでは「camera」とした。

Axisネットワークカメラのイベント設定はアクションルールとレシピの二つに分かれていて、前者は何をイベントとして受け付けるのか、後者はイベントを受け付けた時の動作を設定する。従ってブラウザのモニタ画面でボタンを押された時に画像をFTPサーバへアップロードする場合は、アクションルールに「マニュアルトリガ」、レシピに「FTP転送」を設定する事になる。

スクリーンショット 2014-12-08 11.56.24

スクリーンショット 2014-12-08 11.43.31

この設定をネットワークカメラに保存して、モニタ画面のトリガボタンをON/OFFするとRaspberry Piに画像が転送される事を確認。これが上手く行ったら、あとはトリガボタンがON/OFFされた時に実行されるCGIを、Raspberry Piから直接叩けば良い。

トリガONの時は

カメラのIPアドレス/axis-cgi/io/virtualinput.cgi?action=6:/

が実行されて、OFFの時は

カメラのIPアドレス/axis-cgi/io/virtualinput.cgi?action=6:\

が実行される。

pythonでCGIを実行するのはurllibモジュールを使用すれば良いのだが、認証が必要になるのでそこがちょっとだけ面倒。予め認証用のオブジェクトを作っておき、それをurllibモジュールに登録しておく必要がある。

ネットワークカメラの画像をFTP転送させるプログラムは以下の通り。IPアドレスやカメラのユーザ名、パスワードは適宜変更する。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from urllib import request
from urllib import parse

class camera():
    def __init__(self, topurl, cgiurl, camuser, campass):
        passwd_mgr = request.HTTPPasswordMgrWithDefaultRealm( )
        passwd_mgr.add_password(None, topurl, camuser, campass)
        handler = request.HTTPDigestAuthHandler(passwd_mgr)
        opener = request.build_opener(handler)
        request.install_opener(opener)
        self.cgi = topurl + cgiurl
    def save(self):
        trig_on  = parse.urlencode({'action' : '6:/'})
        trig_off = parse.urlencode({'action' : '6:\\'})
        request.urlopen(self.cgi + trig_on)
        request.urlopen(self.cgi + trig_off)

if __name__ == '__main__':
    netcam = camera('http://192.168.1.90/',
                    'axis-cgi/io/virtualinput.cgi?',
                    'root',
                    'xxxxxxxx')
    netcam.save()

実際のところpythonが動けばRaspberry Pi以外でもこのプログラムは動作するので、画像キャプチャだけならわざわざRaspberry Piを使う必要は無いし、カメラ単体に一定周期や動体検知で画像保存する機能もあるから、それだけで事足りる場合も多いだろう。

何かのセンサー類を使って、特定の条件で画像を取り込みたい。というネットワークカメラ単体では対応が難しいような要件であれば、役に立つかもしれない。

PySide(3)

Qt Designerで作成した .ui ファイルには、フォームとコントロール全ての情報がxml形式で含まれていて

loader = QUiLoader()
UI = loader.load(ファイルパス名)

のように読み込むと、配置したコントロールのオブジェクトが全て含まれたUIオブジェクトが作成される。たとえばLabelコントロールのオブジェクト名を”label”とした場合

UI.label.setText(‘Foo’)

とすればラベルコントロールのテキストを変更することができる。

それだけ分かっていれば、コードのみでPySideのGUIを作成したプログラムをQt Designer版に対応させるのは簡単に行える。

ボタンオブジェクト名 = QtGui.QPushButton(ボタンテキスト)
ボタンオブジェクト名.clicked.connect(関数名)

UI.ボタンオブジェクト名.clicked.connect(関数名)

のように置き換えてしまえば良い。

Quick2Wireを使ってカラーLEDを指定した色で光らせるPySideプログラムを .ui ファイルに対応させて、更に選択した色名を画面にカラー表示させたり、クリックしたボタンの色を変えたりできるように修正すると、最終的にプログラムは以下のようになった。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import os
sys.path.append('/usr/lib/python3/dist-packages')
from PySide import QtCore, QtGui
from PySide.QtCore import Qt
from PySide.QtUiTools import QUiLoader
from quick2wire.gpio import pins, Out

CURRENT_PATH = os.path.dirname(__file__)
COLOR_TBL = ((Qt.black,  'BLACK'), 
             (Qt.red,    'RED'),
             (Qt.green,  'GREEN'),
             (Qt.yellow, 'YELLOW'),
             (Qt.blue,   'BLUE'),
             (Qt.magenta,'MAGENTA'),
             (Qt.cyan,   'CYAN'),
             (Qt.white,  'WHITE'))
BUTTON_COLOR = (Qt.red, Qt.green, Qt.blue)

class ColorLED:
    led = (pins.pin(0, direction=Out),
           pins.pin(1, direction=Out),
           pins.pin(2, direction=Out))
    def __init__(self):
        for e in self.led:
            e.open();
    def __del__(self):
        for e in self.led:
            e.close();
    def set(self, color):
        self.led[0].value = color & 0x01
        self.led[1].value = color & 0x02
        self.led[2].value = color & 0x04

class Window(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        loader = QUiLoader()
        uiFilePath = os.path.join(CURRENT_PATH, 'QtColorLED.ui')
        self.UI = loader.load(uiFilePath)
        self.setCentralWidget(self.UI)
        self.btnRGB = (self.UI.pushButton_r,
                       self.UI.pushButton_g,
                       self.UI.pushButton_b)
        self.btnRGB[0].clicked.connect(lambda: self.click_btn(0))
        self.btnRGB[1].clicked.connect(lambda: self.click_btn(1))
        self.btnRGB[2].clicked.connect(lambda: self.click_btn(2))
        self.led = ColorLED()
        self.color = 0x01
        self.pal = self.UI.pushButton_r.palette()
        self.click_btn(0)
    def click_btn(self, n):
        self.color = self.color ^ (0x01 << n)
        self.led.set(self.color)
        pal = QtGui.QPalette()
        pal.setColor(QtGui.QPalette.Foreground, COLOR_TBL[self.color][0])
        self.UI.label.setPalette(pal)
        self.UI.label.setText(COLOR_TBL[self.color][1])
        if self.color & (0x01 << n) != 0:
            pal.setColor(self.btnRGB[n].backgroundRole(), BUTTON_COLOR[n])
            self.btnRGB[n].setPalette(pal)
        else:
            self.btnRGB[n].setPalette(self.pal)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    win = Window()
    win.show()
    sys.exit(app.exec_())

実行してボタンをクリックすると、ボタンの色が変わってボタンの組み合わせによる色でLEDが光り、同時に色の名前が表示される。

範囲を選択_0202014-11-13 09.33.45

範囲を選択_021

2014-11-13 09.33.58

範囲を選択_022

2014-11-13 09.34.07

範囲を選択_023

2014-11-13 09.34.18

ソースコードの説明は省くが、やっている事は一目瞭然なので必要ないだろう。
Qtを使うのはほとんど始めてなので、冗長な部分やもっとエレガントな使い方があるのだろうと思うが、Raspberry PiでGUIアプリを動かしてハードを制御するという目標は達したので良しとする。

Qtには色々と高度なコントロールが用意されているので、次はそのへんを使って何か作ってみる予定。

GPIOエクステンション改造

Raspberry PiのGPIOポートをブレッドボードに引き出すためのアダプタが以前は国内販売されていなかったので、ピンヘッダとユニバーサル基板を使って自作した物を使っていたが、今は取り扱っている所が増えて楽に入手できるようになった。
ざっと捜してみただけでも色々と見つかる。

Raspberry Pi用T型I/O延長基板
RaspberryPi対応GPIO変換基R板キット (ケーブル無し)
ブレッドボード接続用Raspberry Pi GPIOエクステンションキット (Model B専用)
Raspberry Pi GPIOエクステンション [RPi-GEB]

この中ではaitendoで扱っているアダプタが350円と最も安かったので、試しに一個購入してみた。
VCCとGNDがブレッドボードの電源ラインと直接接続できるタイプなので便利なのだが、電源ラインの位置は規格化されているわけではないので、当然ながら使えないブレッドボードも存在する。
と言うか手持ちのブレッドボードでは全てうまく使えなかった。ギリギリで使えたものでも、微妙にずれていてかなり無理をしないと挿せない。挿すと基板が歪んでしまう。

さすがにその状態で使用するのは不安なので、簡単に改造してみた。電源ラインのピンをハンダゴテで外し、代わりにVCCとGNDにブレッドボード用のジャンパー線をハンダ付けする。
ピンを抜く時は先に樹脂部分をニッパー等で切り外し、表側からコテ先を当てて裏からラジオペンチで一本ずつ引き抜くと簡単。基板は万力等で固定しておく。

あとは抜き取った穴にジャンパー線を差し込んでハンダ付けすれば良い。電源は+3.3Vと+5Vの両方が出ているので、必要な分だけハンダ付けする。
リード部分を切断して被覆を剥いてからハンダ付けしたほうが見た目は綺麗になると思うが、面倒なのでそのままハンダ付けした。

R0012687

出来上がったものを実際に使うとこんな感じ。これで利用できるブレッドボードの種類が増える。

R0012686