IoT

Raspberry Pi+PythonでLINE通知付きセキュリティカメラを自作する方法【1万円以下】

Raspberry PiとPythonを使った自作セキュリティカメラを作りたいと思っていませんか?「外出中に自宅の様子が気になる」「不審者が来たらすぐに知りたい」——そんな悩みを、1万円以下・Pythonコード数十行で解決できます。

この記事では、Raspberry Pi+OpenCVによる動体検知LINE通知を組み合わせたIoTセキュリティシステムの作り方を、初〜中級者向けにステップごとに丁寧に解説します。完成すれば、不審な動きを検知した瞬間にLINEへ画像付き通知が届く本格的なシステムの出来上がりです!

⚠️ 2024年最新情報:LINE Notifyは2025年3月末をもってサービス終了予定です。本記事ではLINE Notify(現時点で動作確認済み)で解説しつつ、移行先となるLINE Messaging APIについても末尾で補足しています。

Raspberry Piセキュリティカメラに必要なものリスト

ハードウェア一覧

  • Raspberry Pi 4(または3B+)
  • Raspberry Pi Camera Module v2(または互換カメラ)
  • microSDカード(16GB以上・Class10推奨)
  • 電源アダプター(USB-C、5V/3A)

ソフトウェア・サービス一覧

  • Raspberry Pi OS(最新版 Bookworm推奨)
  • Python 3.8以上
  • OpenCV(動体検知ライブラリ)
  • LINE Notify(無料のLINE通知API)

カメラモジュールはAmazonで2,000〜3,000円程度で購入できます。Raspberry Pi本体(5,000〜7,000円前後)と合わせても合計1万円前後でセキュリティカメラが完成します。市販のIPカメラ(1〜3万円)と比べてもコスパは抜群です。

【手順1】LINE通知用アクセストークンを取得する

LINE通知の要となるLINE Notifyアクセストークンを最初に取得しておきましょう。取得は5分程度で完了します。

  1. LINE Notify公式サイトにLINEアカウントでログイン
  2. 右上のアカウント名をクリック →「マイページ」へ移動
  3. 「トークンを発行する」をクリック
  4. トークン名(例:「セキュリティカメラ」)を入力し、通知先のトークルームを選択
  5. 発行されたトークンをメモ帳などに保存する(一度しか表示されません!

このトークンをPythonスクリプトに設定することで、Raspberry PiからLINEへ直接通知を送れるようになります。

【手順2】Raspberry Piの開発環境をセットアップする

Raspberry Pi OSのインストールが完了したら、OpenCVをはじめとする必要なPythonライブラリをインストールします。ターミナルで以下のコマンドを順番に実行してください。

# システムのアップデート(必ず最初に実行)
sudo apt update && sudo apt upgrade -y

# OpenCV本体のインストール(動体検知の核となるライブラリ)
pip3 install opencv-python

# requestsライブラリのインストール(LINE通知のHTTPリクエスト用)
pip3 install requests

# picamera2のインストール(Raspberry Pi OS Bookworm以降はこちらを使用)
pip3 install picamera2

インストール完了後、カメラモジュールが正しく認識されているか確認しましょう。以下のコマンドを実行してプレビューウィンドウが開けばカメラの接続はOKです。

libcamera-hello

カメラが認識されない場合は、sudo raspi-config →「Interface Options」→「Camera」からカメラインターフェースが有効化されているか確認してください。

【手順3】OpenCVで動体検知+LINE通知Pythonスクリプトを作成する

いよいよ動体検知とLINE通知を組み合わせたメインのPythonスクリプトを作成します。仕組みはシンプルで、連続する2フレームの差分をOpenCVで計算し、変化量が閾値を超えたら動体と判定してLINEに画像付き通知を送信します。

import cv2
import requests
import time
import os
from picamera2 import Picamera2
from datetime import datetime

# ===== 設定エリア =====
LINE_TOKEN = "ここにLINE Notifyのトークンを貼り付ける"
THRESHOLD  = 3000   # 動体検知の感度(数値が小さいほど敏感・誤検知注意)
COOL_TIME  = 30     # 通知クールタイム(秒)連続通知を防止
SAVE_PATH  = "/home/pi/security/"
# =====================

# 保存先ディレクトリの作成
os.makedirs(SAVE_PATH, exist_ok=True)

def send_line_notify(message, image_path=None):
    """LINEに通知を送信する関数"""
    url     = "https://notify-api.line.me/api/notify"
    headers = {"Authorization": f"Bearer {LINE_TOKEN}"}
    data    = {"message": message}

    if image_path:
        with open(image_path, "rb") as f:
            files    = {"imageFile": f}
            response = requests.post(url, headers=headers, data=data, files=files)
    else:
        response = requests.post(url, headers=headers, data=data)

    if response.status_code == 200:
        print(f"[LINE通知] 送信成功: {message}")
    else:
        print(f"[LINE通知] 送信失敗: ステータスコード {response.status_code}")

def detect_motion():
    """動体検知のメインループ"""
    picam2 = Picamera2()
    config = picam2.create_preview_configuration(
        main={"size": (640, 480), "format": "RGB888"}
    )
    picam2.configure(config)
    picam2.start()
    time.sleep(2)  # カメラ安定待ち

    print("[セキュリティカメラ] 動体検知を開始します...")

    prev_frame  = None
    last_notify = 0  # 最後に通知した時刻

    try:
        while True:
            # フレーム取得とグレースケール変換
            frame      = picam2.capture_array()
            gray_frame = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
            gray_frame = cv2.GaussianBlur(gray_frame, (21, 21), 0)

            if prev_frame is None:
                prev_frame = gray_frame
                continue

            # フレーム差分で動体を検知
            diff         = cv2.absdiff(prev_frame, gray_frame)
            _, thresh    = cv2.threshold(diff, 25, 255, cv2.THRESH_BINARY)
            motion_score = cv2.countNonZero(thresh)

            if motion_score > THRESHOLD:
                current_time = time.time()
                # クールタイムが経過していれば通知
                if current_time - last_notify > COOL_TIME:
                    timestamp  = datetime.now().strftime("%Y%m%d_%H%M%S")
                    image_path = f"{SAVE_PATH}motion_{timestamp}.jpg"

                    # BGR変換して保存(OpenCVはBGR形式)
                    bgr_frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
                    cv2.imwrite(image_path, bgr_frame)

                    message = f"\n🚨 動体を検知しました!\n日時: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\nスコア: {motion_score}"
                    send_line_notify(message, image_path)
                    last_notify = current_time
                    print(f"[検知] スコア: {motion_score} / 画像保存: {image_path}")

            prev_frame = gray_frame
            time.sleep(0.5)  # CPU負荷軽減

    except KeyboardInterrupt:
        print("\n[セキュリティカメラ] 停止しました。")
    finally:
        picam2.stop()
        cv2.destroyAllWindows()

if __name__ == "__main__":
    detect_motion()

スクリプトの主要パラメーターを調整する

スクリプト上部の設定エリアにある3つのパラメーターを環境に合わせてチューニングしましょう。

パラメーターデフォルト値説明・調整の目安
THRESHOLD3000動体検知の感度。室内なら2000〜4000、屋外(風・木の揺れあり)なら8000〜15000が目安
COOL_TIME30秒連続通知を防ぐクールタイム。頻繁に通知が届く場合は60〜120秒に延ばす
SAVE_PATH/home/pi/security/検知画像の保存先。SDカード容量に注意し、定期的な削除スクリプトの併用を推奨

【手順4】スクリプトをSystemdで自動起動させる

毎回手動でスクリプトを起動するのは不便です。Systemdサービスとして登録することで、Raspberry Pi起動時に自動でセキュリティカメラが立ち上がるようになります。

# サービスファイルを作成
sudo nano /etc/systemd/system/security-camera.service

エディタが開いたら、以下の内容を貼り付けてください(UserExecStartのパスは環境に合わせて変更)。

[Unit]
Description=Raspberry Pi Security Camera with LINE Notify
After=network.target

[Service]
User=pi
WorkingDirectory=/home/pi
ExecStart=/usr/bin/python3 /home/pi/security_camera.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
# サービスを有効化して起動
sudo systemctl daemon-reload
sudo systemctl enable security-camera.service
sudo systemctl start security-camera.service

# 動作状態の確認
sudo systemctl status security-camera.service

Active: active (running) と表示されれば自動起動の設定は完了です。これでRaspberry Piの電源を入れるだけでセキュリティカメラが稼働します。

動体検知の精度を上げるチューニングテクニック

基本的なシステムが完成したら、OpenCVのパラメーター調整で動体検知の精度をさらに高めましょう。

輪郭検出で人物・物体を絞り込む

現在の実装はピクセル差分の総量で判定していますが、cv2.findContours()を追加することで動いている物体の輪郭サイズを基準にでき、虫や照明変化による誤検知を大幅に減らせます。

# 輪郭検出で人物サイズの動体のみ検知
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

for contour in contours:
    # 輪郭の面積が小さい場合は無視(虫・ノイズ対策)
    if cv2.contourArea(contour) < 1500:
        continue
    # 人物サイズの動体を検知した場合のみ通知処理へ
    x, y, w, h = cv2.boundingRect(contour)
    cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
    # → 通知処理をここに移動

夜間・暗所での検知精度を高める

暗所での誤検知が多い場合は、ガウシアンブラーのカーネルサイズを大きく(例:41×41)してノイズを除去するか、Raspberry Pi NoIRカメラと赤外線LEDを組み合わせる方法が有効です。

よくある質問・トラブルシューティング

Q. LINE通知が届かない

A. 以下の順番で確認してください。①トークンが正しくコピーされているか(前後にスペースが入っていないか)②Raspberry PiがWi-Fiまたは有線LANでインターネットに接続されているか③response.status_codeprintして401(認証エラー)か400(リクエストエラー)かを特定する。

Q. 誤検知が多すぎる(通知が頻繁に届く)

A. THRESHOLDの値を段階的に上げてください(3000→8000→15000)。屋外設置の場合は木の葉の揺れや光の変化が誤検知の主原因になるため、15000〜30000程度が現実的な設定値です。またCOOL_TIMEを60秒以上に延ばすことで通知頻度も抑えられます。

Q. Raspberry Pi 5でも動作するか

A. 動作します。Raspberry Pi 5はCSIコネクタの仕様が変更されているため、公式のFPC変換ケーブルが別途必要になる場合があります。picamera2のバージョンを最新(pip3 install --upgrade picamera2)にしてから動作確認することを推奨します。

LINE Notifyサービス終了後の移行先:LINE Messaging API

LINE Notifyは2025年3月末でサービス終了予定です。移行先としてLINE Messaging API(無料枠:月200通)が公式に案内されています。Messaging APIはチャンネルアクセストークンの取得手順がやや複雑になりますが、requests.post()でメッセージを送る基本構造は同様です。

Messaging APIへの詳しい移行手順は「LINE Messaging APIをPythonで使う方法【2024年版】」の記事で解説しています。

まとめ:Raspberry Pi+PythonでセキュリティカメラをDIYしよう

この記事で解説した手順をおさらいします。

  • LINE Notifyのトークンを取得してPythonから通知を送れる状態にする
  • OpenCV・picamera2をインストールしてRaspberry Piの開発環境を整える
  • フレーム差分による動体検知スクリプトを作成・動作確認する
  • Systemdで自動起動を設定して運用を安定させる
  • 輪郭検出・感度調整で誤検知を減らしてチューニングする

Raspberry PiとPythonを使った自作セキュリティカメラは、IoT・電子工作の入門プロジェクトとして最適です。OpenCVの動体検知やLINE APIの活用を通じて、実践的なPythonプログラミングスキルも身につきます。ぜひ自宅のセキュリティ強化に役立ててください!

次のステップとして、OpenCVで顔認識を追加してさらに精度を高める方法や、Raspberry Piで作るIoTプロジェクト一覧もあわせてご覧ください。

ABOUT ME
やまちゃん
これまで学生と社会人を合わせて5000人以上にプログラミング学習を指導。 ゼロからイチをわかりやすく解説する専門家として活動しており、本業ではArduinoを用いたIoT開発とロボットプログラミングが専門。 Pythonを用いたアプリ開発、ウェブアプリケーションの開発で業務の効率化をサポートしています。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です