MENU

問い合わせ


    【YOLOで作る画像認識ツール 第2回】認識結果を画像に描いて確認する:枠とラベルで「間違い」を見つけやすくする

    前回の第1回では、信頼度のしきい値を変えると結果がどう変わるかを調べ、結果をJSONで出力できるようにしました。ただ、「位置 (317, 247, 512, 477)」のような数字の並びでは、認識が合っているのかを判断しにくいものです。

    今回は、認識した結果を元の画像に枠とラベルで描き込み、目で見て確認できるようにします。画像認識のシステムでは、この「見て確認できる画面」が、現場の合意を得るうえでとても重要になります。

    目次

    この回で作るもの

    • 検出した物体の枠と、種類・信頼度のラベルを画像に描く関数 draw_detections
    • コマンドに --out を付けると、確認用の画像を保存する機能

    仕組み:元の画像には触れず、描き込んだ「コピー」を保存する

    処理の流れは次のとおりです。

    1. 元の画像を読み込む(Pillow。画像を扱うPythonの定番ライブラリ)
    2. 検出結果ごとに、枠(四角)とラベル(種類と信頼度の文字)を描く
    3. 別のファイルとして保存する(元の画像は書き換えない)

    元の画像を書き換えない点は、業務システムでは大切です。証拠となる写真を、確認用の加工で汚さないためです。

    実装

    種類ごとに色を分ける

    種類が違えば枠の色も変えると、一目で区別できます。

    # app/draw.py(抜粋)
    PALETTE = [(230, 57, 70), (29, 120, 220), (42, 157, 143), (244, 162, 97), (131, 56, 236), (6, 214, 160)]
    
    
    def color_for(label: str) -> tuple[int, int, int]:
        """同じ種類には、実行のたびに同じ色を返す(Python の hash() は実行ごとに変わるので使わない)。"""
        return PALETTE[sum(label.encode("utf-8")) % len(PALETTE)]

    Pythonの標準の hash() は、実行のたびに値が変わる仕組みです。色の決定に使うと、同じ「orange」が今日と明日で違う色になってしまうため、文字のバイト値の合計で決めています。

    枠とラベルを描く

    # app/draw.py(抜粋)
    def draw_detections(image_path: str | Path, detections: list[Detection], out_path: str | Path) -> Path:
        """枠・種類・信頼度を描いた画像を out_path に保存して、そのパスを返す。元の画像は書き換えない。"""
        image = Image.open(image_path).convert("RGB")
        draw = ImageDraw.Draw(image)
        font = ImageFont.load_default(size=max(12, image.width // 40))
        line = max(2, image.width // 200)
        for d in detections:
            color = color_for(d.label)
            draw.rectangle(d.box, outline=color, width=line)
            text = f"{d.label} {d.confidence:.2f}"
            left, top, right, bottom = draw.textbbox((d.box[0], d.box[1]), text, font=font)
            # ラベルは枠の上に置く。画像の上端からはみ出す場合は枠の内側に置く。
            shift = 0 if top - 4 >= 0 else (bottom - top) + 6
            draw.rectangle((left - 2, top - 4 + shift, right + 2, bottom + shift), fill=color)
            draw.text((left, top - 2 + shift), text, fill=(255, 255, 255), font=font)
        out = Path(out_path)
        out.parent.mkdir(parents=True, exist_ok=True)
        image.save(out)
        return out
    • 枠の太さと文字の大きさは、画像の幅に合わせて変えます(大きな写真でも文字が読めるように)
    • 枠が画像の上の端にあるとき、ラベルが画像の外にはみ出さないよう、枠の内側へ置きます
    • 出力先のフォルダが無ければ自動で作ります

    コマンドに --out を追加

    # app/main.py(変更部分)
    parser.add_argument("--out", help="枠とラベルを描いた画像の保存先(例: out/result.png)")
    ...
    if args.out:
        saved = draw_detections(args.image, detections, args.out)
        print(f"確認用の画像を保存しました: {saved}")

    動かして確かめる

    python -m app.main samples/fruits.jpg --out out/result.png

    出力された画像が次のとおりです(開発環境で生成。元の写真はOpenCVのサンプル画像で、Apache-2.0ライセンスです)。

    サンプル画像に、検出結果の枠とラベルを描いた画像

    数字だけのときには気づきにくかった問題が、画像にすると一目で分かります。

    • 切ったオレンジ(中央)に「orange 0.72」が付いています。これは合っています
    • 右下のレモンに「orange 0.87」が付いています。信頼度が最も高いのに、間違いです
    • 左下のキウイに「orange 0.47」、右上のライムに「orange 0.40」が付いています。これも間違いです

    この結果から分かるとおり、信頼度が高いことは、正しいことの保証にはなりません。学習済みモデルが知らない果物(レモン・キウイ・ライム)を、似たものとして自信を持って間違えています。この問題は、第6回で「精度を測る」、第7回で「追加学習」として扱います。

    テスト

    pytest -q      # 11件成功
    ruff check .   # 問題なし

    描画のテストでは、白い画像に枠を描き、枠の位置の色が期待どおりか、元のファイルが変わっていないか、画像の端でも落ちないかを確認しています。

    つまずきやすい点

    • 日本語のラベルは文字化けする:標準のフォントは英語向けです。日本語のラベルを出す場合は、日本語フォントのファイルを指定する必要があります(この連載では英語のラベルのままにしています)
    • 枠が画像の外に出る:座標が画像の外を指す場合に備え、実運用では描画前に範囲を切り詰めておくと安全です
    • 確認用の画像に個人情報が残る:顔や車のナンバーが写る写真を扱う場合、確認用の画像の保存先・保管期間も個人情報の管理対象になります

    発注者向けメモ:「見える化」は合意形成の道具

    画像認識の検討では、数字(精度)だけでなく、実際の認識結果を画像で見て判断する場が欠かせません。今回のようにAIが自信を持って間違える例を、導入前に見ておくことで、現場の期待値を合わせられます。

    発注者がやること チェックリスト

    • ☐ 自社の実際の写真で、枠とラベルを描いた画像を見て、間違いの傾向を確認した
    • ☐ 「信頼度が高い=正しい」ではないことを、関係者に共有した
    • ☐ 確認用の画像を誰が・どこで見るか(画面の要否)を決めた
    • ☐ 確認用の画像の保存先と保管期間を決めた(個人情報が写る場合は特に)

    開発会社への質問例

    • 「認識結果を画面で確認できる仕組みは、見積もりに含まれていますか」
    • 「間違いやすい対象は、事前のテストでどのように洗い出しますか」
    • 「確認用に保存する画像は、どこに何日間保存されますか。削除の手順はありますか」

    まとめと次回予告

    第2回では、次のことを行いました。

    • 認識結果を、枠と種類・信頼度のラベルとして画像に描く関数を作った
    • 元の画像は書き換えず、確認用のコピーを保存するようにした
    • 画像で見ることで、「信頼度が最も高いレモンが間違い」という問題が一目で分かった

    次回の第3回では、写真に何個写っているかを種類ごとに数え、CSVに集計します。フォルダ内の複数の写真もまとめて処理します。

    この連載の記事一覧

    この記事は連載「YOLOで作る画像認識ツール」の1回です。連載のほかの回は次のとおりです(連載の一覧ページ)。

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


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

      この記事を書いた人

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

      目次