vision-framework について
Apple プラットフォーム開発者向けに、画像や動画のオンデバイス画像認識を扱う Vision スキルです。最新の非同期リクエスト、旧 API へのフォールバック、VisionKit と Core ML の連携を解説します。
主な機能
- 01テキスト、顔、バーコードの認識
- 02構造化された文書内容の読み取り
- 03セグメンテーションマスク生成と物体追跡
- 04人体、手、動物のポーズ検出
- 05Vision による Core ML モデルの実行
- 06VisionKit によるライブテキスト・バーコードスキャン
活用シーン
- 01画像からテキストやバーコード内容を抽出
- 02文書をスキャンしてレイアウトを解析
- 03動画フレーム間で物体を追跡
- 04画像効果向けの人物マスクを生成
- 05カメラ映像内のテキストやバーコードをスキャン
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dpearson2699/ swift-ios-skills --skill vision-frameworkインストール後、Claude Code で/vision-frameworkを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/evals.jsonreferences/vision-requests.mdvisionkit-scanner.md詳細
Vision Framework
デバイス上のコンピュータービジョンを使用して、画像や動画からテキスト、顔、バーコード、オブジェクト、身体の姿勢を検出します。最新の iOS 18 以降のリクエスト API を優先し、デプロイメントターゲットで必要な場合にのみレガシーリファレンスを読み込んでください。
完全なコードパターンについては、references/vision-requests.md を参照してください。また、DataScannerViewController との統合については、references/visionkit-scanner.md を参照してください。
Contents
- 2 世代の API
- リクエストのパターン(最新 API)
- テキスト認識(OCR)
- 顔検出
- バーコード検出
- 書類のスキャン(iOS 26+)
- 画像のセグメンテーション
- オブジェクトの追跡
- その他のリクエストタイプ
- Core ML との統合
- VisionKit:DataScannerViewController
- よくある間違い
- レビュー用チェックリスト
- リファレンス
2 世代の API
Vision には、異なる 2 つの API レイヤーがあります。新しいコードでは最新の API を優先してください。Swift ネイティブのリクエストタイプと try await request.perform(on:) を使用します。VN*、VNImageRequestHandler、VNSequenceRequestHandler、完了ハンドラー、レガシーの CGRect ヘルパーは、明示的なレガシー用フォールバックセクションまたはファイル内に限定してください。
| 観点 | 最新(iOS 18+) | レガシー |
|---|---|---|
| パターン | let result = try await request.perform(on: image) | VNImageRequestHandler + 完了ハンドラー |
| リクエストタイプ | Swift の型 — 構造体とクラス(RecognizeTextRequest、DetectFaceRectanglesRequest) | Objective-C のクラス(VNRecognizeTextRequest、VNDetectFaceRectanglesRequest) |
| 並行処理 | ネイティブの async/await | 完了ハンドラーまたは同期的な perform |
| 観測結果 | 型付きの戻り値 | [Any] から results をキャスト |
| 対応状況 | iOS 18+ / macOS 15+ | iOS 11+ |
最新の API は ImageProcessingRequest プロトコルを使用します。各リクエストタイプには、CGImage、CIImage、CVPixelBuffer、CMSampleBuffer、Data、URL を受け取る perform(on:orientation:) メソッドがあります。ほとんどのリクエストは構造体です。GeneratePersonSegmentationRequest、TrackObjectRequest、TrackRectangleRequest、DetectTrajectoriesRequest などの状態を持つリクエストは final クラスです。
リクエストのパターン(最新 API)
すべての最新の Vision リクエストは、同じパターンに従います。リクエストを作成し、perform(on:) を呼び出して、型付きの結果を処理します。
import Vision
func recognizeText(in image: CGImage) async throws -> [String] {
var request = RecognizeTextRequest()
request.recognitionLevel = .accurate
request.recognitionLanguages = [Locale.Language(identifier: "en-US")]
let observations = try await request.perform(on: image)
return observations.compactMap { observation in
observation.topCandidates(1).first?.string
}
}
レガシーパターン(iOS 18 より前)
iOS 18 より前のターゲットでは、対応する VNRequest と VNImageRequestHandler または VNSequenceRequestHandler を使用してください。完全なレガシーのリクエストとハンドラーのパターンについては、references/vision-requests.md を読み込んでください。
テキスト認識(OCR)
最新:RecognizeTextRequest(iOS 18+)
var request = RecognizeTextRequest()
request.recognitionLevel = .accurate // .fast for real-time
request.recognitionLanguages = [
Locale.Language(identifier: "en-US"),
Locale.Language(identifier: "fr-FR"),
]
request.usesLanguageCorrection = true
request.customWords = ["SwiftUI", "Xcode"] // domain-specific terms
let observations = try await request.perform(on: cgImage)
for observation in observations {
guard let candidate = observation.topCandidates(1).first else { continue }
let text = candidate.string
let confidence = candidate.confidence // 0.0 ... 1.0
let bounds = observation.boundingBox // NormalizedRect
}
レガシー:VNRecognizeTextRequest
レガシーのリクエストでは、文字列による言語識別子と、リファレンスに記載されているハンドラーパターンを使用します。どちらの世代も、高精度と高速の認識レベルに対応しています。
顔検出
顔の矩形、ランドマーク(目、鼻、口)、撮影品質を検出します。
// Modern API
let faceRequest = DetectFaceRectanglesRequest()
let faces = try await faceRequest.perform(on: cgImage)
for face in faces {
let boundingBox = face.boundingBox // NormalizedRect
let roll = face.roll // Measurement<UnitAngle>
let yaw = face.yaw // Measurement<UnitAngle>
}
// Landmarks (eyes, nose, mouth contours)
var landmarkRequest = DetectFaceLandmarksRequest()
let landmarkFaces = try await landmarkRequest.perform(on: cgImage)
for face in landmarkFaces {
let landmarks = face.landmarks
let leftEye = landmarks?.leftEye.points
let nose = landmarks?.nose.points
}
座標系
Vision は、原点が左下にある正規化座標系を使用します。表示する前に UIKit(原点が左上)用に変換してください。
import Vision
func imageRectForDisplay(_ rect: NormalizedRect, imageSize: CGSize) -> CGRect {
rect.toImageCoordinates(imageSize, origin: .upperLeft)
}
バーコード検出
QR コードを含む 1D および 2D バーコードを検出します。
var request = DetectBarcodesRequest()
let symbologies: [BarcodeSymbology] = [.qr, .ean13, .code128, .pdf417]
request.symbologies = symbologies
let barcodes = try await request.perform(on: cgImage)
for barcode in barcodes {
let payload = barcode.payloadString // decoded content
let symbology = barcode.symbology // .qr, .ean13, etc.
let bounds = barcode.boundingBox // NormalizedRect
}
まずローカル値に型を指定してから、リクエストのプロパティを個別に設定してください。
ドキュメントスキャン(iOS 26+)
RecognizeDocumentsRequest は、基本的な OCR を超えたレイアウト理解を備えた、構造化ドキュメント読み取り機能を提供します。段落、表、リスト、バーコードを格納するネストされた Container 構造を持つ DocumentObservation オブジェクトを返します。現在、Vision は画像ごとに 1 つのドキュメント観測結果を返します。
var request = RecognizeDocumentsRequest()
let documents = try await request.perform(on: cgImage)
for observation in documents {
let container = observation.document
// Full text content
let fullText = container.text
// Structured access to paragraphs
for paragraph in container.paragraphs {
let paragraphText = paragraph.text
}
// Tables and lists
for table in container.tables { /* structured table data */ }
for list in container.lists { /* structured list data */ }
// Embedded barcodes detected within the document
for barcode in container.barcodes { /* barcode data */ }
// Document title if detected
if let title = container.title { print(title) }
}
よりシンプルなドキュメントカメラのスキャンには、自動撮影、パースペクティブ補正、複数ページのスキャンに対応した全画面カメラ UI を提供する VisionKit の
VNDocumentCameraViewController を使用してください。
画像のセグメンテーション
最新:GeneratePersonSegmentationRequest(iOS 18+)
var request = GeneratePersonSegmentationRequest()
request.qualityLevel = .accurate // .balanced, .fast
let mask = try await request.perform(on: cgImage)
// mask is a PixelBufferObservation with a pixelBuffer property
let maskBuffer = mask.pixelBuffer
// Apply mask using Core Image: CIFilter.blendWithMask()
レガシー:VNGeneratePersonSegmentationRequest
古いターゲットでは、VNGeneratePersonSegmentationRequest は最初のピクセルバッファ観測結果を通じてマスクを公開します。リファレンスのハンドラーとマスク合成の手順を使用してください。
品質レベル:
.accurate-- 最高品質、最も低速(約1秒)、フル解像度.balanced-- 良好な品質、中程度の速度(約100ms)、960x540.fast-- 最低品質、最速(約10ms)、256x144、リアルタイムに適しています
インスタンスセグメンテーション(iOS 18+)
個別のエフェクトを適用できるよう、人ごとにマスクを分離します。
// Modern API (iOS 18+)
let request = GeneratePersonInstanceMaskRequest()
let observation = try await request.perform(on: cgImage)
let indices = observation.allInstances
for index in indices {
let mask = try observation.generateMask(for: IndexSet(integer: index))
// mask is a CVPixelBuffer with only this person visible
}
// Legacy API (iOS 17+)
let request = VNGeneratePersonInstanceMaskRequest()
let handler = VNImageRequestHandler(cgImage: cgImage)
try handler.perform([request])
guard let result = request.results?.first else { return }
let indices = result.allInstances
for index in indices {
let instanceMask = try result.generateMaskedImage(
ofInstances: IndexSet(integer: index),
from: handler,
croppedToInstancesExtent: false
)
}
マスク合成と Core Image フィルターの統合パターンについては、references/vision-requests.md を参照してください。
オブジェクトトラッキング
最新:TrackObjectRequest(iOS 18+)
TrackObjectRequest は、フレーム間でトラッキングのコンテキストを維持するステートフルなリクエストです。
// Initialize with a detected object's bounding box
let initialObservation = DetectedObjectObservation(boundingBox: detectedBox)
let request = TrackObjectRequest(detectedObject: initialObservation)
for pixelBuffer in framePixelBuffers {
let results = try await request.perform(on: pixelBuffer)
if let tracked = results.first {
let updatedBounds = tracked.boundingBox // NormalizedRect
}
}
最新の TrackObjectRequest には trackingLevel や qualityLevel はありません。
レガシー:VNTrackObjectRequest
古いターゲットでは、保持した VNSequenceRequestHandler を 1 つ使用して VNTrackObjectRequest を実行し、各結果を次の入力観測結果として渡します。リファレンスにはループ全体が記載されています。
その他のリクエストタイプ
Vision が提供するその他のリクエストについては、references/vision-requests.md を参照してください。
| リクエスト | 用途 |
|---|---|
ClassifyImageRequest | シーンの内容(屋外、食べ物、動物など)を分類します |
GenerateAttentionBasedSaliencyImageRequest | 視聴者の注意が集まる場所を示す、単一の SaliencyImageObservation を返します |
GenerateObjectnessBasedSaliencyImageRequest | オブジェクトらしい領域を示す、単一の SaliencyImageObservation を返します |
GenerateForegroundInstanceMaskRequest | 前景オブジェクトをセグメンテーションします(人物に限定されません) |
DetectRectanglesRequest | 長方形の形状(ドキュメント、カード、画面)を検出します |
DetectHorizonRequest | 写真の自動水平補正用に地平線の角度を検出します |
DetectHumanBodyPoseRequest | 身体の関節(肩、肘、膝)を検出します |
DetectHumanBodyPose3DRequest | 3D 人体姿勢を推定します |
DetectHumanHandPoseRequest | 手の関節と指の位置を検出します |
DetectAnimalBodyPoseRequest | 動物の身体の関節位置を検出します |
DetectFaceCaptureQualityRequest | 写真選択用に顔の撮影品質をスコア化します(0~1) |
TrackRectangleRequest | 動画フレーム間で長方形のオブジェクトを追跡します |
TrackOpticalFlowRequest | 動画フレーム間のオプティカルフローを検出します |
DetectTrajectoriesRequest | 動画内のオブジェクトの軌跡を検出します |
上記の最新のリクエストタイプはすべて、iOS 18+ / macOS 15+ に対応しています。
Core ML の統合
Vision を通じてカスタム Core ML モデルを実行し、画像を自動的に前処理します。
Vision は、すでに準備されたモデルを CoreMLRequest または VNCoreMLRequest で実行します。変換、プロファイリング、パッケージ化、ライフサイクルに関する判断は coreml に任せてください。
import CoreML
import Vision
// Modern API (iOS 18+): CoreMLRequest takes a CoreMLModelContainer.
let model = try MLModel(contentsOf: modelURL)
let container = try CoreMLModelContainer(model: model, featureProvider: nil)
let request = CoreMLRequest(model: container)
let results = try await request.perform(on: cgImage)
// Classification model
if let classification = results.first as? ClassificationObservation {
let label = classification.identifier
let confidence = classification.confidence
}
CoreMLModelContainer は、CoreMLRequest 用の iOS 18+ 向け公開 Vision コンテナーです。MLModel を読み込み、CoreMLModelContainer(model:featureProvider:) でラップしてから、そのコンテナーを CoreMLRequest(model:) に渡します。Vision を通じた Core ML の結果マッピングを確認する際は、分類器は ClassificationObservation を、画像出力は PixelBufferObservation を、汎用予測器は CoreMLFeatureValueObservation を生成することに注意してください。
// Legacy API
let vnModel = try VNCoreMLModel(for: model)
let request = VNCoreMLRequest(model: vnModel) { request, error in
guard let results = request.results as? [VNClassificationObservation] else { return }
let topResult = results.first
}
let handler = VNImageRequestHandler(cgImage: cgImage)
try handler.perform([request])
VisionKit:DataScannerViewController
DataScannerViewController は、テキストとバーコードをリアルタイムでスキャンするカメラ機能を提供します。references/visionkit-scanner.md を参照してください。VisionKit は VNBarcodeSymbology を使用します。最新の DetectBarcodesRequest は BarcodeSymbology を使用します。
クイックスタート
import AVFoundation
import Vision
import VisionKit
@MainActor
func presentScanner() async {
// Add NSCameraUsageDescription before requesting camera access.
guard await AVCaptureDevice.requestAccess(for: .video) else { return }
guard DataScannerViewController.isSupported,
DataScannerViewController.isAvailable else { return }
let scannerSymbologies: [VNBarcodeSymbology] = [.qr, .ean13]
let scanner = DataScannerViewController(
recognizedDataTypes: [
.text(languages: ["en"]),
.barcode(symbologies: scannerSymbologies)
],
qualityLevel: .balanced,
recognizesMultipleItems: true,
isHighFrameRateTrackingEnabled: true,
isHighlightingEnabled: true
)
scanner.delegate = self
present(scanner, animated: true) {
// Start scanning after presentation, on the main actor.
try? scanner.startScanning()
}
}
SwiftUI との統合
DataScannerViewController を UIViewControllerRepresentable でラップし、updateUIViewController で Task { @MainActor in try? controller.startScanning() } を使用して開始します。references/visionkit-scanner.md を参照してください。
よくある間違い
避けること: iOS 18 以降を対象とする新しいプロジェクトで、従来の VNImageRequestHandler API を使用すること。
推奨: perform(on:) と async/await を使う、最新の Swift ネイティブのリクエストを使用してください。
理由: 最新の API は型安全性が高く、Swift の並行処理をより適切にサポートし、エラー処理も簡潔です。
避けること: バウンディングボックスを描画する前に、正規化座標を変換し忘れること。
推奨: 最新のオブザベーションには NormalizedRect.toImageCoordinates(_:origin:) を、従来の CGRect オブザベーションには VNImageRectForNormalizedRect(_:_:_:) を使用してください。
理由: Vision は左下を原点とする正規化座標(0...1)を使用しますが、UIKit は左上を原点とするポイントを使用します。
避けること: Vision のリクエストをメインスレッドで実行すること。 推奨: バックグラウンドスレッドでリクエストを実行するか、デタッチされたタスクから async/await を使用してください。 理由: 画像解析は CPU/GPU を大量に使用する処理であり、メインアクターで実行すると UI がブロックされます。
避けること: リアルタイムのカメラ映像に .accurate 認識レベルを使用すること。
推奨: ライブ映像には .fast を、静止画像やオフライン処理には .accurate を使用してください。
理由: 高精度認識は 30fps の映像には遅すぎます。高速認識は品質と引き換えに速度を向上させます。
避けること: Vision のすべてのオブザベーションが同じプロパティを持つと想定すること。 推奨: 共通ヘルパーを作成する前に、各オブザベーション型のバウンディングボックス、信頼度、ペイロード、マスク、角度の各フィールドを確認してください。 理由: 最新の Vision は型付けされたオブザベーションを返し、結果の形状はリクエストによって異なります。
避けること: 各ビデオフレームで状態を保持するトラッキングリクエストを作り直すこと。
推奨: 同じ最新の TrackObjectRequest インスタンスを保持するか、従来のトラッキングリクエストでは VNSequenceRequestHandler を使用してください。
理由: トラッキングはフレーム間の時間的なコンテキストに依存します。
避けること: QR コードだけが必要なときに、すべてのバーコードシンボル体系をリクエストすること。 推奨: リクエストには必要なシンボル体系のみを指定してください。 理由: シンボル体系が少ないほど検出が速くなり、誤検出も減ります。
避けること: すべてのデバイスで DataScannerViewController が利用できると想定すること。
推奨: 表示する前に、isSupported(ハードウェア)と isAvailable(ユーザーの許可)の両方を確認してください。
理由: A12 以降のチップが必要です。isAvailable はカメラへのアクセス許可も確認します。
レビューチェックリスト
- 古いデプロイ対象をサポートする場合を除き、最新の Vision API(iOS 18 以降)を使用している
- Vision のリクエストがメインスレッド以外で実行されている(async/await またはバックグラウンドキュー)
- UI に表示する前に正規化座標が変換されている
- 品質の低いオブザベーションを除外するため、信頼度のしきい値が適用されている
- 認識レベルが用途に適している(動画には
.fast、静止画には.accurate) - 入力言語がわかっている場合、テキスト認識に言語ヒントが設定されている
- バーコードのシンボル体系が必要なものだけに限定されている
- 表示前に
DataScannerViewControllerの利用可否が確認されている - VisionKit のために、Info.plist にカメラ使用の説明(
NSCameraUsageDescription)が設定されている - 表示前に VisionKit のカメラアクセスがリクエストされ、表示後にスキャンが開始されている
- 人物セグメンテーションの品質レベルが用途に適している
- 状態を保持するトラッキングリクエストまたは
VNSequenceRequestHandlerがビデオフレーム間で保持されている - エラー処理でリクエストの失敗と結果が空の場合に対応している
References
- Vision request patterns: references/vision-requests.md
- VisionKit scanner integration: references/visionkit-scanner.md
- Apple docs: Vision | VisionKit | RecognizeTextRequest | DataScannerViewController | CoreMLRequest | CoreMLModelContainer