1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ローカルLLM(Ollama + llava)で画像の人物検出アプリを作った

1
Last updated at Posted at 2026-05-18

hoge_kawamuro さんの記事 を参考に、Claude Code と Obsidian を使って執筆しました。また、記事内の画像は Stable Diffusion(AUTOMATIC1111)を使って自動生成・挿入しています。

はじめに

「ローカルLLMって実際どこまで使えるの?」という素朴な疑問から始まりました。

最近はChatGPTやClaudeのようなクラウドAPIが主流ですが、完全ローカルで・無料で・アカウント登録なしで動く画像認識がどれくらい実用的か試してみたくなりました。今回はOllamaとllavaを組み合わせて、写真に人物が写っているかどうかを判定するCLIツールを作りました。

結果として、プロンプトをチューニングしたら30枚中28〜29枚を正しく判定できるところまで持っていけました。

ローカルLLM画像認識パイプライン全体像

構成

  • Ollama:ローカルでLLMを動かすためのフレームワーク
  • llava / llama3.2-vision:マルチモーダル(画像+テキスト)対応のモデル
  • Python:CLIのラッパースクリプト
  • 動作環境:Apple M4 Pro(48GB)。GPU推論なので快適に動きます

外部APIへの送信は一切なし。モデルのダウンロード後はオフラインでも動きます。

実装手順

1. Ollamaのインストール

brew install ollama

2. モデルのダウンロード

# 高精度版(推奨)
ollama pull llama3.2-vision:11b   # 約8GB

# 軽量・高速版
ollama pull llava                  # 約4.7GB
ollama pull moondream              # 約1.7GB

3. Ollamaをバックグラウンド起動

ollama serve &
# またはMac起動時に自動起動
brew services start ollama

4. Pythonスクリプト

依存パッケージは requests のみです。

import requests, base64, sys
from pathlib import Path

OLLAMA_URL = "http://localhost:11434/api/generate"

def judge_image(image_path: str, model: str = "llama3.2-vision") -> dict:
    with open(image_path, "rb") as f:
        b64 = base64.b64encode(f.read()).decode()

    prompt = (
        "Look at this image carefully. "
        "Is there any person (human) visible in this image? "
        "This includes faces, bodies, or any part of a human body (hands, arms, etc.). "
        "If you are not certain, answer NO. "
        "Answer with YES or NO on the first line, then one sentence explanation."
    )

    response = requests.post(OLLAMA_URL, json={
        "model": model,
        "prompt": prompt,
        "images": [b64],
        "stream": False,
        "options": {"temperature": 0}
    }, timeout=120)

    text = response.json()["response"].strip()
    first_line = text.split("\n")[0].upper()
    has_person = first_line.startswith("YES")

    return {"has_person": has_person, "response": text, "file": image_path}

使い方:

# 単一ファイル
python3 main.py photo.jpg

# フォルダ内を一括判定
python3 main.py ./photos/

# モデル切り替え
python3 main.py photo.jpg --model llava

# JSON出力(スクリプト連携用)
python3 main.py photo.jpg --json | jq 'select(.has_person)'

出力例:

判定中: photo.jpg ...
[YES] 人物あり  photo.jpg
     → YES. There is one person standing facing forward in this image.

--- 集計: 5枚中 2枚に人物あり ---

YES/NO判定フロー図

ハマった点・注意点

日本語プロンプトだとYES/NOの位置がずれる

最初は日本語でプロンプトを書いていたのですが、モデルによって回答フォーマットがバラバラになり、YES/NOの抽出がうまくいきませんでした。プロンプトは英語で書くのが安定します。

temperature: 0 を必ず設定する

デフォルトだと同じ画像でも毎回判定が変わることがあります。temperature: 0 を設定することで確定的な出力になり、信頼性が上がりました。

プロンプトで「全身が写っていなくてもYES」と明示する

llama3.2-visionは厳密すぎて、顔のアップや手だけ写っている場合を「人物なし」と判定していました。「hands, arms, etc.」を含むと明示したら精度が大幅に改善しました。

テスト用画像はUnsplashから用意する

Lorem Picsumでランダム画像を取得したら、ほとんどが風景写真で人物が写っていませんでした。人物検出のテストにはUnsplashで人物ありなし混在の画像を用意するのがおすすめです。

モデル比較

モデル サイズ 精度 速度 特徴
llama3.2-vision:11b 約8GB ★★★ 遅め(1〜2分/枚) 説明が正確。保守的な判定
llava 約4.7GB ★★ 中程度 標準的。誤検知やや多め
moondream 約1.7GB 速い 軽量だが画像でクラッシュすることも

M4 Pro(48GB)では100% GPU推論で動作します。llama3.2-vision:11b でも問題なく動きました。

結果

精度評価ダッシュボード

Unsplashから集めた人物あり15枚・なし15枚の計30枚で評価:

  • 人物あり14枚:14/14 正解(100%)
  • 人物なし15枚:12/15 正解(3枚の「誤検知」はいずれも手が写り込んでいた)

実質**28〜29/30(97%前後)**の精度でした。誤検知の3枚も「猫を持つ手」「パンケーキにシロップを注ぐ手」など、モデルが正しく人体部位を認識した結果であり、画像選びの問題に近いです。

まとめ

  • ローカルLLMでの画像認識は完全無料・登録なし・オフラインで動く
  • プロンプトのチューニングで精度は大きく変わる(日本語より英語、temperature=0、部位の明示)
  • llama3.2-vision:11b が精度・安定性ともにおすすめ
  • Apple Siliconとの相性が良く、M4 Pro環境なら実用的な速度で動作

「クラウドAPIに画像を送りたくない」「コストをかけずに試したい」という用途にぴったりです。コードは GitHub に置いています。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?