GEMINI LABEN
NANOLITE — Nano Banana 2 Liteが登場しました。Googleで最も速く、最もコスト効率の高いGemini Imageモデルで、軽量な画像生成を安く回したい用途に向いていますOMNIFLASH — Gemini Omni Flashがpublic previewになりました。ネイティブにマルチモーダルなモデルで、企業や開発者が独自の動的な動画ワークフローを構築できますAGENTS — Managed Agentsが拡張されました。background: trueでサーバー側の非同期実行とポーリング、リモートMCPサーバー連携、対話をまたぐ認証情報のリフレッシュに対応しますMEMORY — Memory BankのIngestEvents APIが一般提供になりました。イベントの取り込みとメモリ生成を分離し、コンテンツを継続的にストリームできますTHROUGHPUT — Provisioned Throughputで、同一モデル・同一リージョンに対して最大7件の保留オーダーを提出できるようになりましたDEPRECATE — 画像生成モデルは8月17日に、Gemini Enterprise Agent PlatformのGrok 4.1系は8月20日に停止される予定ですNANOLITE — Nano Banana 2 Liteが登場しました。Googleで最も速く、最もコスト効率の高いGemini Imageモデルで、軽量な画像生成を安く回したい用途に向いていますOMNIFLASH — Gemini Omni Flashがpublic previewになりました。ネイティブにマルチモーダルなモデルで、企業や開発者が独自の動的な動画ワークフローを構築できますAGENTS — Managed Agentsが拡張されました。background: trueでサーバー側の非同期実行とポーリング、リモートMCPサーバー連携、対話をまたぐ認証情報のリフレッシュに対応しますMEMORY — Memory BankのIngestEvents APIが一般提供になりました。イベントの取り込みとメモリ生成を分離し、コンテンツを継続的にストリームできますTHROUGHPUT — Provisioned Throughputで、同一モデル・同一リージョンに対して最大7件の保留オーダーを提出できるようになりましたDEPRECATE — 画像生成モデルは8月17日に、Gemini Enterprise Agent PlatformのGrok 4.1系は8月20日に停止される予定です
記事一覧/API / SDK
API / SDK/2026-04-28上級

Gemini 2.5 Pro の空間理解(バウンディングボックス・セグメンテーション)を本番アプリで使いこなす

Gemini 2.5 Pro の空間理解出力を本番のモバイル/Webアプリに組み込むための実装ガイド。座標正規化・マスクのデコード・ハルシネーション検出・YOLOへの自動フォールバックまで、動作するコードと共に解説します。

gemini-2-5-pro3image-understandingbounding-boxsegmentationcomputer-visionproduction105multimodal24ai-app

プレミアム記事

「写っている棚の商品の位置を教えて」「このレシートの合計金額が書かれている領域を抜き出して」——こうした「画像のどこに何があるか」を答えさせる仕事は、長らく専用のコンピュータビジョン(CV)モデルの出番でした。私自身も、モバイルアプリで物体検出が必要になったときは、まず YOLO や CoreML の検出器を最初に検討してきました。Gemini 2.5 Pro が空間理解(spatial understanding)を強化してから状況は変わりつつあるのですが、本番アプリに組み込もうとすると、想像していたより躓きどころが多いというのが正直な感想です。

Gemini 2.5 Pro のバウンディングボックスとセグメンテーションマスクを「アプリに組み込んで安定して動かす」ところまで持っていくための実装パターンを実例とともに整理しました。座標が 0〜1000 で返ってくるという独特の規約、マスクが base64 PNG で埋め込まれていること、そしてハルシネーション座標をどう排除するか——公式ドキュメントだけ読んでいると見落としやすい部分を中心に取り上げます。

なぜ Gemini の空間理解が「使いどころ」なのか — 専用CVモデルと比較する

最初に立ち位置を整理しておきます。Gemini 2.5 Pro の空間理解は、YOLO や Detectron2 といった専用検出器を「置き換えるもの」ではありません。私の現場感覚で言うと、得意なシーンとそうでないシーンが明確に分かれます。

Gemini が向いているのは、概念的な指示で物体を引き当てたい場面です。たとえば「このレシートの『合計金額』が書かれている領域を返して」「キッチンの写真から『ガスコンロの取手』だけを切り出して」のように、クラス名がカテゴリで定義しきれない、または事前学習されていない用途に強い。専用検出器は事前にラベルを与えていないと動きませんが、Gemini はゼロショットで意味を解釈してくれます。

一方、苦手なのはリアルタイム性とスループットです。1リクエスト数百ミリ秒〜数秒かかりますし、料金も画像1枚あたりトークンを消費します。1秒あたり30フレーム検出するような用途には向きません。「カメラを構えて1枚撮って解析する」「アップロードされた画像を非同期でラベリングする」といった頻度の低い処理が中心になります。

実装方針としては、私は次のように使い分けています。低レイテンシ・高頻度の検出は専用モデルに任せ、人間の意図に近い「探したい対象」が来たら Gemini を呼ぶ。両者を組み合わせるのが現実的だと感じています。後述するフォールバック設計はこの考え方を前提にしています。

もう一つ実務で大事な視点として、検出単価が「何を聞くか」で大きく揺れます。1280px の画像に対する単純な物体検出なら数銭〜数十銭の世界ですが、4Kサイズに対してマスクまで要求すると数十円に跳ね上がることがあります。日に数千回呼ぶアプリだと無視できない金額になりますので、私は画像ごとのコストとレイテンシを同じテレメトリテーブルに残し、プロンプトや画像サイズが変わったときに退化を即時検知できるようにしています。

バウンディングボックス出力の正しい要求方法

ここからが本題です。Gemini の空間出力には「ハマりやすい3つのポイント」があるので、コードを書く前に押さえておきましょう。

第一に、座標は 0〜1000 の正規化値 で返ってきます。0〜1 ではありません。画像の左上が (0, 0)、右下が (1000, 1000) です。第二に、出力順は [ymin, xmin, ymax, xmax] です——一般的な (x, y) 順ではなく、Y が先です。私はここで一度ハマって、画面に表示されるボックスが90度回転しているように見えてしばらく悩みました。第三に、Gemini はあくまで「最善の推測」を返してくるため、画像に存在しない物体を聞かれても自信ありげに座標を作ることがあります(後で対策します)。

イメージとしては、Gemini を「画像を一度見ただけの優秀なインターン」だと思って付き合うのが近いです。だいたい正しいところを指してくれますが、「ない物」を聞かれても遠慮なく『ありそうな場所』を返してきますし、写真の内容そのものよりも「写っていそうな状況」を語ることがあります。本記事のスキーマ・プロンプト・バリデータは、その聡明だが暗示にかかりやすい同僚を、本番投入できる仕組みに磨き上げるための装具のようなものだと考えてください。

プロンプトの書き方と JSON スキーマ

座標を確実に取り出したい場合は、プロンプトで形式を指定し、response_schema で JSON 構造を強制するのが鉄則です。形式を曖昧にすると、Gemini はマークダウンや散文で返してくることがあり、パーサが壊れます。

# requirements:
#   pip install google-genai pillow
# env:
#   export GEMINI_API_KEY="YOUR_GEMINI_API_KEY"
 
import json
import os
from io import BytesIO
from typing import List
 
from google import genai
from google.genai import types
from PIL import Image, ImageDraw, ImageFont
from pydantic import BaseModel, Field
 
class Detection(BaseModel):
    label: str = Field(description="検出した物体のラベル")
    box_2d: List[int] = Field(
        description="座標 [ymin, xmin, ymax, xmax](0〜1000で正規化)",
        min_length=4, max_length=4,
    )
    confidence: float = Field(description="0〜1の信頼度", ge=0, le=1)
 
class DetectionResult(BaseModel):
    detections: List[Detection]
 
def detect_objects(image_path: str, target: str) -> DetectionResult:
    client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
    image = Image.open(image_path)
 
    prompt = (
        f"画像から『{target}』に該当する物体をすべて検出してください。"
        "座標は [ymin, xmin, ymax, xmax] の順で 0〜1000 の整数で返してください。"
        "存在しない場合は detections を空配列で返してください。"
        "推測ではなく実際に視認できるものだけを含めてください。"
    )
 
    resp = client.models.generate_content(
        model="gemini-2.5-pro",
        contents=[prompt, image],
        config=types.GenerateContentConfig(
            response_mime_type="application/json",
            response_schema=DetectionResult,
            temperature=0.1,  # 安定化のため低めに
        ),
    )
    # 期待出力: DetectionResult をそのまま受け取れる
    return DetectionResult.model_validate_json(resp.text)
 
if __name__ == "__main__":
    result = detect_objects("./shelf.jpg", "ペットボトルの飲料")
    print(json.dumps(result.model_dump(), indent=2, ensure_ascii=False))

ここで意図的に行っている工夫をいくつか説明します。response_schema に Pydantic モデルを渡すことで、型のズレを Gemini 側で吸収させています。temperature=0.1 はゼロにしたいところですが、ゼロだと「自信が持てない物体は検出しない」傾向が極端に強まり、再現率が落ちます。経験上、0.1〜0.2 が「安定」と「網羅性」のバランスが取れる範囲です。プロンプトに「推測ではなく実際に視認できるものだけ」と明記しているのは、ハルシネーション抑制の最初の防波堤になります。

0〜1000 正規化座標を画像ピクセルに変換する

検出結果を画面に描画したり、後段のクロップ処理に渡したりするには、ピクセル座標に変換する必要があります。座標順序を間違えるとボックスが斜めにズレるので、関数として切り出して使い回すのがおすすめです。

def to_pixel_box(box_2d: List[int], img_w: int, img_h: int):
    """[ymin, xmin, ymax, xmax] (0-1000) -> (x1, y1, x2, y2) in pixels."""
    ymin, xmin, ymax, xmax = box_2d
    x1 = round(xmin / 1000 * img_w)
    y1 = round(ymin / 1000 * img_h)
    x2 = round(xmax / 1000 * img_w)
    y2 = round(ymax / 1000 * img_h)
    # 念のため画像範囲にクランプ
    x1, x2 = max(0, x1), min(img_w, x2)
    y1, y2 = max(0, y1), min(img_h, y2)
    return x1, y1, x2, y2
 
def render_detections(image_path: str, detections: List[Detection], out_path: str):
    img = Image.open(image_path).convert("RGB")
    draw = ImageDraw.Draw(img)
    w, h = img.size
    for d in detections:
        x1, y1, x2, y2 = to_pixel_box(d.box_2d, w, h)
        if (x2 - x1) < 4 or (y2 - y1) < 4:
            continue  # ノイズの極小ボックスは捨てる
        draw.rectangle([x1, y1, x2, y2], outline="red", width=3)
        draw.text((x1, max(0, y1 - 14)), f"{d.label} {d.confidence:.2f}", fill="red")
    img.save(out_path)

min(x_or_y, img_w_or_h) でクランプしているのは、Gemini がときどき 1000 をわずかに超えた値(1003 など)を返すことがあるためです。座標を信用しきらず、必ず画像範囲に収める処理を入れておくと、後段のクロップが IndexError で落ちるのを防げます。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
Gemini に画像内の物体位置を聞いたら座標がズレていた、と困っていた方が、信頼できる出力を得るためのプロンプトとパーサを今日から使えます
バウンディングボックスとセグメンテーションマスクを画面に描画し、ストレージへ保存する完全な本番コードを習得できます
ハルシネーション座標を検出して棄却する仕組みと、専用CVモデル(YOLO等)への自動フォールバック設計まで実装できます
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Gemini Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

API / SDK2026-04-26
gemini-2.5-pro-latest を本番投入する前に押さえる5つの設計判断
gemini-2.5-pro-latest を本番ワークロードで使うとき、性能だけでなく可用性・コスト・互換性まで含めた設計判断が必要です。私が複数のサービスで運用してきた経験から、押さえるべき5つの設計ポイントを実例ベースで整理しました。
API / SDK2026-04-11
Gemini API で構築するコンテンツモデレーション本番システム
Gemini API でカスタムコンテンツモデレーションシステムを本番構築する完全ガイド。テキスト・画像のマルチモーダル検査、非同期バッチ処理、Human-in-the-Loop、コスト最適化まで網羅的に解説します。
API / SDK2026-04-08
Gemini API × Cloud Storage 大容量ファイル処理パイプライン — 100MBアップロードとプライベートDB連携の本番実装ガイド
Gemini APIのCloud Storage統合と100MBファイル対応を活用し、大容量PDF・動画・音声を本番パイプラインで処理するアーキテクチャと実装パターンを詳解します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →