MENU

問い合わせ


    【YOLOで作る画像認識ツール 第3回】種類ごとに何個あるか数えて、CSVに集計する

    前回の第2回では、認識結果を枠とラベルで画像に描き、間違いを目で確認できるようにしました。今回は、検品や在庫確認で最も使われる機能、「何が何個あるか」を数えて集計する処理を作ります。

    写真1枚ではなく、フォルダに入った複数の写真をまとめて処理し、結果をExcelで開けるCSVに出力します。

    目次

    この回で作るもの

    • 検出結果を、種類ごとの個数に数える関数
    • 個数をCSV(Excelで開ける表形式のファイル)に書き出す処理
    • フォルダ内の画像をまとめて処理するコマンド(1枚が壊れていても止まらない)

    仕組み:検出した件数を、種類ごとに数える

    画像認識のAIが出すのは「ここに、これがある」という個別の結果です。「全部でいくつか」は、その結果をプログラムで数えることで得られます。

    1. 画像を認識して、検出結果の一覧を得る
    2. 種類(label)ごとに件数を数える
    3. 画像ごと・種類ごとの個数を、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回です。連載のほかの回は次のとおりです(連載の一覧ページ)。

    システム制作・運用・保守のお問い合わせはこちら


      よかったらシェアしてね!
      • URLをコピーしました!
      • URLをコピーしました!

      この記事を書いた人

      株式会社THIRD HERO代表取締役 朝野貴朗
      Webシステム開発を中心に、toC向けサービスサイトの運営、ツール開発などを行ってまいりました。

      目次