YOLOv8を実装し異常検知＆警報システムを自作する

##### YOLOは1回の畳み込みニューラルネットワーク（CNN）で処理する物体検出モデルです。画像全体を1つのグリッドに分割し、物体の存在を一括で解析、検出するため高速で誤検出が少なくなります（との事です）。
---
##### 今回トライするのは、先ずは動体検知と通知システムです。
:::note info
1.接続したカメラでリアルタイム監視をする
2.検知すると音声アラートを出す（Windowsのみ）
3.動画でターゲットを表示する
4.ログを残す
5.メールで通知する
6.スナップショットを保存
:::
```python
import cv2  # OpenCV（カメラ映像取得）
import torch  # PyTorch（YOLOを動かすため）
import datetime  # 日時の取得
import winsound  # 音声アラート（Windows）
import smtplib  # メール送信
from email.mime.text import MIMEText  # メール送信用
from ultralytics import YOLO  # 最新の YOLOv8 を使用

# 🔹 GPUを使用可能ならCUDA、なければCPUを使用
device = 'cuda' if torch.cuda.is_available() else 'cpu'

# 🔹 YOLOv8モデルをロード（物体検出用）
model = YOLO("yolov8s.pt")

# 🔹 カメラを開く（0はデフォルトのカメラ）
cap = cv2.VideoCapture(0)

if not cap.isOpened():
    print("カメラが開けませんでした。プログラムを終了します。")
    exit()

# 🔹 監視ログファイルを作成
log_file = "detection_log.txt"

with open(log_file, "w") as f:
    f.write("=== 監視カメラログ ===\n")

# 🔹 メール通知設定
EMAIL_SENDER = "＜メアド＞"
EMAIL_PASSWORD = "＜パスワード＞"
EMAIL_RECEIVER = "＜メアド＞"

def send_alert(message):
    """ 検出した異常をメールで送信 """
    msg = MIMEText(message)
    msg["Subject"] = "【監視カメラアラート】異常検出"
    msg["From"] = EMAIL_SENDER
    msg["To"] = EMAIL_RECEIVER

    try:
        # with smtplib.SMTP_SSL("＜メールサーバ＞", 465) as server: SSLの場合
        with smtplib.SMTP("＜メールサーバ＞", 587) as server:
            server.starttls()
            server.login(EMAIL_SENDER, EMAIL_PASSWORD)
            server.sendmail(EMAIL_SENDER, EMAIL_RECEIVER, msg.as_string())
        print("📩 メール通知を送信しました！")
    except Exception as e:
        print("⚠️ メール通知の送信に失敗しました:", e)
        
# 🔹 監視を続ける
while True:
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
    
    ret, frame = cap.read()  # カメラの映像を取得
    if not ret:
        print("カメラの映像が取得できません。終了します。")
        break

    # 🔹 YOLOv8 で物体検出
    results = model(frame)

    # 🔹 検出されたオブジェクトをログに記録
    detected_objects = []
    for result in results:
        for box in result.boxes:
            class_id = int(box.cls[0])  # クラスID（例：人、車、犬など）
            confidence = float(box.conf[0])  # 信頼度
            label = model.names[class_id]  # クラス名（YOLOのラベル）

            # ログに保存
            detected_objects.append(f"{label}（信頼度: {confidence:.2f}）")

    # 🔹 もし物体が検出されたらログに書き込み、アラートを鳴らす
    if detected_objects:
        now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_text = f"{now} - 検出: {', '.join(detected_objects)}\n"
        print(log_text)

        with open(log_file, "a") as f:
            f.write(log_text)

        # 🔹 スクリーンショットを保存
        filename = f"screenshot_{now.replace(':', '-')}.jpg"
        cv2.imwrite(filename, frame)

        # 🔹 音声アラート（Windowsのみ）
        winsound.Beep(1000, 500)  # 1kHzの音を0.5秒鳴らす

        # 🔹 メール通知
        send_alert(log_text)

    # 🔹 YOLOの検出結果を描画
    frame_with_detections = results[0].plot()

    # 🔹 画面にリアルタイム映像を表示
    cv2.imshow("Security Cam", frame_with_detections)

    # 🔹 'q'キーで監視終了
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 🔹 カメラを解放し、ウィンドウを閉じる
cap.release()
cv2.destroyAllWindows()
```
#### では、早速このプログラムを実行してみます。
```
$ python <このプログラム名>.py
0: 480x640 1 person, 1 tie, 128.8ms
Speed: 3.1ms preprocess, 128.8ms inference, 1.4ms postprocess per image at shape (1, 3, 480, 640)
2025-03-03 19:51:49 - 検出: person（信頼度: 0.89）, tie（信頼度: 0.25）

📩 メール通知を送信しました！

0: 480x640 1 person, 121.6ms
Speed: 2.6ms preprocess, 121.6ms inference, 0.7ms postprocess per image at shape (1, 3, 480, 640)
2025-03-03 19:51:54 - 検出: person（信頼度: 0.73）

📩 メール通知を送信しました！
```
#### うん！？早速、何者かが侵入して来た様だ！！ 
#### ログを見てみると確かに何者かが検知されている！！
```
C:\Users> type detection_log.txt
=== 監視カメラログ ===
2025-03-03 19:51:49 - 検出: person（信頼度: 0.89）, tie（信頼度: 0.25）
2025-03-03 19:51:54 - 検出: person（信頼度: 0.73）
2025-03-03 19:51:57 - 検出: person（信頼度: 0.94）, tie（信頼度: 0.30）
2025-03-03 19:52:00 - 検出: person（信頼度: 0.94）
```
#### 犯人はこいつだった！！画像もしっかりと取られていた！
screenshot_2025-03-03 22-17-27.jpg
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348536/24414776-b4da-42c2-81cb-30cd3d876293.png)