更新日:2023年6月3日
概要
①【YOLOv5】で動画からネコ検出(=^・・^=)
②【YOLOv8】をWindowsで動かす手順
③【YOLOv8】WindowsでWEBカメラからリアルタイム物体検出
④【YOLOv8】WindowsでWEBカメラからリアルタイム物体検出してメッセージボックス表示
【プロジェクトにゃーん4】
家の近くを散歩するネコちゃんをリアルタイムで検出して
アラートを飛ばしたい!!
さて、前回は【YOLOv8】でWEBカメラからリアルタイム物体検出できるとこまでやりましたので、今回は、出力結果からアラートを飛ばしてみたいと思います。
環境
環境:Winows11、メモリ32GB、GPU GeForce RTX3060 12GB
Python : 3.10.6、CUDA : 11.8、torch : 2.0.1+cu118
webcamera:Logicool(ロジクール) C270n
よくあるWEBカメラです。
2,500円くらいと安いけど使いやすくておすすめです。
後継版C310n ↓↓
※GPUをこれから購入を考えている方は
このRTX3060の12GB版の一択になるかと思います。(2023年6月時点)
理由は、コスパが最強なので!!
画像生成Stable Diffusionを使う場合、最低メモリ12GBほしいところなのですが、けっこうお高い買い物になるため躊躇されるかもしれません。
しかし!!こちらは5万円を切る圧倒的安さ!
ちなみに私は上位のRTX3070superだったのですが、メモリが8GBと画像生成には不足していたのでダウングレードしてこちらに乗り換えました。
交換作業は簡単なのですが、自分のPCに取り付け可能かは確認してくださいね。
重要なのは電源容量と、接続PIN数、空間です。
手順
【YOLOv8】の設定は前回の記事↑を見てね。
1.リアルタイム検出の出力結果保存
さて、どのように出力できるか調べてみます。
predictのオプション詳細がdocsの中、下記にありました。
https://github.com/ultralytics/ultralytics/blob/main/docs/modes/predict.md
パラメータを直訳するとこんな感じです。
- save_txt=True 出力結果を保存
- save_conf=True 確信度も必要になりそうなのでこちらもTrueに
- vid_stride=1800
あと物体検出の回数が多すぎるのでそこを制御しないとですね。
フレームレート(fps)は1秒間の動画が何枚の画像で構成されているかを示す単位なので、こちらで制御できそうかな。
WEBカメラはよくある「30fps」を使っているので1秒で30枚ですね。
ただ。。どのように使うかは書かれていなさそうなので
とりあえず引数に追加して試してみますかね。
デフォルトは1っぽいので
とりあえず、1800フレームで1分なので1800にしてみました。
from ultralytics import YOLO
model = YOLO("yolov8x.pt")
model.to("cuda")
# WEBカメラからリアルタイム検出
results = model(0 , show=True, save_txt=True, save_conf=True, vid_stride=1800)
for i in enumerate(results):
print(i)
「runs/detect/predict/labels」に一応出力されました!
中身はこんな感じ
一番左の番号が物体番号っぽい
続いて座標、一番右が確信度ですね。
vid_stride=1800にしたことで
画面上の検出は1分に1回になってたようだが
出力txtが1000ファイル以上出ちゃってる
結局検出してるじゃん。
vid_stride=1800はshowの設定か、別の制御がいるのね。。
2.物体検出頻度の制御
苦戦しました。。
- subprocessで呼び出す方法 ➡失敗
- importで「webcam.py」を呼び出しintervalで定期起動する方法 ➡失敗
- ultralytics\yolo\engineの「results.py」を修正 ➡成功
10秒に1回検出するようにしました。
まずwebcam.pyを作ります。
画面で確認する必要はないのでshowは削除。
webcam.py
from ultralytics import YOLO
#model = YOLO("yolov8x.pt")
model = YOLO("yolov8m.pt")
model.to("cuda")
# WEBカメラからリアルタイム検出
results = model(0, show=True, save_txt=True, save_conf=True)
for i in enumerate(results):
print(i)
【追記】
「YOLOv8x」で動かしていましたが、けっこうGPU使用量が大きいので
軽い「YOLOv8m」の方が無難です。猫検出くらいならmでも十分だと思います。
ultralytics\yolo\engineの「results.py」
import timeとtime.sleep(10)を追記します。
def save_txt(self, txt_file, save_conf=False):
"""
Save predictions into txt file.
Args:
txt_file (str): txt file path.
save_conf (bool): save confidence score or not.
"""
boxes = self.boxes
masks = self.masks
probs = self.probs
kpts = self.keypoints
texts = []
if probs is not None:
# Classify
n5 = min(len(self.names), 5)
top5i = probs.argsort(0, descending=True)[:n5].tolist() # top 5 indices
[texts.append(f'{probs[j]:.2f} {self.names[j]}') for j in top5i]
elif boxes:
# Detect/segment/pose
for j, d in enumerate(boxes):
c, conf, id = int(d.cls), float(d.conf), None if d.id is None else int(d.id.item())
line = (c, *d.xywhn.view(-1))
if masks:
seg = masks[j].xyn[0].copy().reshape(-1) # reversed mask.xyn, (n,2) to (n*2)
line = (c, *seg)
if kpts is not None:
kpt = (kpts[j][:, :2] / d.orig_shape[[1, 0]]).reshape(-1).tolist()
line += (*kpt, )
line += (conf, ) * save_conf + (() if id is None else (id, ))
texts.append(('%g ' * len(line)).rstrip() % line)
if texts:
time.sleep(10)
with open(txt_file, 'a') as f:
f.writelines(text + '\n' for text in texts)
これで10秒ごとにtxtが出力されるようになりました。
3.クラスIDの確認
まずはネコちゃんが何番なのか調べます。
物体検出モデル、特にYOLO系列のモデルでは、各物体カテゴリ(人間、車、犬など)は一意のID(通常は整数)で識別されます。
このIDはデータセットに依存しているので、学習データで使っているCOCOデータセットのクラスIDのようですね。
COCO Dataset Class Labels
15番が猫ちゃんですね。
4.検出結果からメッセージボックスを表示させる
runs\detect ディレクトリとそのすべてのサブディレクトリを監視して
新しく作成された.txtファイルが存在して、そのファイルの中身が条件を満たす場合、アラート音を出して10秒間メッセージボックスを表示させる。
手順2で作った「webcam.py」を起動させた状態で
別のコマンドプロンプトで「」
条件:クラスID=15、確信度>=0.7
「tkinter.messagebox」「watchdog」「winsound」を使います。
"import tkinter"ができない場合
Pythonインストール時にtkinterにチェックを入れていなかったことが考えられます。
Python exeから「Modify」を押して「td/tk and IDLE」にチェックをいれて実行すればインストールされます。
watchdogは「pip install watchdog」でインストール。
winsound
Python標準ライブラリでアラート音を鳴らすことができます。このライブラリはWindows専用なので、他のOSでは利用できません。
作成したコードがこちら
tkinterオリジナルのメッセージボックスだと自動で閉じるのができなさそうだったのでメッセージだけ表示するようにしています。
webcam.py
import os
import time
import winsound
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from tkinter import Tk, Label, TOP
class MyHandler(FileSystemEventHandler):
def on_created(self, event):
filepath = event.src_path
if filepath.endswith('.txt'):
with open(filepath, 'r') as f:
lines = f.readlines()
for line in lines:
cols = line.strip().split()
if cols[0] == "15" and float(cols[5]) >= 0.5:
self.show_message('Condition matched in file: ' + filepath)
def show_message(self, message):
root = Tk()
root.overrideredirect(1) # ウィンドウのタイトルバーと枠を削除
root.after(10000, root.destroy) # 10秒後にウィンドウを自動的に閉じる
Label(root, text=message, padx=20, pady=20).pack(side=TOP, fill='both', expand=True)
winsound.MessageBeep() # Windowsのアラート音を鳴らす
root.mainloop()
if __name__ == "__main__":
path = r'runs\detect'
event_handler = MyHandler()
observer = Observer()
observer.schedule(event_handler, path, recursive=True)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
こんな感じのメッセージボックスがアラート音と共に表示されます!!
これを起動しておけばパソコン作業中でも外にネコちゃんが散歩してたら気付くことができますね~
ちらちら確認しなくても癒しタイムを逃しません!!
やりました(=^・・^=)
====================================
【おすすめ書籍】
2023年7月発売
鋭い洞察と深みのある言葉がささります。
読み物としてお勧め。なので電子版でもいいです。
2023年10月発売
AI、データ活用が必須の時代に。
豊富な企業事例で自社や自分を俯瞰できると思います。
【お勧めアイテム】
肩こりに悩むエンジニアの皆様へ!!!
私も慢性的な重度の肩こりプログラマですが
数年間いろいろな枕を買っては捨ててを繰り返してきまして
やーーーーっといい枕に出会いました。
朝起きて首が痛くない!すばらしい
横向けでも仰向けでもいい感じに寝ることができています。
ので肩こりが多いエンジニアの皆様にお勧めします。
高価ですが、整体2回分と考えたら安いものですね笑
====================================
以上、【YOLOv8】WindowsでWEBカメラからリアルタイム物体検出してメッセージボックス表示 でした。
次はメールかLINEに通知を飛ばしたいですね つづく
ではまた。