画像の理解

Gemini モデルは画像を処理できるため、従来はドメイン固有のモデルを必要としていた多くのフロンティア デベロッパーのユースケースを実現できます。Gemini のビジョン機能には、次のものがあります。

  • 画像にキャプションを付け、画像に関する質問に回答する
  • 最大 200 万トークンを含む PDF を音声文字変換して推論する
  • 画像内のオブジェクトを検出して、境界ボックスの座標を返す
  • 画像内のオブジェクトをセグメント化する

Gemini はマルチモーダルを念頭にしてゼロから構築されており、Google は可能性の限界を押し広げ続けています。このガイドでは、Gemini API を使用して画像入力に基づいてテキスト レスポンスを生成し、一般的な画像認識タスクを実行する方法について説明します。

始める前に

Gemini API を呼び出す前に、任意の SDK がインストールされ、Gemini API キーが構成され、使用可能であることを確認してください。

画像入力

画像を Gemini に入力するには、次の方法があります。

  • generateContent にリクエストを送信する前に、File API を使用して画像ファイルをアップロードします。この方法は、20 MB を超えるファイルや、複数のリクエストでファイルを再利用する場合に使用します。
  • リクエストで generateContentインライン画像データを渡す。この方法は、小さなファイル(合計リクエスト サイズが 20 MB 未満)または URL から直接取得される画像に使用します。

画像ファイルをアップロードする

Files API を使用して画像ファイルをアップロードできます。リクエストの合計サイズ(ファイル、テキスト プロンプト、システム インストラクションなど)が 20 MB を超える場合や、複数のプロンプトで同じ画像を使用する場合は、必ず Files API を使用してください。

次のコードは、画像ファイルをアップロードし、generateContent の呼び出しでそのファイルを使用します。

Python

from google import genai

client = genai.Client(api_key="GOOGLE_API_KEY")

myfile = client.files.upload(file="path/to/sample.jpg")

response = client.models.generate_content(
    model="gemini-2.0-flash",
    contents=[myfile, "Caption this image."])

print(response.text)

JavaScript

import {
  GoogleGenAI,
  createUserContent,
  createPartFromUri,
} from "@google/genai";

const ai = new GoogleGenAI({ apiKey: "GOOGLE_API_KEY" });

async function main() {
  const myfile = await ai.files.upload({
    file: "path/to/sample.jpg",
    config: { mimeType: "image/jpeg" },
  });

  const response = await ai.models.generateContent({
    model: "gemini-2.0-flash",
    contents: createUserContent([
      createPartFromUri(myfile.uri, myfile.mimeType),
      "Caption this image.",
    ]),
  });
  console.log(response.text);
}

await main();

Go

file, err := client.UploadFileFromPath(ctx, "path/to/sample.jpg", nil)
if err != nil {
    log.Fatal(err)
}
defer client.DeleteFile(ctx, file.Name)

model := client.GenerativeModel("gemini-2.0-flash")
resp, err := model.GenerateContent(ctx,
    genai.FileData{URI: file.URI},
    genai.Text("Caption this image."))
if err != nil {
    log.Fatal(err)
}

printResponse(resp)

REST

IMAGE_PATH="path/to/sample.jpg"
MIME_TYPE=$(file -b --mime-type "${IMAGE_PATH}")
NUM_BYTES=$(wc -c < "${IMAGE_PATH}")
DISPLAY_NAME=IMAGE

tmp_header_file=upload-header.tmp

# Initial resumable request defining metadata.
# The upload url is in the response headers dump them to a file.
curl "https://generativelanguage.googleapis.com/upload/v1beta/files?key=${GOOGLE_API_KEY}" \
  -D upload-header.tmp \
  -H "X-Goog-Upload-Protocol: resumable" \
  -H "X-Goog-Upload-Command: start" \
  -H "X-Goog-Upload-Header-Content-Length: ${NUM_BYTES}" \
  -H "X-Goog-Upload-Header-Content-Type: ${MIME_TYPE}" \
  -H "Content-Type: application/json" \
  -d "{'file': {'display_name': '${DISPLAY_NAME}'}}" 2> /dev/null

upload_url=$(grep -i "x-goog-upload-url: " "${tmp_header_file}" | cut -d" " -f2 | tr -d "\r")
rm "${tmp_header_file}"

# Upload the actual bytes.
curl "${upload_url}" \
  -H "Content-Length: ${NUM_BYTES}" \
  -H "X-Goog-Upload-Offset: 0" \
  -H "X-Goog-Upload-Command: upload, finalize" \
  --data-binary "@${IMAGE_PATH}" 2> /dev/null > file_info.json

file_uri=$(jq ".file.uri" file_info.json)
echo file_uri=$file_uri

# Now generate content using that file
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=$GOOGLE_API_KEY" \
    -H 'Content-Type: application/json' \
    -X POST \
    -d '{
      "contents": [{
        "parts":[
          {"file_data":{"mime_type": "${MIME_TYPE}", "file_uri": '$file_uri'}},
          {"text": "Caption this image."}]
        }]
      }' 2> /dev/null > response.json

cat response.json
echo

jq ".candidates[].content.parts[].text" response.json

メディア ファイルの操作の詳細については、Files API をご覧ください。

画像データをインラインで渡す

画像ファイルをアップロードする代わりに、リクエストでインライン画像データを generateContent に渡すことができます。これは、サイズの小さい画像(合計リクエスト サイズが 20 MB 未満)や、URL から直接取得される画像に適しています。

画像データは、Base64 エンコードされた文字列として提供することも、ローカル ファイルを直接読み取ることもできます(SDK によって異なります)。

ローカル画像ファイル:

Python

  from google.genai import types

  with open('path/to/small-sample.jpg', 'rb') as f:
      img_bytes = f.read()

  response = client.models.generate_content(
    model='gemini-2.0-flash',
    contents=[
      types.Part.from_bytes(
        data=img_bytes,
        mime_type='image/jpeg',
      ),
      'Caption this image.'
    ]
  )

  print(response.text)

JavaScript

import { GoogleGenAI } from "@google/genai";
import * as fs from "node:fs";

const ai = new GoogleGenAI({ apiKey: "GOOGLE_API_KEY" });
const base64ImageFile = fs.readFileSync("path/to/small-sample.jpg", {
  encoding: "base64",
});

const contents = [
  {
    inlineData: {
      mimeType: "image/jpeg",
      data: base64ImageFile,
    },
  },
  { text: "Caption this image." },
];

const response = await ai.models.generateContent({
  model: "gemini-2.0-flash",
  contents: contents,
});
console.log(response.text);

Go

model := client.GenerativeModel("gemini-2.0-flash")

bytes, err := os.ReadFile("path/to/small-sample.jpg")
if err != nil {
  log.Fatal(err)
}

prompt := []genai.Part{
  genai.Blob{MIMEType: "image/jpeg", Data: bytes},
  genai.Text("Caption this image."),
}

resp, err := model.GenerateContent(ctx, prompt...)
if err != nil {
  log.Fatal(err)
}

for _, c := range resp.Candidates {
  if c.Content != nil {
    fmt.Println(*c.Content)
  }
}

REST

IMG_PATH=/path/to/your/image1.jpg

if [[ "$(base64 --version 2>&1)" = *"FreeBSD"* ]]; then
  B64FLAGS="--input"
else
  B64FLAGS="-w0"
fi

curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=$GOOGLE_API_KEY" \
    -H 'Content-Type: application/json' \
    -X POST \
    -d '{
      "contents": [{
        "parts":[
            {
              "inline_data": {
                "mime_type":"image/jpeg",
                "data": "'\$(base64 \$B64FLAGS \$IMG_PATH)'"
              }
            },
            {"text": "Caption this image."},
        ]
      }]
    }' 2> /dev/null

URL の画像:

Python

from google import genai
from google.genai import types

import requests

image_path = "https://goo.gle/instrument-img"
image = requests.get(image_path)

client = genai.Client(api_key="GOOGLE_API_KEY")
response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents=["What is this image?",
              types.Part.from_bytes(data=image.content, mime_type="image/jpeg")])

print(response.text)

JavaScript

import { GoogleGenAI } from "@google/genai";

async function main() {
  const ai = new GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY });

  const imageUrl = "https://goo.gle/instrument-img";

  const response = await fetch(imageUrl);
  const imageArrayBuffer = await response.arrayBuffer();
  const base64ImageData = Buffer.from(imageArrayBuffer).toString('base64');

  const result = await ai.models.generateContent({
    model: "gemini-2.0-flash",
    contents: [
    {
      inlineData: {
        mimeType: 'image/jpeg',
        data: base64ImageData,
      },
    },
    { text: "Caption this image." }
  ],
  });
  console.log(result.text);
}

main();

Go

func main() {
ctx := context.Background()
client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GOOGLE_API_KEY")))
if err != nil {
  log.Fatal(err)
}
defer client.Close()

model := client.GenerativeModel("gemini-2.0-flash")

// Download the image.
imageResp, err := http.Get("https://goo.gle/instrument-img")
if err != nil {
  panic(err)
}
defer imageResp.Body.Close()

imageBytes, err := io.ReadAll(imageResp.Body)
if err != nil {
  panic(err)
}

// Create the request.
req := []genai.Part{
  genai.ImageData("jpeg", imageBytes),

  genai.Text("Caption this image."),
}

// Generate content.
resp, err := model.GenerateContent(ctx, req...)
if err != nil {
  panic(err)
}

// Handle the response of generated text.
for _, c := range resp.Candidates {
  if c.Content != nil {
    fmt.Println(*c.Content)
  }
}

}

REST

IMG_URL="https://goo.gle/instrument-img"

MIME_TYPE=$(curl -sIL "$IMG_URL" | grep -i '^content-type:' | awk -F ': ' '{print $2}' | sed 's/\r$//' | head -n 1)
if [[ -z "$MIME_TYPE" || ! "$MIME_TYPE" == image/* ]]; then
  MIME_TYPE="image/jpeg"
fi

if [[ "$(base64 --version 2>&1)" = *"FreeBSD"* ]]; then
  B64FLAGS="--input"
else
  B64FLAGS="-w0"
fi

curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=$GOOGLE_API_KEY" \
    -H 'Content-Type: application/json' \
    -X POST \
    -d '{
      "contents": [{
        "parts":[
            {
              "inline_data": {
                "mime_type":"'"$MIME_TYPE"'",
                "data": "'$(curl -sL "$IMG_URL" | base64 $B64FLAGS)'"
              }
            },
            {"text": "Caption this image."}
        ]
      }]
    }' 2> /dev/null

インライン画像データに関する留意点は次のとおりです。

  • リクエストの合計サイズの上限は 20 MB です。これには、テキスト プロンプト、システム インストラクション、インラインで提供されるすべてのファイルが含まれます。ファイルのサイズが原因でリクエストの合計サイズが 20 MB を超える場合は、Files API を使用して画像ファイルをアップロードし、リクエストで使用します。
  • 画像サンプルを複数回使用する場合は、File API を使用して画像ファイルをアップロードするほうが効率的です。

複数の画像によるプロンプト

1 つのプロンプトで複数の画像を指定するには、contents 配列に複数の画像 Part オブジェクトを含めます。これらは、インライン データ(ローカル ファイルまたは URL)と File API 参照を組み合わせることができます。

Python

from google import genai
from google.genai import types

client = genai.Client(api_key="GOOGLE_API_KEY")

# Upload the first image
image1_path = "path/to/image1.jpg"
uploaded_file = client.files.upload(file=image1_path)

# Prepare the second image as inline data
image2_path = "path/to/image2.png"
with open(image2_path, 'rb') as f:
    img2_bytes = f.read()

# Create the prompt with text and multiple images
response = client.models.generate_content(
    model="gemini-2.0-flash",
    contents=[
        "What is different between these two images?",
        uploaded_file,  # Use the uploaded file reference
        types.Part.from_bytes(
            data=img2_bytes,
            mime_type='image/png'
        )
    ]
)

print(response.text)

JavaScript

import {
  GoogleGenAI,
  createUserContent,
  createPartFromUri,
} from "@google/genai";
import * as fs from "node:fs";

const ai = new GoogleGenAI({ apiKey: "GOOGLE_API_KEY" });

async function main() {
  // Upload the first image
  const image1_path = "path/to/image1.jpg";
  const uploadedFile = await ai.files.upload({
    file: image1_path,
    config: { mimeType: "image/jpeg" },
  });

  // Prepare the second image as inline data
  const image2_path = "path/to/image2.png";
  const base64Image2File = fs.readFileSync(image2_path, {
    encoding: "base64",
  });

  // Create the prompt with text and multiple images
  const response = await ai.models.generateContent({
    model: "gemini-2.0-flash",
    contents: createUserContent([
      "What is different between these two images?",
      createPartFromUri(uploadedFile.uri, uploadedFile.mimeType),
      {
        inlineData: {
          mimeType: "image/png",
          data: base64Image2File,
        },
      },
    ]),
  });
  console.log(response.text);
}

await main();

Go

+    // Upload the first image
image1Path := "path/to/image1.jpg"
uploadedFile, err := client.UploadFileFromPath(ctx, image1Path, nil)
if err != nil {
    log.Fatal(err)
}
defer client.DeleteFile(ctx, uploadedFile.Name)

// Prepare the second image as inline data
image2Path := "path/to/image2.png"
img2Bytes, err := os.ReadFile(image2Path)
if err != nil {
  log.Fatal(err)
}

// Create the prompt with text and multiple images
model := client.GenerativeModel("gemini-2.0-flash")
prompt := []genai.Part{
  genai.Text("What is different between these two images?"),
  genai.FileData{URI: uploadedFile.URI},
  genai.Blob{MIMEType: "image/png", Data: img2Bytes},
}

resp, err := model.GenerateContent(ctx, prompt...)
if err != nil {
  log.Fatal(err)
}

printResponse(resp)

REST

# Upload the first image
IMAGE1_PATH="path/to/image1.jpg"
MIME1_TYPE=$(file -b --mime-type "${IMAGE1_PATH}")
NUM1_BYTES=$(wc -c < "${IMAGE1_PATH}")
DISPLAY_NAME1=IMAGE1

tmp_header_file1=upload-header1.tmp

curl "https://generativelanguage.googleapis.com/upload/v1beta/files?key=${GOOGLE_API_KEY}" \
  -D upload-header1.tmp \
  -H "X-Goog-Upload-Protocol: resumable" \
  -H "X-Goog-Upload-Command: start" \
  -H "X-Goog-Upload-Header-Content-Length: ${NUM1_BYTES}" \
  -H "X-Goog-Upload-Header-Content-Type: ${MIME1_TYPE}" \
  -H "Content-Type: application/json" \
  -d "{'file': {'display_name': '${DISPLAY_NAME1}'}}" 2> /dev/null

upload_url1=$(grep -i "x-goog-upload-url: " "${tmp_header_file1}" | cut -d" " -f2 | tr -d "\r")
rm "${tmp_header_file1}"

curl "${upload_url1}" \
  -H "Content-Length: ${NUM1_BYTES}" \
  -H "X-Goog-Upload-Offset: 0" \
  -H "X-Goog-Upload-Command: upload, finalize" \
  --data-binary "@${IMAGE1_PATH}" 2> /dev/null > file_info1.json

file1_uri=$(jq ".file.uri" file_info1.json)
echo file1_uri=$file1_uri

# Prepare the second image (inline)
IMAGE2_PATH="path/to/image2.png"
MIME2_TYPE=$(file -b --mime-type "${IMAGE2_PATH}")

if [[ "$(base64 --version 2>&1)" = *"FreeBSD"* ]]; then
  B64FLAGS="--input"
else
  B64FLAGS="-w0"
fi
IMAGE2_BASE64=$(base64 $B64FLAGS $IMAGE2_PATH)

# Now generate content using both images
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=$GOOGLE_API_KEY" \
    -H 'Content-Type: application/json' \
    -X POST \
    -d '{
      "contents": [{
        "parts":[
          {"text": "What is different between these two images?"},
          {"file_data":{"mime_type": "'"${MIME1_TYPE}"'", "file_uri": '$file1_uri'}},
          {
            "inline_data": {
              "mime_type":"'"${MIME2_TYPE}"'",
              "data": "'"$IMAGE2_BASE64"'"
            }
          }
        ]
      }]
    }' 2> /dev/null > response.json

cat response.json
echo

jq ".candidates[].content.parts[].text" response.json

オブジェクトの境界ボックスを取得する

Gemini モデルは、画像内のオブジェクトを識別し、境界ボックスの座標を提供するトレーニングを受けています。座標は画像のサイズを基準として返され、[0, 1000] にスケーリングされます。これらの座標は、元の画像サイズに基づいてスケールを小さくする必要があります。

Python

prompt = "Detect the all of the prominent items in the image. The box_2d should be [ymin, xmin, ymax, xmax] normalized to 0-1000."

JavaScript

const prompt = "Detect the all of the prominent items in the image. The box_2d should be [ymin, xmin, ymax, xmax] normalized to 0-1000.";

Go

prompt := []genai.Part{
    genai.FileData{URI: sampleImage.URI},
    genai.Text("Detect the all of the prominent items in the image. The box_2d should be [ymin, xmin, ymax, xmax] normalized to 0-1000."),
}

REST

PROMPT="Detect the all of the prominent items in the image. The box_2d should be [ymin, xmin, ymax, xmax] normalized to 0-1000."

境界ボックスは、画像や動画内のオブジェクトの検出とローカライズに使用できます。境界ボックスを使用してオブジェクトを正確に識別して区切ることで、幅広いアプリケーションを実現し、プロジェクトのインテリジェンスを強化できます。

主なメリット

  • シンプル: コンピュータ ビジョンの専門知識に関係なく、オブジェクト検出機能をアプリケーションに簡単に統合できます。
  • カスタマイズ可能: カスタムモデルをトレーニングしなくても、カスタム インストラクション(「この画像内のすべての緑色のオブジェクトの境界ボックスを表示したい」など)に基づいて境界ボックスを生成できます。

詳細な技術情報

  • 入力: プロンプトと、関連する画像または動画フレーム。
  • 出力: [y_min, x_min, y_max, x_max] 形式の境界ボックス。左上は原点です。x 軸と y 軸は、それぞれ水平方向と垂直方向に進みます。座標値は、画像ごとに 0~1,000 に正規化されます。
  • 可視化: AI Studio ユーザーには、UI 内に境界ボックスが表示されます。

Python デベロッパーの場合は、2D 空間認識ノートブックまたは試験運用版の 3D ポインティング ノートブックをお試しください。

座標を正規化する

モデルは、境界ボックスの座標を [y_min, x_min, y_max, x_max] の形式で返します。これらの正規化された座標を元の画像のピクセル座標に変換する手順は次のとおりです。

  1. 各出力座標を 1,000 で割ります。
  2. x 座標に元の画像の幅を掛けます。
  3. y 座標に元の画像の高さを掛けます。

境界ボックス座標の生成と画像での可視化の詳細な例については、オブジェクト検出の Cookbook の例をご覧ください。

画像セグメンテーション

Gemini 2.5 モデル以降の Gemini モデルは、アイテムを検出するだけでなく、セグメント化して輪郭のマスクを提供するようにトレーニングされています。

モデルは JSON リストを予測します。各アイテムはセグメンテーション マスクを表します。各アイテムには、0 ~ 1000 の正規化された座標を持つ [y0, x0, y1, x1] 形式の境界ボックス(box_2d)、オブジェクトを識別するラベル(label)、境界ボックス内のセグメンテーション マスク(base64 でエンコードされた png 形式の確率マップ)があります。値は 0 ~ 255 です。マスクは、境界ボックスのサイズに合わせてサイズを変更し、信頼度のしきい値(中央値の場合は 127)でバイナリ化する必要があります。

Python

prompt = """
  Give the segmentation masks for the wooden and glass items.
  Output a JSON list of segmentation masks where each entry contains the 2D
  bounding box in the key "box_2d", the segmentation mask in key "mask", and
  the text label in the key "label". Use descriptive labels.
"""

JavaScript

const prompt = `
  Give the segmentation masks for the wooden and glass items.
  Output a JSON list of segmentation masks where each entry contains the 2D
  bounding box in the key "box_2d", the segmentation mask in key "mask", and
  the text label in the key "label". Use descriptive labels.
`;    

Go

prompt := []genai.Part{
    genai.FileData{URI: sampleImage.URI},
    genai.Text(`
      Give the segmentation masks for the wooden and glass items.
      Output a JSON list of segmentation masks where each entry contains the 2D
      bounding box in the key "box_2d", the segmentation mask in key "mask", and
      the text label in the key "label". Use descriptive labels.
    `),
}

REST

PROMPT='''
  Give the segmentation masks for the wooden and glass items.
  Output a JSON list of segmentation masks where each entry contains the 2D
  bounding box in the key "box_2d", the segmentation mask in key "mask", and
  the text label in the key "label". Use descriptive labels.
'''
カップケーキが置かれたテーブル。木製とガラスのオブジェクトがハイライト表示されています
画像に写っている木製とガラス製のオブジェクトのマスク

詳細な例については、クックブック ガイドのセグメンテーションの例をご覧ください。

サポートされている画像形式

Gemini は、次の画像形式の MIME タイプをサポートしています。

  • PNG - image/png
  • JPEG - image/jpeg
  • WEBP - image/webp
  • HEIC - image/heic
  • HEIF - image/heif

画像に関する技術的な詳細

  • ファイルの上限: Gemini 2.5 Pro、2.0 Flash、1.5 Pro、1.5 Flash は、リクエストあたり最大 3,600 個の画像ファイルをサポートしています。
  • トークンの計算:
    • Gemini 1.5 Flash と Gemini 1.5 Pro: 両方のサイズが 384 ピクセル以下の場合は 258 トークン。サイズが大きい画像はタイル化されます(最小タイルサイズは 256 ピクセル、最大タイルサイズは 768 ピクセル、768x768 にサイズ変更されます)。各タイルの費用は 258 トークンです。
    • Gemini 2.0 Flash: 両方の寸法が 384 ピクセル以下の場合は 258 個のトークン。サイズが大きい画像は、768x768 ピクセルのタイルに分割され、それぞれ 258 個のトークンを使用します。
  • ベスト プラクティス:
    • 画像が正しく回転されていることを確認します。
    • ぼやけていない鮮明な画像を使用します。
    • テキストを含む 1 つの画像を使用する場合は、contents 配列の画像部分の後ろにテキスト プロンプトを配置します。

次のステップ

このガイドでは、画像ファイルをアップロードし、画像入力からテキスト出力を生成する方法について説明します。詳細については、次のリソースをご覧ください。

  • システム指示: システム指示を使用すると、特定のニーズやユースケースに基づいてモデルの動作を制御できます。
  • 動画の理解: 動画入力を操作する方法を学びます。
  • Files API: Gemini で使用するファイルのアップロードと管理の詳細を確認する。
  • ファイル プロンプト戦略: Gemini API は、テキスト、画像、音声、動画データによるプロンプト(マルチモーダル プロンプト)をサポートしています。
  • 安全性に関するガイダンス: 生成 AI モデルは、不正確な出力、偏見のある出力、不適切な出力など、予期しない出力を生成することがあります。このような出力による被害のリスクを軽減するには、後処理と人間による評価が不可欠です。