WWDC Quick Look 💓 By SwiftGGTeam
画像理解の新機能

画像理解の新機能

元の動画を見る

ハイライト

Apple は Vision フレームワークに、任意の物体を分割できる tap-to-segment API を追加し、Foundation Models フレームワークには画像入力を追加しました。両者は Tool Calling でつながり、LLM はバーコード読み取りや OCR などのピクセル単位のタスクを Vision ツールに自動委譲できます。さらに Vision は初めて watchOS に対応しました。

主要内容

「人だけ切り抜ける」から「タップしたものを切り抜ける」へ

これまで Vision で画像セグメンテーションを行う場合、選択肢は限られていました。VNGeneratePersonSegmentationRequest で切り抜けるのは人物と背景だけです。花、コーヒーカップ、床の一部を切り抜きたい場合は、開発者が自分でモデルを訓練するか、サードパーティサービスに頼る必要がありました。

今年 Vision に追加された GenerateIterativeSegmentationRequest では、ユーザーが画像内の任意の物体をタップすると、システムが対応するマスクを生成できます。

操作方法は 4 種類あります。

  • 単一点:カップをタップすると、カップが切り抜かれる
  • 矩形選択:カップと皿を囲むと、両方がまとめて切り抜かれる
  • 投げ縄:クロワッサンの周りに閉じた線を描く
  • スクリブル:複数の物体をざっとなぞり、一度にまとめて選択する

02:19

より実用的なのは反復できる点です。まずカップをタップして mask を作り、次に隣の皿をタップすると、mask が自動的に結合されます。間違えて選んだ場合は減算もできます。カップの本体を除外点としてタップすると、カップの中のコーヒーだけを残せます。

03:16

LLM がついに画像を「見られる」ようになった

Foundation Models フレームワークは今年、画像入力に対応しました。冷蔵庫の中の写真を LLM に渡すとレシピを作れます。リビングの写真を渡すと、インテリアの提案を返せます。

06:09

API はとても直接的です。

import FoundationModels

let prompt = Prompt {
    "この画像のキャプションを生成してください"
    Attachment(image)
}
let response = try await session.respond(to: prompt)
let caption = response.content

06:41

Vision と LLM は二択ではなく、組み合わせるもの

Vision の API は特定タスクに最適化されており、動画フレームを処理できるほど高速です。ただし Vision ができるのはあらかじめ決められた処理であり、画像の内容を「理解」するわけではありません。

LLM はほとんど何でも質問できますが、バーコード上の小さな文字を正確に読んだり、ピクセル単位の精度を扱ったりするのは苦手です。

Apple の解決策は、Tool Calling で両者をつなぐことです。LLM が自力ではうまく解けないタスクに出会うと、自動的に Vision ツールを呼び出して処理します。

たとえば、イベントのチラシ画像を LLM に渡し、日付、場所、申し込み URL を抽出させるとします。チラシに QR コードがある場合、LLM は自分では読み取れないので、Vision の BarcodeReaderTool を呼び出します。URL を取得したあと、LLM が回答を整理します。

11:16

Vision には 2 つの組み込みツールがあります。

  • BarcodeReaderTool:バーコードと QR コードを読み取る
  • OCRTool:30 以上の言語で密集した小さな文字を認識する

11:53

Vision が Apple Watch に来た

Vision フレームワークは初めて watchOS に対応しました。Apple Watch の画面は小さいため、写真全体を表示すると主役が見えにくくなります。GenerateObjectnessBasedSaliencyImageRequest で写真の中の最も目立つ物体を見つけ、切り抜いて主体部分だけを表示できます。

13:18

詳細

Tap-to-segment の完全な使い方

let handler = ImageRequestHandler(image)
let request = GenerateIterativeSegmentationRequest(seed: point)
let observation = try await handler.perform(request)
let mask = observation?.pixelBuffer

// 反復的な微調整:新しい点を追加
request.addIncludedPoint(newPoint)
let refinedObservation = try await handler.perform(request)

04:15

要点:

  • ImageRequestHandler は処理対象の画像を保持する
  • GenerateIterativeSegmentationRequest は今年追加された新しい request 型
  • seed パラメータに初期点を渡し、システムはそこから初期 mask を生成する
  • addIncludedPoint は新しい領域を mask に追加し、addExcludedPoint は mask から領域を取り除く
  • 返される pixelBuffer は白黒のマスクで、白いピクセルが対象物体に属する

注意点は 3 つです。

  1. 座標系の原点は左下で、値の範囲は 0 から 1。使用前に正規化が必要
  2. 投げ縄の線幅は画像幅の 1% 以上が必要。細すぎると認識されない
  3. 初回使用時はモデルのダウンロードが必要。downloadAssets で事前ダウンロードし、assetStatus で状態を確認できる

04:51

LLM 向けの画像ツールを書く

struct PlantIdentifierTool: Tool {
    @SessionProperty(\.history) var history

    @Generable
    struct Arguments {
        var image: ImageReference
    }

    func call(arguments: Arguments) async throws -> String {
        let imageReference = arguments.image
        let transcript = Transcript(history)
        guard let imageAttachment = imageReference.resolve(in: transcript) else {
            throw AppError.imageNotFound
        }
        let image = try imageAttachment.pixelBuffer()
        return classifyPlant(image)
    }
}

09:55

要点:

  • ツールは Tool プロトコルに準拠する必要がある
  • @Generable を付けた引数構造体により、モデルが呼び出し引数を自動生成できる
  • ImageReference は画像への参照であり、実際の画像データではない
  • @SessionProperty(\.history) で現在の会話履歴を取得する
  • Transcript(history) は履歴を問い合わせ可能な transcript に変換する
  • imageReference.resolve(in: transcript) は会話コンテキストから実際の画像添付を解決する
  • pixelBuffer() は添付を CVPixelBuffer に変換し、従来のコンピュータビジョンコードで扱えるようにする

Vision の組み込みツールを使う

import FoundationModels
import Vision

let session = LanguageModelSession(model: model, tools: [BarcodeReaderTool()])
let response = try await session.respond(generating: EventInfo.self) {
    "このチラシから日付、場所、Web サイトを取得してください"
    Attachment(image)
        .label("チラシ")
}

12:09

要点:

  • import Vision すれば BarcodeReaderToolOCRTool を使える
  • LanguageModelSession を作成するときに tools パラメータでツール一覧を渡す
  • Attachment(image).label("チラシ") で画像にラベルを付け、モデルがツール呼び出し時にどの画像を使うか特定できるようにする
  • generating: EventInfo.self により、モデルは指定した構造体形式で結果を返す

watchOS での顕著性クロップ

func generateImageCrop(in image: CGImage) async throws -> NormalizedRect? {
    let request = GenerateObjectnessBasedSaliencyImageRequest()
    let observation = try await request.perform(on: image)
    let prominentObjects = observation.salientObjects
    return prominentObjects.first
}

13:54

要点:

  • GenerateObjectnessBasedSaliencyImageRequest は画像内で「最も目立つ」領域を解析する
  • salientObjects は顕著性順に並んだ矩形配列を返す
  • first を取ると、最も目立つ主体領域を得られる
  • 返される NormalizedRect はそのまま画像の切り抜きに使える

核心的な示唆

1. 「スマート写真編集」アプリを作る

ユーザーが写真内の物体をタップするだけで切り抜き、背景変更やフィルター調整ができます。GenerateIterativeSegmentationRequest でインタラクティブなセグメンテーションを行い、点選択、矩形選択、スクリブルをすべてサポートできます。入口となる API は ImageRequestHandler + GenerateIterativeSegmentationRequest です。

2. 「カメラで何でも識別する」App を作る

ユーザーが植物の写真を撮ると、App が種類を自動識別します。Foundation Models で自然言語のやり取りを行い、具体的な識別タスクではカスタム Vision ツールを呼び出します。実装の考え方は、PlantIdentifierTool を定義し、call メソッド内で ImageReference.resolve により画像を取得して、自前の分類モデルを実行することです。

3. 「レシート自動入力」ツールを作る

ユーザーが請求書やイベントチラシを撮影すると、LLM が金額、日付、場所、URL を自動抽出します。QR コードが読みにくい場合は BarcodeReaderTool を自動呼び出しし、密集した小さな文字は OCRTool で処理します。LanguageModelSession(tools: [BarcodeReaderTool(), OCRTool()]) を設定すれば使えます。

4. Apple Watch での画像表示を最適化する

watchOS の写真 App やメッセージ App で、GenerateObjectnessBasedSaliencyImageRequest を使って写真の主体を自動切り抜きすれば、小さな画面でも重要な部分を見やすくできます。この API は今年初めて watchOS に対応し、それ以前は iOS でしか使えませんでした。

5. 「冷蔵庫の食材管理」App を作る

ユーザーが冷蔵庫を開けて写真を撮ると、LLM が食材を識別し、レシピを提案します。Foundation Models の画像入力機能を使い、Attachment(image) を prompt に直接入れて、食材一覧とレシピ提案を生成させます。

関連セッション

コメント

GitHub Issues · utterances