GeekFactory

int128.hatenablog.com

motionとZabbixによる監視カメラシステム

監視カメラというと高価な専用システムを連想しますが、PCサーバとUSBカメラを使うと安価に実現できます。自宅サーバに取り組んでいる人は一度は経験しているかもしれませんね。プライバシーや検出精度の問題など、まともに運用していくのは非常に難しいシステムともいえます。

今回は、カメラで取り込んだ画像から特徴量を抽出し、変化を監視するための基礎を考えます。画像処理やパターン認識は今後の課題とします。

必要なもの

  • USBカメラ
  • USB延長ケーブル
  • 監視カメラサーバ
  • 運用管理サーバ(私はAWS上のZabbix Serverを使いました)

監視カメラサーバと運用管理サーバは同一でも構いませんが、物理的に侵入された場合のデータ保全を考えると別拠点の方がよいでしょう。どこまでやるか次第です。

USBカメラの設置工事

外部からの侵入経路、もしくは、重要なものがある場所にカメラを設置します。光源の位置や逆光に注意しましょう。下記はうちで使用している製品です。これより少し古い製品かもしれません。

iBUFFALO Webカメラ Cmos130万画素 UVC対応 ヘッドセット付 シルバー BSW13K07HSV

iBUFFALO Webカメラ Cmos130万画素 UVC対応 ヘッドセット付 シルバー BSW13K07HSV

iBUFFALO Arvel USB2.0対応 リピーター ケーブル 5.0M ホワイト AUR09WH

iBUFFALO Arvel USB2.0対応 リピーター ケーブル 5.0M ホワイト AUR09WH

後から映り具合を調整するため、この段階ではカメラを仮止めしておきます。

監視カメラサーバの設定

motionというパッケージを使うと、USBカメラから取り込んだ画像の変化を検出し、画像や動画を残したりコマンドを実行したりできます。Gentoo LinuxではPortageツリーに取り込まれているため、emerge media-video/motionでインストールできます*1

Linuxではビデオデバイスは /dev/video0 として認識されます。キャプチャカードを積んでいたりすると番号がずれるので注意してください。

/etc/motion.conf を編集します。要点のみ抜粋します。

# Videodevice to be used for capturing  (default /dev/video0)
# for FreeBSD default is /dev/bktr0
videodevice /dev/video0    # 環境に合わせて変更します


# Threshold for number of changed pixels in an image that
# triggers motion detection (default: 1500)
#threshold 1500
threshold 5000    # デフォルトでは敏感すぎるので鈍感にします


# イベント発生時にトラップを飛ばす設定を入れます

# Command to be executed when an event starts. (default: none)
# An event starts at first motion detected after a period of no motion defined by gap
on_event_start /usr/local/bin/motion-zabbix-sender 1 %D %N %K %L %i %J

# Command to be executed when an event ends after a period of no motion
# (default: none). The period of no motion is defined by option gap.
on_event_end /usr/local/bin/motion-zabbix-sender 1 %D %N %K %L %i %J

# Command to be executed when a camera can't be opened or if it is lost
# NOTE: There is situations when motion doesn't detect a lost camera!
# It depends on the driver, some drivers don't detect a lost camera at all
# Some hang the motion thread. Some even hang the PC! (default: none)
on_camera_lost /usr/local/bin/motion-zabbix-sender 0

後半のイベントで指定しているスクリプトは、Zabbix Serverにトラップを飛ばすためのものです。現時点では下記のデータを送信していますが、不要であれば削ってください。

表記 内容
%D changed pixels
%N noise level
%i width of motion area
%J height of motion area
%K X coordinates of motion center
%L Y coordinates of motion center

スクリプトはこんな感じ。SENDER_OPTIONSで、Zabbix ServerのIPアドレスやポートを指定してください。

#!/bin/sh
#
# motion-zabbix-sender
#
# Specify this script in motion.conf:
#   on_event_start /usr/local/bin/motion-zabbix-sender 1 %D %N %K %L %i %J
#   on_event_end   /usr/local/bin/motion-zabbix-sender 1 %D %N %K %L %i %J
#   on_camera_lost /usr/local/bin/motion-zabbix-sender 0
#
SENDER="/usr/bin/zabbix_sender"
SENDER_OPTIONS="-z xxx.xxx.xxx.xxx -p 10051 -s ${HOSTNAME}"

function send_trap () {
        ${SENDER} ${SENDER_OPTIONS} "$@" || logger -t motion "could not send trap: $*"
}

function send_motion_traps () {
        send_trap -k motion.alive -o "$1"; shift
        send_trap -k motion.changed_pixels -o "$1"; shift
        send_trap -k motion.noise_level -o "$1"; shift
        send_trap -k motion.center_x -o "$1"; shift
        send_trap -k motion.center_y -o "$1"; shift
        send_trap -k motion.width -o "$1"; shift
        send_trap -k motion.height -o "$1"; shift
}

if [ $# -gt 1 ]; then
        send_motion_traps "$1" 0 0 0 0 0 0
        send_motion_traps "$@"
else
        send_motion_traps "$1" 0 0 0 0 0 0
fi

運用管理サーバの設定

運用管理サーバではZabbixが設定されているものとします。監視カメラサーバから受信したトラップをZabbixに取り込む設定を追加します。下記はchanged pixelsの例です。

項目 設定値
説明 Motion changed pixels
タイプ Zabbixトラッパー
キー motion.changed_pixels  ※トラップのキーと合わせる
データ型 数値 (整数)
データの形式 10進数
単位 pixels

このままではトラップを受信した時点のみ値が記録されるため、そのままグラフ化するとノコギリ形になってしまいます。そこで、1分ごとに測定値を記録するようにします。

項目 設定値
説明 Motion changed pixels every minute
タイプ 計算
last(motion.changed_pixels)
キー motion.changed_pixels_minute
データ型 数値 (整数)
データの形式 10進数
単位 pixels
更新間隔(秒) 60

これにより下記のグラフが描けます。もっと良い方法をご存知でしたら教えてください。


今回はUSBカメラから取り込んだ画像の変化量をグラフ化する方法を紹介しましたが、自分で特徴量を抽出することで様々な応用が可能です。また、不在時間などが分かっている場合は監視通知を活用できると思います。遊びといえば遊びですが、便利で安心な生活を実現するサービスになるのでぜひ試してみてください。

*1:以前は配布されているebuildを /usr/local/portage に配置する必要がありました。