はじめに
- 従来AIは学習させて使用するものでしたが、最近は汎用の学習済みモデルをダウンロードして使えるようになってます。この1つに__YOLOV5__があります。
- これを利用して、カメラ付きノートPCをAI監視カメラ( = 物体認識するカメラ)にしてみました。
- CPUだけでどれだけの速さになるか、試したかったためです。
工夫したこと
- ローカル化
 ネットワーク環境に縛られず、使えるようにしました。
- PCカメラから映像取り込み
 カメラからの映像を処理するようにしました。
- 推定検出の処理軽量化
 ハイスペックでないPCで動かすために、処理を減らしました。
- 正確性は劣るが軽量なモデル__yolov5s__を使用
- 推定時の画像を小さくして軽量化
- 検出結果の変数取得
 検出結果の矩形を取得し、ヒットエリアに入ったら、表示を変更するようにしました。
内容
1.PC環境
実施したPC環境は以下のとおりです。GPUは計算に使ってません。
| CPU | Celeron N4100 | 
| メモリ | 8GB LPDDR4 | 
2.前準備
 Windowsで使えるようにするため、以下のツール / システムをインストールしました。
インストール時に参考にしたサイトも記載します。
1.python(使用したのはVer.3.7 )
 実行時のベースシステムです。
(参考)https://qiita.com/ssbb/items/b55ca899e0d5ce6ce963
2.pip(使用したのはVer.21.2.4 )
 他のツールをダウンロードする際に使うツールです。
(python3系ではバージョン3.4以降であれば、pythonのインストールと共にpipもインストールされます。)
(参考)https://gammasoft.jp/python/python-library-install/
3.OpenCV(使用したのはVer.4.5.3 )
 画像系処理するためのライブラリです。
(参考)https://qiita.com/ideagear/items/3f0807b7bde05aa18240
4.PyTorch(使用したのはVer.1.9.1+cpu )
 DeepLearningのライブラリです。CPUだけでやるため、Compute PlatformはCPUにしました。
(参考)https://qiita.com/thinknee/items/0c0c466928356c9a55af
5.YOLOV5(使用したのはVer.5.0 )
 物体検出のアルゴリズムです。
(参考)https://github.com/ultralytics/yolov5
5.yolov5s.pt
 使用する学習済みモデルです。
YOLOV5のフォルダで、例えば以下のコードを実行すると自動でダウンロードされます。
detect.py --source data/images/bus.jpg --weights yolov5s.pt
 次に組むpyファイルと同じフォルダに置きます。
 (このptファイルは、pyファイルを実行したときになければ、自動でダウンロードされます。)
3.pyファイルの作成
組んだコードは次のとおりです。
import sys
import cv2
import torch
# --- 検出する際のモデルを読込 ---
# model = torch.hub.load('ultralytics/yolov5','yolov5s')#--- webのyolov5sを使用
model = torch.hub.load("../yolov5",'yolov5s',source='local')#--- localのyolov5sを使用
# --- 検出の設定 ---
model.conf = 0.5 #--- 検出の下限値(<1)。設定しなければすべて検出
model.classes = [0] #--- 0:person クラスだけ検出する。設定しなければすべて検出
# print(model.names) #--- (参考)クラスの一覧をコンソールに表示
# --- 映像の読込元指定 ---
# camera = cv2.VideoCapture("../pytorch_yolov3/data/sample.avi")#--- localの動画ファイルを指定
camera = cv2.VideoCapture(0)                #--- カメラ:Ch.(ここでは0)を指定
# --- 画像のこの位置より左で検出したら、ヒットとするヒットエリアのためのパラメータ ---
pos_x = 240
while True:
# --- 画像の取得 ---
#  imgs = 'https://ultralytics.com/images/bus.jpg'#--- webのイメージファイルを画像として取得
#  imgs = ["../pytorch_yolov3/data/dog.png"] #--- localのイメージファイルを画像として取得
  ret, imgs = camera.read()              #--- 映像から1フレームを画像として取得
# --- 推定の検出結果を取得 ---
#  results = model(imgs) #--- サイズを指定しない場合は640ピクセルの画像にして処理
  results = model(imgs, size=160) #--- 160ピクセルの画像にして処理
# --- 出力 ---
# --- 検出結果を画像に描画して表示 ---
  #--- 各検出について
  for *box, conf, cls in results.xyxy[0]:  # xyxy, confidence, class
      #--- クラス名と信頼度を文字列変数に代入
      s = model.names[int(cls)]+":"+'{:.1f}'.format(float(conf)*100)
      #--- ヒットしたかどうかで枠色(cc)と文字色(cc2)の指定
      if int(box[0])>pos_x :
        cc = (255,255,0)
        cc2 = (128,0,0)
      else:
        cc = (0,255,255)
        cc2 = (0,128,128)
      #--- 枠描画
      cv2.rectangle(
          imgs,
          (int(box[0]), int(box[1])),
          (int(box[2]), int(box[3])),
          color=cc,
          thickness=2,
          )
      #--- 文字枠と文字列描画
      cv2.rectangle(imgs, (int(box[0]), int(box[1])-20), (int(box[0])+len(s)*10, int(box[1])), cc, -1)
      cv2.putText(imgs, s, (int(box[0]), int(box[1])-5), cv2.FONT_HERSHEY_PLAIN, 1, cc2, 1, cv2.LINE_AA)
  #--- ヒットエリアのラインを描画
  cv2.line(imgs, (pos_x, 0), (pos_x, 640), (128,128,128), 3)
  #--- 描画した画像を表示
  cv2.imshow('color',imgs)
# --- (参考)yolo標準機能を使った出力 ---
#  results.show()#--- yolo標準の画面表示
#  results.print()#--- yolo標準のコンソール表示
# --- (参考)yolo標準の画面を画像取得してopencvで表示 ---
#  pics = results.render()
#  pic = pics[0]
#  cv2.imshow('color',pic)
  #--- 「q」キー操作があればwhileループを抜ける ---
  if cv2.waitKey(1) & 0xFF == ord('q'):
    break
4.説明
1. ローカル化
以下のhub関数のコードのところを1行目から2行目のように書き換え、ローカル処理にしました。
# model = torch.hub.load('ultralytics/yolov5','yolov5s')#--- webのyolov5sを使用
model = torch.hub.load("../yolov5",'yolov5s',source='local')#--- localのyolov5sを使用
2. PCカメラから映像取り込み
以下のコードのところを1行目から2行目のように書き換え、カメラ画像を取り込むようにしました。
# camera = cv2.VideoCapture("../pytorch_yolov3/data/sample.avi")#--- localの動画ファイルを指定
camera = cv2.VideoCapture(0)                #--- カメラ:Ch.(ここでは0)を指定
3. 推定検出の処理軽量化
- 正確性は劣るが軽量なモデル__yolov5s__を使用
 以下のコードで__yolov5s__を使うようにしました。
model = torch.hub.load("../yolov5",'yolov5s',source='local')#--- localのyolov5sを使用
 YOLOV5のモデルには、yolov5n、yolov5s、yolov5m、yolov5l、yolov5xなどがあります。
(参考)https://github.com/ultralytics/yolov5/releases
- 推定時の画像を小さくして軽量化
 以下のコードのところを1行目から2行目のように書き換え、処理画像を荒く小さくしました。
#  results = model(imgs) #--- サイズを指定しない場合は640ピクセルの画像にして処理
  results = model(imgs, size=160) #--- 160ピクセルの画像にして処理
4. 検出結果の変数取得
以下のコードで各検出の変数をfor文で取得しました。
  for *box, conf, cls in results.xyxy[0]:  # xyxy, confidence, class
変数種類とこのコードにて代入される変数名の対応は下表のとおりです。
| 変数種類 | 変数名 | 
|---|---|
| 矩形の左上角のX座標 | box[0] | 
| 矩形の左上角のY座標 | box[1] | 
| 矩形の右下角のX座標 | box[2] | 
| 矩形の右下角のY座標 | box[3] | 
| クラスの番号 | cls | 
| 推定の信頼度 | conf | 
 これらの変数を利用して、後処理を変えることができます。
今回はヒットエリア(画面の左側)で検出したものは枠の色を変更するようにしました。
5.結果
 カメラ映像でも遅延が気にならない速さで処理できました。
ちなみに、results = model(imgs, size=160)のところでsize=160をsize=80にするともっと速く処理できますが、検出ミスがひどくなりました。逆にsize=320にすると遅延が気になるところまで遅くなりました。