算譜王におれはなる!!!!

偏りはあると思うけど情報技術全般についてマイペースに書くよ。

Gemini 2.0の空間認識をJavaScriptで試す

Gemini 2.0 Flashのプレビューが出ましたね。 APIドキュメントを見て、興味を惹かれたのはBounding box detection。 かねてより、画像から対象の座標を取れたら面白いことできそうだな〜と思っていました。 Google AI Studioで試すことができます。

Google AI Studioが発行しているプロンプトを確認すると

Detect 料理, with no more than 20 items. Output a json list where each entry contains the 2D bounding box in "box_2d" and a text label in "label".

って感じで、自然言語JSONの形式を指定しているんですね。OpenAIのstructured_outputに慣れているとちょっと驚き。 実際に、どういうレスポンスが来るのかは後述します。

この空間認識・バウンディング検出は、既存のJavaScript向けSDKでも利用可能であるのが、すぐ試すには手軽でよいです。 新しいSDKは、JavaScript向けの提供がまだ始まっていないようなので。

const model = vertexai.getGenerativeModel({
  model: "gemini-2.0-flash-exp",
});

素直に、新しいモデル名を指定するだけで使えるみたいです。 あとは、いつも通りに generateContent を呼び出してテキストを生成するだけです。 先述のようにバウンディングを検出したい旨をプロンプトに含めることで、決まった書式のJSONっぽいものが返されます。

まずは2Dから実装。 プロンプトはGoogle AI Studioのものを、ちょこっといじってこんな感じにしてみます。

`Detect ${target}, with no more than 20 items. Output a json list where each entry contains the 2D bounding box in "box_2d" and name in "label".`

これでgenerateContentすると、次のようなテキストが生成されます。

```json
[
  {"box_2d": [13, 432, 457, 879], "label": "料理"},
  {"box_2d": [309, 0, 892, 509], "label": "料理"},
  {"box_2d": [535, 390, 892, 773], "label": "料理"}
]
```

純粋なJSONではなくて、JSONを含むMarkdownであることに注意が必要です。中身のJSONだけ取り出して扱いましょう。 整数の配列の意味はこの資料に書かれています。 画像 左上の座標を (0, 0) とし、右下の座標を (1000, 1000) としたときの、ボックスの左上、右下の座標を表しています。 y座標が先で、x座標が後なことに注意。 つまり [13, 432, 457, 879] は、左上 x=432, y=13 右下 x=879, y=457 です。

実際にブラウザ上にただ表示するのは簡単です。 CSSでabsoluteしてtop, left, width, heightを%指定するだけですね。

3Dも大体同じではあります。 Google AI Studioのプロンプトをいじって、こうしてみました。

`Detect the 3D bounding boxes of ${target} , output no more than 10 items. Output a json list where each entry contains the object name in "label" and its 3D bounding box in "box_3d".`

生成されるテキストはこんな感じです。

```json
[
  {"label": "料理", "box_3d": [0.41,1.54,0.22,0.71,0.74,0.87,-34,-13,10]},
  {"label": "料理", "box_3d": [-0.31,1.55,-0.1,0.71,0.5,0.76,-34,-12,9]},
  {"label": "料理", "box_3d": [0.06,1.54,-0.4,0.46,0.36,0.37,-33,-2,2]}
]
```

それぞれの数値の意味は

  • 最初の3つ: x_center, y_center, z_center
  • 真ん中の3つ: x_size, y_size, z_size
  • 最後の3つ: x軸の回転、y軸の回転, z軸の回転(度数法)

で、ドキュメント曰く x_center とか x_size はメートル単位の長さっぽいです。 なので、画面に描画したあとはズームイン/ズームアウトを行って、元画像との重なりを調節しなきゃいけないと思います、たぶん。

今回はReactでThree.jsするReact Three Fiberを使いました。

ちなみに、Next.js 15系でReact Three Fiber 8.17.10だと、上手く動きませんでした。 このissueを参考に、9.0.0-rc.1 のReact Three Fiberを使ったら上手く行きました。

もう一つ厄介、というか誤解の種として、Three.jsの座標系とGeminiが返すそれは異なるので注意が必要です。 Three.jsは、画面に対して垂直方向がy軸で、奥行きがz軸。 Geminiは、垂直方向がz軸で、奥行きがy軸っぽいです。

そこを気をつけてReact Three Fiberで箱型の辺を組めば、期待通りに3Dを描画できます。

なお、3Dの方はまだ実験段階にあり、精度は高くないようです。

ところで、全然関係ないですが、使用している写真はつじ田、お気に入りのつけ麺屋さんの一つです。