前回の第2回では、認識結果を枠とラベルで画像に描き、間違いを目で確認できるようにしました。今回は、検品や在庫確認で最も使われる機能、「何が何個あるか」を数えて集計する処理を作ります。
写真1枚ではなく、フォルダに入った複数の写真をまとめて処理し、結果をExcelで開けるCSVに出力します。
この回で作るもの
- 検出結果を、種類ごとの個数に数える関数
- 個数をCSV(Excelで開ける表形式のファイル)に書き出す処理
- フォルダ内の画像をまとめて処理するコマンド(1枚が壊れていても止まらない)
仕組み:検出した件数を、種類ごとに数える
画像認識のAIが出すのは「ここに、これがある」という個別の結果です。「全部でいくつか」は、その結果をプログラムで数えることで得られます。
- 画像を認識して、検出結果の一覧を得る
- 種類(label)ごとに件数を数える
- 画像ごと・種類ごとの個数を、CSVに1行ずつ書く
実装
種類ごとに数える app/counter.py
# app/counter.py(抜粋)
def count_by_label(detections: list[Detection]) -> Counter[str]:
"""種類(label)ごとの件数。例: Counter({"orange": 3, "banana": 1})"""
return Counter(d.label for d in detections)
Counter は、Pythonの標準で使える「数え上げ」の道具です。
CSVに書き出す
# app/counter.py(抜粋)
def write_counts_csv(rows: list[tuple[str, Counter[str]]], out_path: str | Path) -> Path:
out = Path(out_path)
out.parent.mkdir(parents=True, exist_ok=True)
with out.open("w", encoding="utf-8-sig", newline="") as f:
writer = csv.writer(f)
writer.writerow(["image", "label", "count"])
for image_name, counts in rows:
if not counts:
writer.writerow([image_name, "", 0]) # 何も見つからなかった画像も1行残す
for label, count in sorted(counts.items()):
writer.writerow([image_name, label, count])
return out
工夫した点は2つです。
utf-8-sig(BOM付きUTF-8)で保存:ExcelでCSVを開くと、BOMが無いUTF-8は日本語が文字化けすることがあります。BOMを付けると、そのまま開けます- 何も見つからなかった画像も1行残す:「見つからなかった」と「処理していない」を区別するためです。行が無いと、処理漏れと見分けがつきません
フォルダをまとめて処理する app/batch.py
# app/batch.py(抜粋)
def process_folder(folder: str | Path, detector: Detector) -> tuple[list[tuple[str, Counter[str]]], list[str]]:
"""全画像を処理する。1枚が壊れていても止めず、失敗した画像名を別に返す。"""
rows: list[tuple[str, Counter[str]]] = []
failed: list[str] = []
for image in find_images(folder):
try:
rows.append((image.name, count_by_label(detector.detect(image))))
except Exception: # 壊れた画像などで全体を止めない。原因はログに残す
logger.exception("処理に失敗しました: %s", image)
failed.append(image.name)
return rows, failed
100枚の写真のうち1枚が壊れていても、残りの99枚の結果は出したいものです。そこで、失敗した画像は名前を記録して次に進み、最後に「失敗した画像」として報告します。
動かして確かめる
練習用の画像を作る
フォルダ処理を試すため、サンプル画像を左右に切り分けた2枚を作ります。
python tools/make_samples.py # fruits_left.jpg / fruits_right.jpg を作る
python -m app.batch samples --csv out/counts.csv
3 枚を処理し、out/counts.csv に保存しました
- fruits.jpg: {'orange': 4}
- fruits_left.jpg: {'orange': 2}
- fruits_right.jpg: {'orange': 3}
CSVの中身は次のとおりです。
image,label,count
fruits.jpg,orange,4
fruits_left.jpg,orange,2
fruits_right.jpg,orange,3
数えるときの落とし穴が見える
元の写真では4個でしたが、左半分と右半分に分けると2個と3個で、合計は5個になります。写真の切り方を変えただけで、個数が変わりました。
- 枠の境目にまたがる物体が、2回数えられたり、逆に見逃されたりする
- 物体の一部しか写っていないと、判定が変わる
これは、実際の現場でも起きる問題です。たとえば、棚を2枚の写真に分けて撮ると、境目の商品が二重に数えられることがあります。撮影のルール(撮る範囲・重なり)まで含めて設計することが大切です。
テスト
pytest -q # 15件成功
ruff check . # 問題なし
テストでは、偽の検出器を使い、種類ごとの集計、CSVのBOMと0件の行、画像の絞り込み、失敗時も処理が続くことを確認しています。
つまずきやすい点
- CSVが文字化けする:BOM付きUTF-8で保存し、Excelで開けるようにします
- 見つからなかった画像が消える:0件の行を残さないと、処理漏れと区別できません
- 同じ物体を二重に数える:撮影の範囲・重なりのルールを決めます
- 数えたい種類が学習済みモデルに無い:レモンなどは正しく数えられません。追加学習は第7回で扱います
発注者向けメモ:「数える」業務は許容範囲を決める
個数を数える機能は、便利な反面、数え間違いをどこまで許容するかが仕様の中心になります。人が数える場合にも、ミスはゼロではありません。「AIの誤差が人と同程度か」「差が出たときにどう扱うか」を決めておきます。
発注者がやること チェックリスト
- ☐ 数えたい対象の種類と、写真の撮り方(範囲・角度・明るさ・重なり)を決めた
- ☐ 許容できる誤差(例:±1個まで)を、業務の言葉で決めた
- ☐ 人が数えた結果と、AIの結果を並べて比べる期間を設けることにした
- ☐ 集計結果の受け渡し先(Excel・既存システム)と形式を決めた
- ☐ 処理に失敗した写真をどう扱うか(再撮影・手作業)を決めた
開発会社への質問例
- 「数え間違いの許容範囲は、どのように決め、どのデータで確認しますか」
- 「撮影のルール(範囲・重なり・照明)は、どこまで開発側で設計してもらえますか」
- 「処理に失敗した画像や、何も見つからなかった画像は、どのように記録・通知されますか」
- 「集計結果は、当社のExcelや既存システムにどの形式で渡せますか」
まとめと次回予告
第3回では、次のことを行いました。
- 検出結果を種類ごとに数え、CSV(BOM付き)に書き出せるようにした
- フォルダ内の画像をまとめて処理し、1枚が壊れても止まらないようにした
- 写真の切り方で個数が変わる例から、撮影ルールの大切さを確認した
次回の第4回では、この認識処理をFastAPIでAPI(ほかのシステムから呼び出せる窓口)にします。
この連載の記事一覧
この記事は連載「YOLOで作る画像認識ツール」の1回です。連載のほかの回は次のとおりです(連載の一覧ページ)。
- 【YOLOで作る画像認識ツール 第0回】全体像と環境づくり:YOLOで最初の1枚を認識する
- 【YOLOで作る画像認識ツール 第1回】信頼度のしきい値とJSON出力:認識結果を「使える形」にする
- 【YOLOで作る画像認識ツール 第2回】認識結果を画像に描いて確認する:枠とラベルで「間違い」を見つけやすくする
- 【YOLOで作る画像認識ツール 第3回】種類ごとに何個あるか数えて、CSVに集計する(この記事)
- 【YOLOで作る画像認識ツール 第4回】FastAPIで画像認識を「API」にして、ほかのシステムから使えるようにする
- 【YOLOで作る画像認識ツール 第5回】ブラウザから写真をアップロードして、認識結果をその場で見る
- 【YOLOで作る画像認識ツール 第6回】精度を数字で測る:正解データと、適合率・再現率
- 【YOLOで作る画像認識ツール 第7回】学習済みモデルにない対象を覚えさせる:追加学習の手順と、結果の正しい読み方
- 【YOLOで作る画像認識ツール 第8回】自信の低い結果だけ人が確認する:AIと人の役割分担を設計する
- 【YOLOで作る画像認識ツール 第9回】速く・軽くする:ONNXに変換してCPUで動かし、変換前後を比べる
- 【YOLOで作る画像認識ツール 第10回】Dockerで動かす:設定・ログ・ヘルスチェックを運用に近い形にする
- 【YOLOで作る画像認識ツール 第11回(最終回)】運用の注意点とライセンス(AGPL-3.0):精度の低下に気づく仕組みと、連載のまとめ

