[2日目] 学校の食堂をIT化させる話　混雑度カメラを開発するための人数の計測方法

こんにちは、なりかくんと申します。
この記事はなりかくん Advent Calender 2023の2日目の記事です。

この話は、1日目から始めた学校の食堂をIT化させる話の続きとなります。まだ、1日目の記事を読んでいない方は「どのようにIT化させるか」を1日目に紹介しているので先にそちらをお読みください。

# 混雑度をどのように確認するのか
今回は、カメラとYOLOv8というモデルを活用して混雑度を視覚化していこうという結論になりました。

それまでにどのような選択肢があったのかをメモ程度に残してあったので紹介します。

# 人数を計測する方法
まず、人数を計測する方法ですがカメラで人間を認識して、人数を数える方法と超音波センサーなどで部屋への入退室をカウントする２つの方法が最初に思いつきました。
そこで、それぞれのメリットとデメリットを考えました。

## カメラのメリット
- AIの深層学習を利用して、人間かどうかを判断することができる

## 超音波センサーのメリット
- カメラよりも安価で簡単に設置可能
- プライバシーに配慮することができる

## カメラのデメリット
- 人との重なりなどを正しく認識できない可能性がある
- プライバシー問題が存在する

## 超音波センサーのデメリット
- 複数人が同時に入退室した場合や、超音波センサーの前を何回も通った際に記録がおかしいことになる
- 人以外の物体との区別が難しい

このような点から今回は最新のAIを活用して現在の人数を判定をしていきたいと考えたため、カメラの方式で混雑度を計測していこうと思います。

# カメラで人間を検出する方式
人間を検出する際に、まず最初に物体検出を行うのが基本的ですが、その物体検出をどのように行っていくのかに関しても２種類の案が出ました。

## Haar-Like特徴方式
Haar-Like特徴方式とは、画像の明暗差を特徴化し、いくつもの処理結果を組み合わせることで物体を判断する仕組みらしいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/936ee147-989b-d41b-8d15-d2201068ef31.png)

### Haar-Like特徴方式のメリット
- OpenCVに標準でデータが用意されているので楽に使える
- 処理が非常に軽い

### Haar-Like特徴方式のデメリット
- 検出の精度が悪い

## Haar-Like特徴方式を試す
実際にPythonでHaar-Like特徴方式で検知するのを試してみます。
今回は、以下のhitomatagiさんの「OpenCVを使った顔認識（Haar-like特徴分類器）」を参考にして実際に試してみます。

https://qiita.com/hitomatagi/items/04b1b26c1bc2e8081427

今回、Haar-like特徴分類器の「haarcascade_fullbody.xml」（全身）を利用します。

検出結果はこのようになりました。4人しか検出することが出来ませんでした。

ただし、処理にかかった時間は私の環境で 254ミリ秒 でした。非常に軽くいいですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/3b0f83e7-9552-fcd8-ae5a-bd1362d6b8df.png)

※画像は、「[歌舞伎町 ライブ ちゃんねる『 Kabukicho Live Channel 』](https://www.youtube.com/@kabukicho-1)」様からお借りしました。

<details><summary>Haar-like特徴の実験で利用したコード</summary>

```python
import cv2
import time
# 処理時間計測開始
start = time.time()

# Haar-like特徴分類器の読み込み
face_cascade = cv2.CascadeClassifier('haarcascade_fullbody.xml')

# イメージファイルの読み込み
img = cv2.imread('sample.png')

# グレースケール変換
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 顔を検知
faces = face_cascade.detectMultiScale(gray)
for (x,y,w,h) in faces:
    # 検知した顔を矩形で囲む
    cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)

# 画像表示
cv2.imshow('img',img)

# 処理時間計測
end = time.time()

time_diff = end - start
print(time_diff)

# 何かキーを押したら終了
cv2.waitKey(0)
cv2.destroyAllWindows()
```
</details>

## YOLOv8
YOLOv8は、Ultralyticsが開発している検出モデルの名称です。物体検出だけではなく、画像分類やセグメンテーションなどを行うことも出来る優れた方法です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/17e6fab5-8704-93ad-5fd4-123ccd242d59.png)

### YOLOv8のメリット
- 処理が高速（ただしOpenCVほどではない）
- 精度が非常に高い

### YOLOv8のデメリット
- 小さい物の検出が苦手
- モデルデータがHaar-Like特徴方式よりもはるかに大きい

## YOLOv8を試す
実際にPythonでYOLOv8で検知するのを試してみます。

学習モデルは、公式から出ている「YOLOv8n」を利用します。

結果はこのようになりました。15人検出することが出来ました。

処理にかかかった時間は、1,953ミリ秒でした。非常に精度が良くていいですね。

![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/c1384b2c-4600-ec84-5c60-2d4783754a87.png)

<details><summary>YOLOv8の実験で利用したコード</summary>

```python
from ultralytics import YOLO
import cv2
import time
# 処理時間計測開始
start = time.time()

# モデル読み込み
model = YOLO("yolov8n.pt")

# 入力画像
results = model('sample.png', save=True, save_txt=True, save_conf=True)

# 処理時間計測
end = time.time()

time_diff = end - start
print(time_diff)

```
</details>


## Haar-Like特徴方式とYOLOv8の比較
では、簡単に比較表を作りました。
圧倒的に精度では、YOLOv8の方が優勢ですね。

混雑度を測るためにある程度の精度が必要なので、今回はYOLOv8を採用することとします。

| | Haar-Like特徴方式 | YOLOv8 |
|:--:|:--:|:--:|
| 処理時間 | 254ms | 1,953ms |
| 精度 | 4人 | 15人 |
| 画像 | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/3b0f83e7-9552-fcd8-ae5a-bd1362d6b8df.png) |  ![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/c1384b2c-4600-ec84-5c60-2d4783754a87.png) |

# 最後に
今回は、混雑度カメラを開発するにあたっての人数の検出方法についてまとめました。
最後までお読みいただきありがとうございました。