motion は Webカメラ(Video4Linuxデバイス)やネットワークカメラで動体検知し録画するソフトです。動作が軽く、必要な条件だけ録画できるので、録画用のPCを別に用意しなくても、デスクトップ作業をしながら見守りをすることができます。
多くのディストリビューションでパッケージが用意されています。公式サイトでは Ubuntu と Debian の .deb バッケージが配布されています。DEB系以外のディストリで最新版を使うには、ソースをビルドすることになるでしょう。
$ motion -c /etc/motion/設定ファイル.conf
で動体検知と録画が始まります。設定ファイルは カメラごとに別々に書きます。多くのディストリでは、/etc/motion に雛形ファイルがあるでしょう。1台のカメラでも、昼と夜で設定ファイルを分けたりできます。軽いので複数台のカメラも1台のPCで間に合います。
PC の性能よりも、USBコントローラーの帯域のほうがボトルネックになることが多いです。多数の Webカメラを接続する場合は、端子ごとにコントローラーを搭載した USB 拡張ボードを用意するといいでしょう。
Video4Linux デバイスは /dev/video0 などのデバイスファイルが作られますが、ディストリビューションのデフォルトでは一般ユーザーに権限がないのが普通です。ログインユーザーを video グループに加えることが必要です。
$ sudo adduser ユーザー名 video
複数台の Webカメラを接続すると、/dev/video0、/dev/video1、… というようにデバイス名が作られますが、順序が一定しません。udev でエイリアスのデバイス名を別に作って、それを設定ファイルで指定することで、カメラの入れ替わりを回避できます。まず lsusb コマンドで、カメラのデバイス名を調べます。
$ lsusb Bus 001 Device 002: ID 1bcf:28c4 Sunplus Innovation Technology Inc. FHD Camera Microphone Bus 001 Device 007: ID 0bda:3036 Realtek Semiconductor Corp. USB Camera
/etc/udev/rules.d/99-local.rules というファイルを新規作成して、エイリアスのデバイス名を作ります。デバイス名の空白文字は逆スラッシュ文字でエスケープする必要があります。
KERNEL=="video[0-9]*", ATTR{index}=="0", ATTR{name}=="USB\ Camera:*", SYMLINK+="video-webcam0"
KERNEL=="video[0-9]*", ATTR{index}=="0", ATTR{name}=="FHD\ Camera\ Microphone*", SYMLINK+="video-webcam1"
最近の画像センサーは暗所性能が上がってるので、マニュアル露出すれば夜間でも真っ黒にならないことが多いです(露出時間を長くするので画像が流れますが)。その場合、昼と夜で設定ファイルを別にします。
カメラの露出やシャープネス、フォーカスなどのパラメータをマニュアルでいじるには、vid_control_params オプションで指定します。設定可能なパラメータは、端末の起動メッセージに出てきますので、スクロールバックして拾って下さい。たとえば以下のようになります。
# camera_id camera_name "FHD Camera" # Video device (e.g. /dev/video0) to be used for capturing. videodevice /dev/video-webcam1 # Image width in pixels. width 1280 # Image height in pixels. height 720 # Maximum number of frames to be captured per second. framerate 2 minimum_motion_frames 1 vid_control_params "Brightness"=-33, "Contrast"=1, "Gamma"=100, "Power Line Frequency"=0, "Sharpness"=7,ID10094858=1,ID10094860=0 # Threshold for number of changed pixels that triggers motion. threshold 40 # Number of images that must contain motion to trigger an event. minimum_motion_frames 1 smart_mask_speed 3 # Output pictures when motion is detected picture_output off # Create movies of motion events. movie_output on # Container/Codec to used for the movie. See motion_guide.html movie_codec mp4 # File name(without extension) for movies relative to target directory movie_filename %Y%m%d-%H%M-%S%q%v
日付ごとにディレクトリを分けるために、ディレクトリを作る起動スクリプトを作ります。まず昼バージョンを $HOME/bin/Fhdcamera.sh とします。夜バージョンが起動してる場合には pkill コマンドで終了させます。
#/bin/sh
pkill -f FHDCamera
while pgrep FHDCamera > /dev/null; do
sleep 1
done
mkdir -p $HOME/Pictures/`date "+%m%d"`/fhd
cd $HOME/Pictures/`date "+%m%d"`/fhd
motion -c /etc/motion/FHDCamera.conf
夜バージョンを $HOME/bin/Fhdcamera-n.sh とします。
/bin/sh
pkill -f FHDCamera
while pgrep FHDCamera > /dev/null; do
sleep 1
done
mkdir -p $HOME/Pictures/`date "+%m%d"`/fhd
cd $HOME/Pictures/`date "+%m%d"`/fhd
motion -c /etc/motion/FHDCamera-n.conf
日の出と日の入りの時刻は、python3-suntime でお手軽に取得できます。外部サーバーに接続せずにローカルで計算します。
$ sudo apt install python3-suntime
自動録画は cron で実行するのが簡単です。/etc/crontab で日の出用と日の入り用のスクリプトを指定します。
# .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat # * * * * * user-name command to be executed 20 4 * * * ユーザー名 python3 $HOME/bin/sunrise.py 30 16 * * * ユーザー名 python3 $HOME/bin/sunset.py
python3-suntime で日の出または日の入りを時刻までスリープして、その時刻になると、pyhtonのプロセスを motion の起動用のシェルスクリプトに置き換えるには、以下のようにします(日の入り sunset.py の場合)。
import time
from datetime import datetime
from zoneinfo import ZoneInfo # Python 3.9以上で標準搭載
from suntime import Sun
import os, sys
lat, lon = 35.6895, 139.6917 # 東京の緯度・経度
tz = ZoneInfo('Asia/Tokyo')
sun = Sun(lat, lon)
now = datetime.now(tz)
# 今日の日の出・日没の「正確な日時オブジェクト」を取得
sunrise_dt = sun.get_local_sunrise_time(now).astimezone(tz)
sunset_dt = sun.get_local_sunset_time(now).astimezone(tz)
# 日没ぴったりに動かしたい場合:残り秒数を計算
delay_seconds = (sunset_dt - now).total_seconds()
if delay_seconds > 0:
print(f"日没({sunset_dt.strftime('%H:%M:%S')})まで {int(delay_seconds)} 秒待機します...")
# 日没の時間までスクリプトをスリープ(待機)させる
time.sleep(delay_seconds)
# ─── ここに自動化したい処理(コマンド)を書く ───
os.execvp("sh", ["sh", "/home/ユーザー名/bin/Fhdcamera-n.sh"])
print("日没になりました。処理を実行します。")
else:
print("本日の日没時刻はすでに過ぎています。")