【Mac M4 ANE】YOLOv8とPythonで監視カメラを自作!Discord通知と誤認識対策までの全開発記録

Python

こんにちは、Tech Samuraiです!
Mac mini (M4) いいですね。このマシンの魅力は、なんといっても強力な**Neural Engine (ANE)**です。このANEのAI処理能力を活かし、低消費電力でインテリジェントな監視カメラシステムを自作できないかと考え、挑戦してみました。

今回のプロジェクトは、単にYOLOv8を動かすだけでなく、**「常時録画」**と**「イベント(人物検出)録画」**を両立させ、検出時には**Discordに動画を即時通知**。最終的には、影などによる**誤認識をフィルタリング**するロジックを組み込み、**OSログイン時に自動起動**する、という実用的なシステムを目指しました。

この記事では、シンプルな録画スクリプトが、段階的な改良を経て、堅牢な監視システムへと進化していく全プロセスを、V1からV3までのバージョンに分けて紹介します。


プロジェクトの概要と環境

  • ハードウェア: Mac mini (M4), USBカメラ
  • AIモデル: YOLOv8n (Core ML形式に変換してANEで実行)
  • 開発環境: Rye (Python 3.12.9)
  • 主要ライブラリ: ultralytics, opencv-python, coremltools, discord-py, python-dotenv

ステップ0:YOLOモデルをANE用に変換

まず、MacのNeural Engine (ANE) でYOLOを高速に動かすため、標準の.pt`モデルをCore ML形式 (.mlpackage) に変換します。ultralyticsライブラリを使えば、これは非常に簡単です。

# export_model.py
from ultralytics import YOLO
import sys

MODEL_NAME = 'yolov8n'
PT_FILE = f'{MODEL_NAME}.pt'
PACKAGE_FILE = f'{MODEL_NAME}.mlpackage'

print(f"[{MODEL_NAME}] モデルをロードしています...")
model = YOLO(PT_FILE)

print(f"[{MODEL_NAME}] をCore ML ({PACKAGE_FILE}) 形式にエクスポートします...")
model.export(format='coreml')
print(f"✅ 成功: '{PACKAGE_FILE}' が作成されました。")

このyolov8n.mlpackage`ファイルを、スクリプトから読み込みます。


ステップ1 (V1):検出とデュアル録画

最初のバージョンでは、監視カメラの基本機能である「常時録画」と「イベント録画」を実装しました。

  • Core MLモデルのロード: model = YOLO('yolov8n.mlpackage', task='detect') のように、ANEで動作するモデルを読み込みます。
  • 常時録画 (Low FPS): カメラからの映像を常時1FPSで録画し、3時間ごとに新しいファイルにローテーションします。
  • イベント録画 (High FPS): YOLOが人(クラスID 0)を検出したら、5FPSで20秒間の高画質録画を開始します。
  • タイムスタンプ: 録画される全フレームに、cv2.putText`で日時を焼き付けます。

この時点で、基本的な監視録画システムは完成しましたが、設定がすべてコード内にハードコードされており、検出しても通知が来ないため、実用性はまだ低い状態でした。


ステップ2 (V2):Discord通知と設定の外部化

V1の課題を解決するため、2つの大きな機能改善を行いました。

1. 設定の外部化 (`.env` ファイル)

python-dotenv`を導入し、カメラ番号、FPS、録画時間、YOLOのモデルパス、そしてDiscordのトークンIDなど、すべての設定値を.env`ファイルに分離しました。これにより、コードを触ることなく環境の変更に対応できます。

# .env.sample の一部
DISCORD_TOKEN="YOUR_DISCORD_BOT_TOKEN_HERE"
DISCORD_CHANNEL_ID="YOUR_CHANNEL_ID_HERE"
COREML_MODEL_PATH="yolov8n.mlpackage"
TARGET_CLASS_ID=0
CONF_THRESHOLD=0.5

2. Discordへのイベント通知

discord-py`を導入。OpenCVのメインループとは別に、Discord Botを**別スレッド (`threading`)** で起動します。イベント録画が完了した時点、またはCtrl+C`でスクリプトが中断された時点で、録画された.mp4`ファイルをDiscordチャンネルに自動で送信するロジックを追加しました。


ステップ3 (V3):誤認識(影)対策のフィルタリング

V2を運用してみると、新たな問題が発生しました。それは**「誤認識(偽陽性)」**です。夜間に車のヘッドライトが動いたり、昼間に影が動いたりすると、YOLOが一瞬だけ「人」と誤検出し、不要なイベント録画と通知が多発しました。

この問題を解決するため、シンプルなフィルタリングロジックを導入しました。

対策: .env`ファイルにDETECTION_STREAK_THRESHOLD=3`という設定を追加。YOLOが「**3回連続**」で人を検出し続けて初めて、システムが「本当に人が検出された」と判断し、イベント録画を開始するようにロジックを変更しました。

# main_monitor_discord.py のメインループから抜粋
# ...
person_detected_this_frame, frame = run_yolo_ane(frame, model)

if person_detected_this_frame:
    detection_streak_counter += 1
    # 連続検出カウンターが閾値を超えたか?
    if not is_person_confirmed_state and detection_streak_counter >= DETECTION_STREAK_THRESHOLD:
        print(f"[INFO] 検出が {detection_streak_counter} 回続きました。イベントを確定します。")
        is_person_confirmed_state = True # イベント確定
else:
    # 検出が途切れたらカウンターをリセット
    if detection_streak_counter > 0:
        print(f"[INFO] 検出が途切れました (Streak: {detection_streak_counter})。リセットします。")
    detection_streak_counter = 0

# ...
# イベントが確定 (is_person_confirmed_state == True) している場合のみ録画開始
if is_person_confirmed_state:
    if writer_high is None:
        writer_high, high_filename = create_new_writer(...)
    # ...

この単純なロジック追加により、影や光のチラつきによる一瞬の誤認識はほぼゼロになり、システムの信頼性が劇的に向上しました。


ステップ4:Macログイン時に自動起動 (`launchd`)

最後に、この監視システムを24時間稼働させるため、Macのログイン時に自動でスクリプトを実行するよう設定します。Macではlaunchd`という仕組みを使います。

1. 起動用シェルスクリプト (`start_cctv.sh`)
.env`ファイルなどを正しく読み込むため、スクリプトの実行ディレクトリに移動してから、Rye経由でPythonスクリプトを実行するシェルスクリプトを作成します。

#!/bin/sh
# スクリプトが置かれているディレクトリに移動
cd /you_project/CCTV

# Ryeを使ってメインスクリプトを実行
/opt/homebrew/bin/rye run python CCTV/main_monitor_discord.py

2. `launchd` 設定ファイル (.plist)
このシェルスクリプトを呼び出すための設定ファイルを、~/Library/LaunchAgents/com.user.cctvmonitor.plist`として保存します。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.cctvmonitor</string>

    <key>ProgramArguments</key>
    <array>
        <string>/bin/sh</string>
        <string>/your_strage/start_cctv.sh</string>
    </array>

    <key>RunAtLoad</key>
    <true/>

    <key>KeepAlive</key>
    <true/>

    <key>StandardOutPath</key>
    <string>/tmp/cctvmonitor.log</string>
    <key>StandardErrorPath</key>
    <string>/tmp/cctvmonitor.err</string>
</dict>
</plist>

これで、Macにログインするたびに、監視システムがバックグラウンドで自動的に起動し、/tmp/cctvmonitor.log`にログを吐き出すようになります。


完成したリポジトリ

この開発の全コードは、以下のGitHubリポジトリで公開しています。.env.sample`を参考に、ご自身の環境に合わせて設定してご使用ください。


まとめ

Mac mini (M4) のNeural Engine (ANE) は、YOLOv8のようなAIモデルを低消費電力で動かすのに最適でした。シンプルな検出スクリプトから始め、段階的に機能を追加することで、最終的にはDiscordとも連携する実用的な監視システムを構築できました。特に「連続検出フィルタリング」は、実運用において非常に効果的なロジックでした。

皆さんも、手元のMacでAIを活用したプロジェクトに挑戦してみてはいかがでしょうか?

コメント

タイトルとURLをコピーしました