Yolov8検出結果と文字列の結び付け
在庫管理のため yolov8で在庫対象とするものを検出し
その在庫数が2以下になれば
LINEで買い物リストを送信するものを作成したい
このためには検出結果のカウント
そして
検出されたものを日本語にする必要がある
YOLOv8の検出結果と対応する文字列を結びつけるためには、
検出されたクラスのラベルを
日本語の対応するラベルに変換するマッピングを作成する必要があり
まずYOLOv8の結果取得:
画像をYOLOv8に入力し、検出結果を取得
検出結果には
各物体のクラスラベル
バウンディングボックスの座標などが含まれている
そして
クラスラベルのマッピング作成
検出されたクラスラベルを
日本語の対応するラベルに変換する辞書を作成
例として
label_mapping = { 'baskulin': 'バスクリン', 'potato_starch': '片栗粉', 'shampoo': 'シャンプー' }
という感じ
以下はchatgptのコード例
import json # YOLOv8の検出結果の例 # ここではJSON形式で表現されていますが、実際にはYOLOv8から得られたデータ形式に合わせてください detection_results = [ {"class": "baskulin", "bbox": [100, 100, 150, 150]}, {"class": "potato_starch", "bbox": [200, 200, 250, 250]}, {"class": "shampoo", "bbox": [300, 300, 350, 350]}, ] # クラスラベルのマッピング label_mapping = { 'baskulin': 'バスクリン', 'potato_starch': '片栗粉', 'shampoo': 'シャンプー' } # マッピングの適用 for detection in detection_results: class_label = detection['class'] if class_label in label_mapping: detection['class'] = label_mapping[class_label] # 結果の表示 print(json.dumps(detection_results, ensure_ascii=False, indent=2))
yolov8の検出結果を表示するには?
とすると
import cv2 import matplotlib.pyplot as plt from ultralytics import YOLO # YOLOv8モデルのロード model = YOLO('yolov8s.pt') # ここで適切なモデルを選択 # 画像のロード image_path = 'path_to_your_image.jpg' image = cv2.imread(image_path) image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # 画像の検出 results = model(image) # 検出結果の取得 detections = results[0] # 最初の結果を取得 classes = detections.boxes.cls boxes = detections.boxes.xyxy scores = detections.boxes.conf # クラスラベルのマッピング label_mapping = { 'baskulin': 'バスクリン', 'potato_starch': '片栗粉', 'shampoo': 'シャンプー' } # バウンディングボックスとラベルの描画 for cls, box, score in zip(classes, boxes, scores): class_label = model.names[int(cls)] if class_label in label_mapping: label = label_mapping[class_label] else: label = class_label x1, y1, x2, y2 = map(int, box) cv2.rectangle(image, (x1, y1), (x2, y2), (255, 0, 0), 2) cv2.putText(image, f'{label} {score:.2f}', (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (255, 0, 0), 2) # 結果の表示 plt.figure(figsize=(10, 10)) plt.imshow(image) plt.axis('off') plt.show()
となるが
バウンディングボックスとラベルを画像に描画
結果をMatplotlibを使って表示
となる
結果の表示で画像での結果表示は不要
from ultralytics import YOLO # YOLOv8モデルのロード model = YOLO('yolov8s.pt') # ここで適切なモデルを選択 # 画像のロード image_path = 'path_to_your_image.jpg' image = cv2.imread(image_path) # 画像の検出 results = model(image) # 検出結果の取得 detections = results[0] # 最初の結果を取得 classes = detections.boxes.cls boxes = detections.boxes.xyxy scores = detections.boxes.conf # クラスラベルのマッピング label_mapping = { 'baskulin': 'バスクリン', 'potato_starch': '片栗粉', 'shampoo': 'シャンプー' } # 検出結果のテキスト表示 for cls, box, score in zip(classes, boxes, scores): class_label = model.names[int(cls)] if class_label in label_mapping: label = label_mapping[class_label] else: label = class_label x1, y1, x2, y2 = map(int, box) print(f'検出: {label}, 信頼度: {score:.2f}, バウンディングボックス: ({x1}, {y1}, {x2}, {y2})') バウンディングボックスの座標も不要 from ultralytics import YOLO # YOLOv8モデルのロード model = YOLO('yolov8s.pt') # ここで適切なモデルを選択 # 画像のロード image_path = 'path_to_your_image.jpg' image = cv2.imread(image_path) # 画像の検出 results = model(image) # 検出結果の取得 detections = results[0] # 最初の結果を取得 classes = detections.boxes.cls scores = detections.boxes.conf # クラスラベルのマッピング label_mapping = { 'baskulin': 'バスクリン', 'potato_starch': '片栗粉', 'shampoo': 'シャンプー' } # 検出結果のテキスト表示 for cls, score in zip(classes, scores): class_label = model.names[int(cls)] if class_label in label_mapping: label = label_mapping[class_label] else: label = class_label print(f'検出: {label}, 信頼度: {score:.2f}')
次に
検出した物体のそれぞれの個数をカウントして表示
from ultralytics import YOLO from collections import defaultdict # YOLOv8モデルのロード model = YOLO('yolov8s.pt') # ここで適切なモデルを選択 # 画像のロード image_path = 'path_to_your_image.jpg' image = cv2.imread(image_path) # 画像の検出 results = model(image) # 検出結果の取得 detections = results[0] # 最初の結果を取得 classes = detections.boxes.cls # クラスラベルのマッピング label_mapping = { 'baskulin': 'バスクリン', 'potato_starch': '片栗粉', 'shampoo': 'シャンプー' } # 検出物体のカウント object_counts = defaultdict(int) for cls in classes: class_label = model.names[int(cls)] if class_label in label_mapping: label = label_mapping[class_label] else: label = class_label object_counts[label] += 1 # 検出結果の表示 for label, count in object_counts.items(): print(f'{label}: {count}個')
これでほぼ目的のものに近くなった
from collections import defaultdict
これは
Pythonの標準ライブラリであるcollectionsモジュールから
defaultdictクラスをインポートしています
defaultdictは、
キーが存在しない場合にデフォルト値を
自動的に提供する辞書を作成するために使用
この場合、物体のカウントを行うために使用している
ただ、在庫管理のものはどんどん追加していくため
別のファイルにして読み込むようにする
vim label_mapping.json
でJSONファイルを作成
{ "baskulin": "バスクリン", "potato_starch": "片栗粉", "shampoo": "シャンプー" }
次にJSON ファイルの読み込み
import json from ultralytics import YOLO from collections import defaultdict # JSONファイルからクラスラベルのマッピングを読み込み with open('label_mapping.json', 'r', encoding='utf-8') as f: label_mapping = json.load(f) # YOLOv8モデルのロード model = YOLO('yolov8s.pt') # ここで適切なモデルを選択 # 画像のロード image_path = 'path_to_your_image.jpg' image = cv2.imread(image_path) # 画像の検出 results = model(image) # 検出結果の取得 detections = results[0] # 最初の結果を取得 classes = detections.boxes.cls # 検出物体のカウント object_counts = defaultdict(int) for cls in classes: class_label = model.names[int(cls)] if class_label in label_mapping: label = label_mapping[class_label] else: label = class_label object_counts[label] += 1 # 検出結果の表示 for label, count in object_counts.items(): print(f'{label}: {count}個')
これを書き換える
コマンドラインで動作するようにする
コマンドラインから画像ファイルを指定して使用するようには
Pythonのargparseモジュールを使用
これにより
コマンドラインから画像ファイルのパスを指定できるようになる
また使用するモデルは
inventory_model/best.pt
とする
vim count_inventory_terminal.py
で中身を
import argparse import json import cv2 from ultralytics import YOLO from collections import defaultdict # コマンドライン引数の解析 parser = argparse.ArgumentParser(description="YOLOv8 Object Detection") parser.add_argument('image_path', type=str, help='Path to the input image file') args = parser.parse_args() # ラベルマッピングファイルのパス label_mapping_path = 'label_mapping.json' # JSONファイルからクラスラベルのマッピングを読み込み with open(label_mapping_path, 'r', encoding='utf-8') as f: label_mapping = json.load(f) # YOLOv8モデルのロード model = YOLO('inventory_model/best.pt') # ここで適切なモデルを選択 # 画像のロード image = cv2.imread(args.image_path) # 画像の検出 results = model(image) # 検出結果の取得 detections = results[0] # 最初の結果を取得 classes = detections.boxes.cls # 検出物体のカウント object_counts = defaultdict(int) for cls in classes: class_label = model.names[int(cls)] if class_label in label_mapping: label = label_mapping[class_label] else: label = class_label object_counts[label] += 1 # 検出結果の表示 for label, count in object_counts.items(): print(f'{label}: {count}個')
これで実行すると
python count_inventory_terminal.py data_bak/Baskulin1.jpg 0: 640x512 1 baskulin, 114.8ms Speed: 9.4ms preprocess, 114.8ms inference, 7.5ms postprocess per image at shape (1, 3, 640, 512) バスクリン: 1個
となって検出結果の日本語表示ができる
とりあえず対象物の日本語化とカウントができたので
次はLINEで送信機能を作成する