MENU

問い合わせ


    【YOLOで作る画像認識ツール 第0回】全体像と環境づくり:YOLOで最初の1枚を認識する

    「写真に何が写っているかをAIに判定させたい」という相談は、この数年で一気に増えました。ところが、画像認識のシステムは何ができて、何が難しく、どこに費用がかかるのかが見えにくく、見積もりの根拠も分かりにくい分野です。

    この連載では、画像認識(写真から「何が・どこに・いくつ」写っているかを見つける技術。物体検出と呼びます)の最小構成を、PythonとYOLO(ヨーロー。物体検出でよく使われるAIモデル)で実際に作ります。題材は、果物の写真から種類と個数を数える検品ツールです。

    第0回では、全体像を説明したうえで、環境を作り、サンプルの写真1枚を認識するところまでを動かします。

    目次

    この連載で作るもの:果物の検品・カウントツール

    題材に果物を選んだ理由は3つあります。

    • テストしやすい:果物の写真は誰でも手元で用意でき、「何が何個写っているか」の正解を人がすぐに確認できます
    • 学習済みモデルがそのまま使える範囲がある:公開されている学習済みモデルは、りんご・バナナ・オレンジを最初から見分けられます
    • 「学習済みモデルで足りない部分」が見える:レモンやキウイなど、学習済みモデルが知らない対象は、うまく識別できません。この失敗を見ることで、精度の測り方や追加学習が必要になる理由が分かります

    連載は全12回の予定です(各回のタイトルは変更になることがあります)。

    回内容
    0全体像と環境づくり(この回)
    1信頼度のしきい値とJSON出力
    2認識結果を画像に描いて確認する
    3種類ごとの個数を数えてCSVに集計する
    4FastAPIで画像認識APIにする
    5ブラウザから画像をアップロードして結果を見る
    6精度を測る(正解ラベルと適合率・再現率)
    7学習済みモデルにない対象を覚えさせる(追加学習)
    8自信の低い結果だけ人が確認するフロー
    9ONNXに変換してCPUで速く動かす
    10Dockerで動かす
    11運用の注意点とライセンス(AGPL-3.0)・限界のまとめ

    外部サービスのAPIキーは不要です。AIモデルは自分のパソコンの中で動きます。

    使う技術と、その選び方

    役割採用したもの補足
    言語Python 3.11以上画像認識の情報が最も多い言語
    物体検出Ultralytics(YOLO26)推論・評価・追加学習・ONNX変換までが1つで済む
    深層学習の基盤PyTorch(CPU版)GPU(画像処理用の高性能な部品)がなくても動く
    テスト・検査pytest / ruff自動テストとコードの書き方の検査

    バージョンは、本連載を書いた2026年6月時点で公開されている版に固定しました(Ultralyticsは8.4系、PyTorchは2系)。詳しい版は、サンプルコードの requirements.txt にあります。

    技術選定は「一番実現性が高いもの」を基準にしました。学習済みモデルが配布されていて、APIキーも不要、パソコンのCPUだけで動く。この3点がそろっているため、まず試作(PoC)から始めたい場合に最も現実的です。クラウドの画像認識サービスという選択肢もあり、第11回で比較します。

    発注者が知っておきたい注意:ライセンス

    UltralyticsのYOLOは、オープンソースのライセンス「AGPL-3.0」で公開されています。公式のREADMEでは、商用の製品・サービスや社内ツールへの組み込みには「Ultralytics Enterprise License」を案内しています。

    📰 出典:Ultralytics 公式リポジトリ README(ライセンスの項)

    自社のシステムにどちらのライセンスが必要かは、使い方によって変わります。この連載では一般的な注意点の紹介にとどめ、個別の判断は専門家や提供元に確認してください。この論点は、第11回でもう一度まとめます。

    環境を作る

    サンプルコードは、リポジトリの blogs/it_hacchu/series/yolo-kensa/code/ にあります。まず、Pythonの仮想環境(プロジェクトごとに部品を分けて入れる仕組み)を作り、必要な部品を入れます。

    cd blogs/it_hacchu/series/yolo-kensa/code
    python3 -m venv .venv
    . .venv/bin/activate
    pip install -r requirements-dev.txt --extra-index-url https://download.pytorch.org/whl/cpu

    requirements.txt には、動作を確認した版を固定して書いています。

    # requirements.txt
    ultralytics==8.4.58
    torch==2.12.0
    torchvision==0.27.0
    opencv-python==4.13.0.92
    numpy==2.4.6
    pillow==12.2.0

    ここで一つ、つまずきやすい点があります。PyTorchの本体(torch)だけ版を上げると、姉妹部品のtorchvisionと版が合わなくなり、operator torchvision::nms does not exist というエラーで止まります。torchとtorchvisionは、必ず対になる版で固定してください。

    学習済みモデルとサンプル画像を取得する

    次のスクリプトで、AIモデル(学習済みの重みファイル)とサンプル画像をダウンロードします。初回だけ実行します。

    # tools/download_assets.py(抜粋)
    ASSETS = {
        ROOT / "models" / "yolo26n.pt": "https://github.com/ultralytics/assets/releases/download/v8.4.0/yolo26n.pt",
        ROOT / "samples" / "fruits.jpg": "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/fruits.jpg",
    }
    python tools/download_assets.py
    • yolo26n.pt:80種類の物体で学習済みの、最も小さいモデル(約5MB)。「n」はnano(超小型)の頭文字です
    • fruits.jpg:画像処理ライブラリOpenCVのサンプル画像(Apache-2.0ライセンス)。切ったオレンジ・レモン・ライム・キウイ・バナナ・紫キャベツが写っています

    モデルと画像は、リポジトリには含めない設定にしています(.gitignore)。

    画像1枚を認識するコードを書く

    認識の中心は、app/detector.py の Detector クラスです。「見つかった物体1つ分」を表す Detection と、画像から Detection の一覧を返す Detector の2つで構成します。

    # app/detector.py(抜粋)
    @dataclass(frozen=True)
    class Detection:
        """見つかった物体1つ分。"""
    
        label: str  # 何が写っているか(例: "orange")
        confidence: float  # 信頼度 0〜1
        box: tuple[int, int, int, int]  # 画像上の四角(左, 上, 右, 下)をピクセルで
    
    
    class Detector:
        def __init__(self, model_path: Path = MODEL_PATH, confidence: float = DEFAULT_CONFIDENCE) -> None:
            if not Path(model_path).exists():
                raise FileNotFoundError(f"モデルが見つかりません: {model_path}(python tools/download_assets.py を実行してください)")
            self._model = YOLO(str(model_path))
            self.confidence = confidence
    
        def detect(self, image_path: str | Path) -> list[Detection]:
            """画像ファイルを読み、しきい値以上の検出結果を返す。"""
            if not Path(image_path).exists():
                raise FileNotFoundError(f"画像が見つかりません: {image_path}")
            result = self._model.predict(str(image_path), conf=self.confidence, verbose=False)[0]
            detections: list[Detection] = []
            for box in result.boxes:
                left, top, right, bottom = (round(v) for v in box.xyxy[0].tolist())
                detections.append(
                    Detection(
                        label=self._model.names[int(box.cls)],
                        confidence=float(box.conf),
                        box=(left, top, right, bottom),
                    )
                )
            return detections

    ポイントは次の3つです。

    • 信頼度(confidence):モデルが「これだ」と思う自信の度合いで、0〜1の数字です。しきい値(既定は0.25)より低いものは結果に出しません。この数字の意味と調整は、次の第1回で詳しく扱います
    • 位置(box):物体を囲む四角の、左・上・右・下の座標です。単位はピクセル(画像の点の数)です
    • ファイルが無いときは分かるエラーにする:モデルや画像が見つからないときに、次に何をすればよいかが分かる文言を出します

    設定は app/config.py にまとめ、環境変数で上書きできるようにしています。

    # app/config.py(抜粋)
    MODEL_PATH = Path(os.environ.get("YOLO_MODEL_PATH", ROOT / "models" / "yolo26n.pt"))
    DEFAULT_CONFIDENCE = float(os.environ.get("YOLO_CONFIDENCE", "0.25"))

    コマンドラインから動かすための入口が app/main.py です。

    # app/main.py(抜粋)
    def main(argv: list[str] | None = None) -> int:
        parser = argparse.ArgumentParser(description="画像1枚から物体を検出する")
        parser.add_argument("image", help="認識する画像ファイル")
        parser.add_argument("--conf", type=float, default=DEFAULT_CONFIDENCE, help="信頼度のしきい値(0〜1)")
        args = parser.parse_args(argv)
    
        detections = Detector(confidence=args.conf).detect(args.image)
        print(f"{len(detections)} 件見つかりました(しきい値 {args.conf})")
        for d in detections:
            print(f"- {d.label} 信頼度 {d.confidence:.2f} 位置 {d.box}")
        return 0

    動かして確かめる

    サンプル画像を認識してみます。

    python -m app.main samples/fruits.jpg

    執筆時の開発環境での実行結果は次のとおりです。

    4 件見つかりました(しきい値 0.25)
    - orange 信頼度 0.87 位置 (317, 247, 512, 477)
    - orange 信頼度 0.72 位置 (69, 44, 348, 470)
    - orange 信頼度 0.47 位置 (0, 277, 130, 477)
    - orange 信頼度 0.40 位置 (321, 121, 512, 305)

    学習済みモデルは、画像から4つの orange(オレンジ)を見つけました。処理時間は、開発環境のCPUで1枚あたり0.1秒弱でした(環境により異なります)。

    結果をよく見ると「うまくいっていない」

    サンプル画像には、切ったオレンジ、レモン、ライム、キウイ、バナナ、紫キャベツが写っています。ところが、AIの答えは「すべてorange」です。

    • レモンやライムなど、学習済みモデルが知らない果物も、似た形の「orange」として答えてしまうことがあります
    • バナナは、この写真では見つかりませんでした(見つからなかった=見逃し)

    これは、AIが壊れているのではなく、学習済みモデルが「知っている80種類」の範囲でしか答えられないためです。この限界をどう扱うかが、画像認識のシステムを発注するときの一番大きな論点になります。第6回(精度の測り方)と第7回(追加学習)で、実際に確かめながら向き合います。

    テストも用意しておく

    コードには、自動テストも付けています。モデルを読み込まない偽物を使ったテストで、ロジックを速く確かめます。

    # tests/test_detector.py(抜粋)
    def test_detect_converts_result(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
        ...
        monkeypatch.setattr(detector_module, "YOLO", _FakeYOLO)
    
        result = Detector(model_path=model, confidence=0.4).detect(image)
    
        assert result == [Detection(label="orange", confidence=pytest.approx(0.87), box=(10, 21, 110, 220))]

    実際のモデルを使うテスト(@pytest.mark.integration)は、モデルとサンプル画像を取得済みの場合だけ走ります。

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

    つまずきやすい点

    • torchとtorchvisionの版がずれる:前述のとおり、対で固定します
    • 初回に時間がかかる:PyTorchの導入とモデルの取得に数分かかります。社内の通信制限でGitHubに接続できないと、モデルを取得できません
    • 写真に人が写っていないか:実運用では、顔や車のナンバーなど個人が特定できる情報を含む写真の扱いに注意が必要です。この連載のサンプルは果物だけを使います

    発注者向けメモ:画像認識の相談で最初に決めること

    この回で見えた「学習済みモデルはそのまま動くが、知らないものは間違える」という点は、発注の場面でそのまま論点になります。

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

    • ☐ 何を判定したいか(種類・個数・良否など)を、写真つきで具体的に書き出した
    • ☐ 判定したい対象の写真を、実際の現場で撮影して数十枚以上集めた
    • ☐ 見逃し(写っているのに見つからない)と誤検出(違うものを見つける)のどちらがより困るかを決めた
    • ☐ AIが間違えたとき、人が確認・修正する運用を前提にすることを社内で合意した
    • ☐ 写真に個人情報(顔・車のナンバー等)が写らないか確認した

    開発会社への質問例

    • 「私たちの対象は、学習済みモデルのままで判定できそうですか。それとも追加の学習が必要ですか」
    • 「精度の目標(何%)は、どのように決め、どのテスト画像で確認しますか」
    • 「学習や評価に使う写真は、こちらで何枚くらい用意する必要がありますか」
    • 「使うAIモデルのライセンスは何ですか。商用で使う場合に追加の費用や条件はありますか」
    • 「稼働後に、対象が変わったり精度が落ちたりしたときの再学習は、保守に含まれますか」

    まとめと次回予告

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

    • 果物の検品・カウントツールを題材に、画像認識の連載の全体像を整理した
    • Python環境を作り、学習済みモデルとサンプル画像を取得した
    • 画像1枚を認識して、種類・信頼度・位置を表示できた
    • 学習済みモデルが知らない対象(レモンなど)を間違える、という限界を確認した

    次回の第1回では、信頼度のしきい値を変えると結果がどう変わるかを調べ、結果をJSONの形で出力して「使える形」にします。

    この連載の記事一覧

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

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


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

      この記事を書いた人

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

      目次