PythonでOpenCVの背景差分を使って、物体カウントと監視カメラアプリを作ってみた！

# はじめに
今回は、Pythonで画像処理のOpenCVのライブラリーの背景差分の機能を使って、硬貨の数をカウントするアプリと、録画機能付きの監視カメラアプリを作成してみましたので、ご紹介します。

# 環境
Windows10
Python3.11.8
VSCode

# 使用ライブラリー
opencv-python 4.9.0.80

#OpenCVのインストール:
```
pip install opencv-python
```

# YouTubeでの解説：
上記のインストール方法から、サンプルプログラムの実行までをYoutubeで詳しく解説していますので、ぜひ、ご覧ください。


https://youtu.be/8gQ4le1RBhk

Youtube動画です。

<iframe width="560" height="315" src="https://www.youtube.com/embed/8gQ4le1RBhk" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" loading="lazy" allowfullscreen></iframe>



# 硬貨の枚数カウントアプリ
プログラムの概要イメージです。

![説明1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1361368/bb86dfa6-f6a0-608b-49c5-5dfcc9c00069.jpeg)


YouTubeで紹介しているコインのカウントアプリのプログラムソースです。

```Python:opencv_背景差分_2.py
import cv2

# 背景画像の取得
cap = cv2.VideoCapture(0)  # カメラを起動する
_, background = cap.read()  # 最初のフレームを背景画像として取得q

# 背景画像をグレースケールに変換
background_gray = cv2.cvtColor(background, cv2.COLOR_BGR2GRAY)

# メインの処理
while True:
    # カメラからフレームを取得
    _, frame = cap.read()

    # グレースケールに変換
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # 背景差分を計算
    diff = cv2.absdiff(frame_gray, background_gray)

    # 二値化処理
    _, thresh = cv2.threshold(diff, 60, 255, cv2.THRESH_BINARY)

    # モルフォロジー処理（オープニング）
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
    thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)

    # 物体を検出した領域を描画
    contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnt = 0

    for contour in contours:
        if cv2.contourArea(contour) > 1000:  # 面積が一定以上のもののみ対象
            x, y, w, h = cv2.boundingRect(contour)
            cnt = cnt + 1
            cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

    # テキストを追加する
    text = f"Count={cnt}"
    font = cv2.FONT_HERSHEY_SIMPLEX
    org = (30, 50)  # テキストの開始位置
    fontScale = 1
    color = (255, 0, 0)  # テキストの色 (BGR形式)
    thickness = 2  # テキストの太さ

    # テキストを画像に追加する
    frame = cv2.putText(frame, text, org, font, fontScale, color, thickness, cv2.LINE_AA)

    # 結果を表示
    cv2.imshow("Frame", frame)
    cv2.imshow("Difference", thresh)

    # 'q'を押すと終了
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 後処理
cap.release()
cv2.destroyAllWindows()
```

# 監視カメラアプリ
監視カメラアプリの概要イメージです。

![説明2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1361368/5bae3f4f-996f-436e-a86f-585380a4fc43.jpeg)

Youtubeで紹介している、監視カメラアプリです。
```Python:opencv_監視カメラ_2
import cv2
from datetime import datetime

# 動画の読み込み
cap = cv2.VideoCapture(0)  # カメラを起動する

# 動画のフレームサイズを取得
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

# 出力動画の設定
output_video_path = "output_video.mp4"
output_video_fps = 30.0
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter(output_video_path, fourcc, output_video_fps, (frame_width, frame_height))

# フレームの差分を比較するための前のフレームを初期化
prev_frame = None

# メインの処理
while True:
    # カメラからフレームを取得
    _, frame = cap.read()

    # グレースケールに変換
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # 前のフレームがある場合にのみ、フレームの差分を計算
    if prev_frame is not None:

        # 背景差分を計算
        diff = cv2.absdiff(prev_frame,frame_gray)

        # 二値化処理
        _, thresh = cv2.threshold(diff, 50, 255, cv2.THRESH_BINARY)

        # モルフォロジー処理（オープニング）
        kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
        thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)

        # 物体を検出した領域を描画
        contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        cnt = 0

        for contour in contours:
            if cv2.contourArea(contour) > 1000:  # 面積が一定以上のもののみ対象
                x, y, w, h = cv2.boundingRect(contour)
                cnt = cnt + 1
                cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
        # テキストを追加する
        text = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
        font = cv2.FONT_HERSHEY_SIMPLEX
        org = (30, 50)  # テキストの開始位置
        fontScale = 1
        color = (255, 0, 0)  # テキストの色 (BGR形式)
        thickness = 1  # テキストの太さ
        # テキストを画像に追加する
        frame = cv2.putText(frame, text, org, font, fontScale, color, thickness, cv2.LINE_AA)
        
        if cnt > 1:
            out.write(frame)

    # 現在のフレームを前のフレームとして保存
    prev_frame = frame_gray.copy()

    # 結果を表示
    cv2.imshow("Frame", frame)

    # 'q'を押すと終了
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break


# 後処理
cap.release()
out.release()
cv2.destroyAllWindows()
```

# 最後に：
今回は、OpenCVのライブラリーの背景差分の機能を使って業務改善で役立ちそうな物体の数をカウントするアプリと、監視カメラアプリをご紹介しました。
今後も、他の機能を使ったアプリをご紹介していきたいと思います！