mcpField
A
axiom-vision-ref

axiom-vision-ref

github.com/charleswiltgen開発1.2k180 回インストール今日更新
リポジトリ

axiom-vision-ref について

画像のセグメンテーション、姿勢や顔の検出、OCR、バーコード検出、書類スキャンに使うVisionフレームワークのAPIリファレンスです。リクエストハンドラーの使い分けや、動画シーケンスでの状態処理も説明します。

主な機能

  1. 01前景・人物のセグメンテーションAPI
  2. 02手と身体の姿勢検出
  3. 03顔分析とテキスト認識
  4. 04バーコード検出と書類スキャン
  5. 05画像・シーケンス用ハンドラー

活用シーン

  1. 01画像から前景の被写体を抽出
  2. 02ジェスチャーやフィットネスアプリで姿勢を追跡
  3. 03画像内の文字やバーコードを認識
  4. 04ライブスキャナーや書類認識を構築

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/charleswiltgen/axiom --skill axiom-vision-ref

インストール後、Claude Code で/axiom-vision-refを入力して読み込まれたか確認します。

詳細

Vision フレームワーク API リファレンス

Vision フレームワークのコンピュータービジョン機能に関する包括的なリファレンスです。対象のセグメンテーション、手や身体のポーズ検出、人物検出、顔分析、テキスト認識(OCR)、バーコード検出、書類スキャンを扱います。

このリファレンスを使用する場面

  • VisionKit または Vision を使って対象の切り抜きを実装する
  • ジェスチャー認識やフィットネスアプリ向けに手や身体のポーズを検出する
  • 背景から人物をセグメント化する、または複数の人物を分離する
  • AR エフェクトや認証向けに顔検出と顔の特徴点検出を行う
  • 複雑なコンピュータービジョンの問題を解決するためにVision API を組み合わせる
  • 特定の API シグネチャやパラメーターの意味を調べる
  • VNRecognizeTextRequest を使って画像内のテキストを認識する(OCR)
  • VNDetectBarcodesRequest を使ってバーコードや QR コードを検出する
  • DataScannerViewController を使ってライブスキャナーを構築する
  • VNDocumentCameraViewController を使って書類をスキャンする
  • RecognizeDocumentsRequest を使って書類の構造化データを抽出する(iOS 26 以降)

関連スキル:判断ツリーとパターンについては axiom-vision、トラブルシューティングについては axiom-vision-diag を参照してください。

Vision フレームワークの概要

Vision は、静止画像とビデオ向けのコンピュータービジョンアルゴリズムを提供します。

基本的なワークフロー:

  1. リクエストを作成します(例:VNDetectHumanHandPoseRequest())
  2. 画像を指定してハンドラーを作成します(VNImageRequestHandler(cgImage: image))
  3. リクエストを実行します(try handler.perform([request]))
  4. request.results から観測結果にアクセスします

座標系:左下が原点の正規化座標(0.0〜1.0)

パフォーマンス:バックグラウンドキューで実行してください。リソースを大量に消費するため、メインスレッドで実行すると UI がブロックされます。

リクエストハンドラー

Vision は、用途に応じて 2 種類のリクエストハンドラーを提供します。

VNImageRequestHandler

単一の画像を分析します。画像を指定して初期化し、その画像に対してリクエストを実行した後、破棄します。

let handler = VNImageRequestHandler(cgImage: image)
try handler.perform([request1, request2])  // Multiple requests, one image

初期化に使用できるもの:CGImage、CIImage、CVPixelBuffer、Data、または URL

ルール:画像ごとに 1 つのハンドラーを使用します。別の画像でハンドラーを再利用することはサポートされていません。

VNSequenceRequestHandler

フレームのシーケンス(ビデオ、カメラ映像)を分析します。空の状態で初期化し、各フレームを perform() に渡します。フレーム間の状態を保持し、時間的な平滑化を行います。

let sequenceHandler = VNSequenceRequestHandler()

// In your camera/video frame callback:
func processFrame(_ pixelBuffer: CVPixelBuffer) throws {
    try sequenceHandler.perform([request], on: pixelBuffer)
}

ルール:一度作成したら、フレーム間で再利用します。ハンドラーは呼び出し間の状態を追跡します。

どちらを使用するか
用途ハンドラー
単一の写真またはスクリーンショットVNImageRequestHandler
ビデオストリームまたはカメラのフレームVNSequenceRequestHandler
時間的な平滑化(ポーズ、セグメンテーション)VNSequenceRequestHandler
CVPixelBuffer の単発分析VNImageRequestHandler
シーケンス処理で効果が得られるリクエスト

以下のリクエストは、VNSequenceRequestHandler を通じて実行するとフレーム間の状態を利用します。

  • VNDetectHumanBodyPoseRequest — 関節の追跡がより滑らかになります
  • VNDetectHumanHandPoseRequest — 特徴点の追跡がより滑らかになります
  • VNGeneratePersonSegmentationRequest — 時間的に一貫したマスクを生成します
  • VNGeneratePersonInstanceMaskRequest — フレーム間で人物の識別を安定させます
  • VNDetectDocumentSegmentationRequest — 書類の輪郭が安定します
  • VNStatefulRequest のサブクラスすべて — シーケンス向けに設計されています
よくある間違い

ビデオの各フレームで新しい VNImageRequestHandler を作成すると、時間的なコンテキストが失われます。ポーズの特徴点が揺れ、セグメンテーションマスクがちらつき、シーケンス処理による平滑化の効果も得られなくなります。

// Wrong — loses temporal context every frame
func processFrame(_ buffer: CVPixelBuffer) throws {
    let handler = VNImageRequestHandler(cvPixelBuffer: buffer)
    try handler.perform([poseRequest])
}

// Right — maintains inter-frame state
let sequenceHandler = VNSequenceRequestHandler()
func processFrame(_ buffer: CVPixelBuffer) throws {
    try sequenceHandler.perform([poseRequest], on: buffer)
}

対象セグメンテーション API

VNGenerateForegroundInstanceMaskRequest

利用可能な OS:iOS 17 以降、macOS 14 以降、tvOS 17 以降、visionOS 1 以降

人物、ペット、建物、食べ物、靴など、前景のオブジェクトのクラスに依存しないインスタンスマスクを生成します。

基本的な使用方法
let request = VNGenerateForegroundInstanceMaskRequest()
let handler = VNImageRequestHandler(cgImage: image)

try handler.perform([request])

guard let observation = request.results?.first as? VNInstanceMaskObservation else {
    return
}
InstanceMaskObservation

allInstances:前景にあるすべてのインスタンスインデックスを含む IndexSet(背景の 0 は除外)

instanceMask:UInt8 ラベルを持つ CVPixelBuffer(0 = 背景、1 以上 = インスタンスインデックス)

instanceAtPoint(_:):正規化座標の点にあるインスタンスインデックスを返します

let point = CGPoint(x: 0.5, y: 0.5)  // Center of image
let instance = observation.instanceAtPoint(point)

if instance == 0 {
    print("Background tapped")
} else {
    print("Instance \(instance) tapped")
}
マスクの生成

createScaledMask(for:croppedToInstancesContent:)

パラメーター:

  • for:含めるインスタンスのIndexSet
  • croppedToInstancesContent:
    • false = 入力と同じ解像度で出力します(合成用)
    • true = 選択したインスタンスの周囲をぴったり切り抜きます

戻り値:単一チャンネルの浮動小数点CVPixelBuffer(ソフトセグメンテーションマスク)

// All instances, full resolution
let mask = try observation.createScaledMask(
    for: observation.allInstances,
    croppedToInstancesContent: false
)

// Single instance, cropped
let instances = IndexSet(integer: 1)
let croppedMask = try observation.createScaledMask(
    for: instances,
    croppedToInstancesContent: true
)
インスタンスマスクのヒットテスト

未加工のピクセルバッファにアクセスして、タップ座標をインスタンスラベルにマッピングします:

let instanceMask = observation.instanceMask

CVPixelBufferLockBaseAddress(instanceMask, .readOnly)
defer { CVPixelBufferUnlockBaseAddress(instanceMask, .readOnly) }

let baseAddress = CVPixelBufferGetBaseAddress(instanceMask)
let width = CVPixelBufferGetWidth(instanceMask)
let bytesPerRow = CVPixelBufferGetBytesPerRow(instanceMask)

// Convert normalized tap to pixel coordinates
let pixelPoint = VNImagePointForNormalizedPoint(
    CGPoint(x: normalizedX, y: normalizedY),
    width: imageWidth,
    height: imageHeight
)

// Calculate byte offset
let offset = Int(pixelPoint.y) * bytesPerRow + Int(pixelPoint.x)

// Read instance label
let label = UnsafeRawPointer(baseAddress!).load(
    fromByteOffset: offset,
    as: UInt8.self
)

let instances = label == 0 ? observation.allInstances : IndexSet(integer: Int(label))

VisionKit の被写体切り抜き

ImageAnalysisInteraction(iOS)

利用可能な環境:iOS 16 以降、iPadOS 16 以降

ビューにシステムのような被写体切り抜き UI を追加します:

let interaction = ImageAnalysisInteraction()
interaction.preferredInteractionTypes = .imageSubject  // Or .automatic
imageView.addInteraction(interaction)

インタラクションの種類:

  • .automatic:被写体切り抜き + Live Text + データ検出
  • .imageSubject:被写体切り抜きのみ(操作可能なテキストなし)
ImageAnalysisOverlayView(macOS)

利用可能な環境:macOS 13 以降

let overlayView = ImageAnalysisOverlayView()
overlayView.preferredInteractionTypes = .imageSubject
nsView.addSubview(overlayView)
プログラムによるアクセス
ImageAnalyzer
let analyzer = ImageAnalyzer()
let configuration = ImageAnalyzer.Configuration([.text, .visualLookUp])

let analysis = try await analyzer.analyze(image, configuration: configuration)
ImageAnalysis

subjects:[Subject] - 画像内のすべての被写体

highlightedSubjects:Set<Subject> - 現在ハイライト表示されている被写体(ユーザーが長押ししたもの)

subject(at:):正規化された座標の被写体を非同期で検索します(該当する被写体がない場合はnilを返します)

// Get all subjects
let subjects = analysis.subjects

// Look up subject at tap
if let subject = try await analysis.subject(at: tapPoint) {
    // Process subject
}

// Change highlight state
analysis.highlightedSubjects = Set([subjects[0], subjects[1]])
Subject 構造体

image:UIImage/NSImage - 透明部分を含む抽出済みの被写体

bounds:CGRect - 画像座標における被写体の境界

// Single subject image
let subjectImage = subject.image

// Composite multiple subjects
let compositeImage = try await analysis.image(for: [subject1, subject2])

プロセス外での処理:VisionKit の解析はプロセス外で実行されます(パフォーマンス上の利点がありますが、画像サイズには制限があります)

人物セグメンテーション API

VNGeneratePersonSegmentationRequest

利用可能な環境:iOS 15 以降、macOS 12 以降

画像内のすべての人物を含む単一のマスクを返します:

let request = VNGeneratePersonSegmentationRequest()
// Configure quality level if needed
try handler.perform([request])

guard let observation = request.results?.first as? VNPixelBufferObservation else {
    return
}

let personMask = observation.pixelBuffer  // CVPixelBuffer
VNGeneratePersonInstanceMaskRequest

利用可能な環境:iOS 17 以降、macOS 14 以降

最大 4 人分の個別マスクを返します:

let request = VNGeneratePersonInstanceMaskRequest()
try handler.perform([request])

guard let observation = request.results?.first as? VNInstanceMaskObservation else {
    return
}

// Same InstanceMaskObservation API as foreground instance masks
let allPeople = observation.allInstances  // Up to 4 people (1-4)

// Get mask for person 1
let person1Mask = try observation.createScaledMask(
    for: IndexSet(integer: 1),
    croppedToInstancesContent: false
)

制限事項:

  • 最大 4 人までをセグメント化します
  • 4 人を超える場合、人物を見落としたり、複数の人物をまとめたりすることがあります(通常は背景にいる人物)
  • 混雑したシーンに対応する必要がある場合は、VNDetectFaceRectanglesRequestを使って顔の数を数えます

手のポーズ検出

VNDetectHumanHandPoseRequest

利用可能な環境:iOS 14 以降、macOS 11 以降

手ごとに21 個の手のランドマークを検出します:

let request = VNDetectHumanHandPoseRequest()
request.maximumHandCount = 2  // Default: 2, increase if needed

let handler = VNImageRequestHandler(cgImage: image)
try handler.perform([request])

for observation in request.results as? [VNHumanHandPoseObservation] ?? [] {
    // Process each hand
}

パフォーマンスに関する注意:maximumHandCountはレイテンシーに影響します。ポーズが計算されるのは、手の数が最大値以下の場合のみです。許容できる範囲で最も小さい値を設定してください。

手のランドマーク(21 点)

手首:1 個のランドマーク

親指(4 個のランドマーク):

  • .thumbTip
  • .thumbIP(指節間関節)
  • .thumbMP(中手指節関節)
  • .thumbCMC(手根中手関節)

指(各 4 個のランドマーク):

  • 先端(.indexTip、.middleTip、.ringTip、.littleTip)
  • DIP(遠位指節間関節)
  • PIP(近位指節間関節)
  • MCP(中手指節関節)
グループキー

ランドマークのグループにアクセスします:

グループキー点
.allすべての 21 個のランドマーク
.thumb親指の関節 4 個
.indexFinger人差し指の関節 4 個
.middleFinger中指の関節 4 個
.ringFinger薬指の関節 4 個
.littleFinger小指の関節 4 個
// Get all points
let allPoints = try observation.recognizedPoints(.all)

// Get index finger points only
let indexPoints = try observation.recognizedPoints(.indexFinger)

// Get specific point
let thumbTip = try observation.recognizedPoint(.thumbTip)
let indexTip = try observation.recognizedPoint(.indexTip)

// Check confidence
guard thumbTip.confidence > 0.5 else { return }

// Access location (normalized coordinates, lower-left origin)
let location = thumbTip.location  // CGPoint
ジェスチャー認識の例(ピンチ)
let thumbTip = try observation.recognizedPoint(.thumbTip)
let indexTip = try observation.recognizedPoint(.indexTip)

guard thumbTip.confidence > 0.5, indexTip.confidence > 0.5 else {
    return
}

let distance = hypot(
    thumbTip.location.x - indexTip.location.x,
    thumbTip.location.y - indexTip.location.y
)

let isPinching = distance < 0.05  // Normalized threshold
利き手(左右)
let chirality = observation.chirality  // .left or .right or .unknown

身体のポーズ検出

VNDetectHumanBodyPoseRequest(2D)

利用可能な環境:iOS 14 以降、macOS 11 以降

18 個の身体ランドマーク(正規化された 2D 座標)を検出します:

let request = VNDetectHumanBodyPoseRequest()
try handler.perform([request])

for observation in request.results as? [VNHumanBodyPoseObservation] ?? [] {
    // Process each person
}
身体のランドマーク(18 点)

顔(5 個のランドマーク):

  • .nose、.leftEye、.rightEye、.leftEar、.rightEar

腕(6 個のランドマーク):

  • 左:.leftShoulder、.leftElbow、.leftWrist
  • 右:.rightShoulder、.rightElbow、.rightWrist

胴体(7 個のランドマーク):

  • .neck(肩の間)
  • .leftShoulder、.rightShoulder(腕のグループにも含まれます)
  • .leftHip、.rightHip
  • .root(腰の間)

脚(6 個のランドマーク):

  • 左:.leftHip、.leftKnee、.leftAnkle
  • 右:.rightHip、.rightKnee、.rightAnkle

注意:肩と腰は複数のグループに含まれます

グループキー(身体)
グループキーポイント
.all18 個すべてのランドマーク
.face顔の 5 個のランドマーク
.leftArm肩、肘、手首
.rightArm肩、肘、手首
.torso首、肩、腰、ルート
.leftLeg股関節、膝、足首
.rightLeg股関節、膝、足首
// Get all body points
let allPoints = try observation.recognizedPoints(.all)

// Get left arm only
let leftArmPoints = try observation.recognizedPoints(.leftArm)

// Get specific joint
let leftWrist = try observation.recognizedPoint(.leftWrist)
VNDetectHumanBodyPose3DRequest(3D)

利用可能環境:iOS 17 以降、macOS 14 以降

メートル単位の**3D 骨格(17 個の関節)**を返します(実世界の座標):

let request = VNDetectHumanBodyPose3DRequest()
try handler.perform([request])

guard let observation = request.results?.first as? VNHumanBodyPose3DObservation else {
    return
}

// Get 3D joint position
let leftWrist = try observation.recognizedPoint(.leftWrist)
let position = leftWrist.position  // simd_float4x4 matrix
let localPosition = leftWrist.localPosition  // Relative to parent joint

3D 身体ランドマーク(17 個のポイント):耳がない点を除き、2D と同じです(2D のランドマークは 18 個、3D は 15 個)

3D 観測プロパティ

bodyHeight:メートル単位の推定身長

  • 深度データがある場合:測定された身長
  • 深度データがない場合:基準身長(1.8m)

heightEstimation:.measured または .reference

cameraOriginMatrix:被写体に対するカメラの位置/向きを示す simd_float4x4

pointInImage(_:):3D 関節を 2D 画像座標に投影します

let wrist2D = try observation.pointInImage(leftWrist)
3D ポイントクラス

VNPoint3D:simd_float4x4 の位置行列を持つ基底クラス

VNRecognizedPoint3D:識別子(関節名)を追加します

VNHumanBodyRecognizedPoint3D:localPosition と parentJoint を追加します

// Position relative to skeleton root (center of hip)
let modelPosition = leftWrist.position

// Position relative to parent joint (left elbow)
let relativePosition = leftWrist.localPosition
深度入力

Vision は画像とともに深度データを受け付けます:

// From AVDepthData
let handler = VNImageRequestHandler(
    cvPixelBuffer: imageBuffer,
    depthData: depthData,
    orientation: orientation
)

// From file (automatic depth extraction)
let handler = VNImageRequestHandler(url: imageURL)  // Depth auto-fetched

深度形式:視差または深度(AVFoundation を介して相互に切り替え可能)

LiDAR:正確なスケール/測定には、ライブキャプチャセッションで使用します

顔検出とランドマーク

VNDetectFaceRectanglesRequest

利用可能環境:iOS 11 以降

顔のバウンディングボックスを検出します:

let request = VNDetectFaceRectanglesRequest()
try handler.perform([request])

for observation in request.results as? [VNFaceObservation] ?? [] {
    let faceBounds = observation.boundingBox  // Normalized rect
}
VNDetectFaceLandmarksRequest

利用可能環境:iOS 11 以降

詳細なランドマークを持つ顔を検出します:

let request = VNDetectFaceLandmarksRequest()
try handler.perform([request])

for observation in request.results as? [VNFaceObservation] ?? [] {
    if let landmarks = observation.landmarks {
        let leftEye = landmarks.leftEye
        let nose = landmarks.nose
        let leftPupil = landmarks.leftPupil  // Revision 2+
    }
}

リビジョン:

  • リビジョン 1:基本的なランドマーク
  • リビジョン 2:上下逆さまの顔を検出
  • リビジョン 3 以降:瞳孔の位置

人物検出

VNDetectHumanRectanglesRequest

利用可能環境:iOS 13 以降

人物のバウンディングボックス(胴体の検出)を検出します:

let request = VNDetectHumanRectanglesRequest()
try handler.perform([request])

for observation in request.results as? [VNHumanObservation] ?? [] {
    let humanBounds = observation.boundingBox  // Normalized rect
}

ユースケース:位置の把握だけが必要な場合、ポーズ検出より高速です

CoreImage との統合

CIBlendWithMask フィルター

Vision のマスクを使って、被写体を新しい背景に合成します:

// 1. Get mask from Vision
let observation = request.results?.first as? VNInstanceMaskObservation
let visionMask = try observation.createScaledMask(
    for: observation.allInstances,
    croppedToInstancesContent: false
)

// 2. Convert to CIImage
let maskImage = CIImage(cvPixelBuffer: visionMask)

// 3. Apply filter
let filter = CIFilter(name: "CIBlendWithMask")!
filter.setValue(sourceImage, forKey: kCIInputImageKey)
filter.setValue(maskImage, forKey: kCIInputMaskImageKey)
filter.setValue(newBackground, forKey: kCIInputBackgroundImageKey)

let output = filter.outputImage  // Composited result

パラメーター:

  • 入力画像:マスクを適用する元の画像
  • マスク画像:Vision のソフトセグメンテーションマスク
  • 背景画像:新しい背景(または透明にする場合は空の画像)

HDR の保持:CoreImage は入力のハイダイナミックレンジを保持します(Vision/VisionKit の出力は SDR です)

テキスト認識 API

VNRecognizeTextRequest

利用可能環境:iOS 13 以降、macOS 10.15 以降

精度と速度のトレードオフを設定して、画像内のテキストを認識します。

基本的な使い方
let request = VNRecognizeTextRequest()
request.recognitionLevel = .accurate  // Or .fast
request.recognitionLanguages = ["en-US", "de-DE"]  // Order matters
request.usesLanguageCorrection = true

let handler = VNImageRequestHandler(cgImage: image)
try handler.perform([request])

for observation in request.results as? [VNRecognizedTextObservation] ?? [] {
    // Get top candidates
    let candidates = observation.topCandidates(3)
    let bestText = candidates.first?.string ?? ""
}
認識レベル
レベルパフォーマンス精度最適な用途
.fastリアルタイム良好カメラ映像、大きなテキスト、標識
.accurate低速非常に高い文書、レシート、手書き文字

高速パス:文字単位の認識(ニューラルネットワーク → 文字検出)

高精度パス:行全体の ML 認識(ニューラルネットワーク → 行/単語認識)

プロパティ
プロパティ型説明
recognitionLevelVNRequestTextRecognitionLevel.fast または .accurate
recognitionLanguages[String]BCP 47 言語コード。順序は優先順位を表します
usesLanguageCorrectionBool言語モデルを使って補正するかどうか
customWords[String]ドメイン固有の語彙
automaticallyDetectsLanguageBool言語を自動検出します(iOS 16 以降)
minimumTextHeightFloat画像に対する最小テキスト高さの割合(0〜1)
revisionIntAPI バージョン(サポートされる言語に影響します)
言語サポート
// Check supported languages for current settings
let languages = try VNRecognizeTextRequest.supportedRecognitionLanguages(
    for: .accurate,
    revision: VNRecognizeTextRequestRevision3
)

言語補正:精度が向上しますが、処理時間がかかります。コードやシリアル番号では無効にしてください。

カスタム単語:ドメイン固有の語彙(医療用語、製品コードなど)を追加すると、認識精度が向上します。

VNRecognizedTextObservation

boundingBox: 認識されたテキストを含む正規化された矩形

topCandidates(_:): 信頼度順に並んだ [VNRecognizedText] を返します

VNRecognizedText
プロパティ型説明
stringString認識されたテキスト
confidenceVNConfidence0.0~1.0
boundingBox(for:)VNRectangleObservation?部分文字列の範囲に対応する矩形
// Get bounding box for substring
let text = candidate.string
if let range = text.range(of: "invoice") {
    let box = try candidate.boundingBox(for: range)
}

バーコード検出 API

VNDetectBarcodesRequest

利用可能なバージョン: iOS 11+、macOS 10.13+

バーコードと QR コードを検出してデコードします。

基本的な使い方
let request = VNDetectBarcodesRequest()
request.symbologies = [.qr, .ean13, .code128]  // Specific codes

let handler = VNImageRequestHandler(cgImage: image)
try handler.perform([request])

for barcode in request.results as? [VNBarcodeObservation] ?? [] {
    let payload = barcode.payloadStringValue
    let type = barcode.symbology
    let bounds = barcode.boundingBox
}
シンボロジー

1D バーコード:

  • .codabar (iOS 15+)
  • .code39、.code39Checksum、.code39FullASCII、.code39FullASCIIChecksum
  • .code93、.code93i
  • .code128
  • .ean8、.ean13
  • .gs1DataBar、.gs1DataBarExpanded、.gs1DataBarLimited (iOS 15+)
  • .i2of5、.i2of5Checksum
  • .itf14
  • .upce

2D コード:

  • .aztec
  • .dataMatrix
  • .microPDF417 (iOS 15+)
  • .microQR (iOS 15+)
  • .pdf417
  • .qr

パフォーマンス: 指定するシンボロジーを減らすほど検出が高速になります

リビジョン
リビジョンiOS機能
111+基本的な検出、一度に 1 つのコード
215+Codabar、GS1、MicroPDF、MicroQR、より優れた ROI
316+ML ベース、複数のコード、より優れた境界ボックス
VNBarcodeObservation
プロパティ型説明
payloadStringValueString?デコードされた内容
symbologyVNBarcodeSymbologyバーコードの種類
boundingBoxCGRect正規化された境界
topLeft/topRight/bottomLeft/bottomRightCGPoint四隅の座標

VisionKit スキャナー API

DataScannerViewController

利用可能なバージョン: iOS 16+

テキストとバーコードに対応した、組み込み UI を備えるカメラベースのライブスキャナーです。

利用可否を確認する
// Hardware support
DataScannerViewController.isSupported

// Runtime availability (camera access, parental controls)
DataScannerViewController.isAvailable
設定
import VisionKit

let dataTypes: Set<DataScannerViewController.RecognizedDataType> = [
    .barcode(symbologies: [.qr, .ean13]),
    .text(textContentType: .URL),  // Or nil for all text
    // .text(languages: ["ja"])  // Filter by language
]

let scanner = DataScannerViewController(
    recognizedDataTypes: dataTypes,
    qualityLevel: .balanced,  // .fast, .balanced, .accurate
    recognizesMultipleItems: true,
    isHighFrameRateTrackingEnabled: true,
    isPinchToZoomEnabled: true,
    isGuidanceEnabled: true,
    isHighlightingEnabled: true
)

scanner.delegate = self
present(scanner, animated: true) {
    try? scanner.startScanning()
}
RecognizedDataType
型説明
.barcode(symbologies:)特定のバーコードの種類
.text()すべてのテキスト
.text(languages:)言語でフィルタリングされたテキスト
.text(textContentType:)種類 (URL、電話番号、メール) でフィルタリングされたテキスト
デリゲートプロトコル
protocol DataScannerViewControllerDelegate {
    func dataScanner(_ dataScanner: DataScannerViewController,
                     didTapOn item: RecognizedItem)

    func dataScanner(_ dataScanner: DataScannerViewController,
                     didAdd addedItems: [RecognizedItem],
                     allItems: [RecognizedItem])

    func dataScanner(_ dataScanner: DataScannerViewController,
                     didUpdate updatedItems: [RecognizedItem],
                     allItems: [RecognizedItem])

    func dataScanner(_ dataScanner: DataScannerViewController,
                     didRemove removedItems: [RecognizedItem],
                     allItems: [RecognizedItem])

    func dataScanner(_ dataScanner: DataScannerViewController,
                     becameUnavailableWithError error: DataScannerViewController.ScanningUnavailable)
}
RecognizedItem
enum RecognizedItem {
    case text(RecognizedItem.Text)
    case barcode(RecognizedItem.Barcode)

    var id: UUID { get }
    var bounds: RecognizedItem.Bounds { get }
}

// Text item
struct Text {
    let transcript: String
}

// Barcode item
struct Barcode {
    let payloadStringValue: String?
    let observation: VNBarcodeObservation
}
非同期ストリーム
// Alternative to delegate
for await items in scanner.recognizedItems {
    // Current recognized items
}
カスタムハイライト
// Add custom views over recognized items
scanner.overlayContainerView.addSubview(customHighlight)

// Capture still photo
let photo = try await scanner.capturePhoto()
VNDocumentCameraViewController

利用可能なバージョン: iOS 13+

自動エッジ検出、遠近補正、明るさ調整を備えたドキュメントスキャンです。

基本的な使い方
import VisionKit

let camera = VNDocumentCameraViewController()
camera.delegate = self
present(camera, animated: true)
デリゲートプロトコル
protocol VNDocumentCameraViewControllerDelegate {
    func documentCameraViewController(_ controller: VNDocumentCameraViewController,
                                       didFinishWith scan: VNDocumentCameraScan)

    func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController)

    func documentCameraViewController(_ controller: VNDocumentCameraViewController,
                                       didFailWithError error: Error)
}
VNDocumentCameraScan
プロパティ型説明
pageCountIntスキャンされたページ数
imageOfPage(at:)UIImage指定したインデックスのページ画像を取得します
titleStringユーザーが編集可能なタイトル
func documentCameraViewController(_ controller: VNDocumentCameraViewController,
                                   didFinishWith scan: VNDocumentCameraScan) {
    controller.dismiss(animated: true)

    for i in 0..<scan.pageCount {
        let pageImage = scan.imageOfPage(at: i)
        // Process with VNRecognizeTextRequest
    }
}

ドキュメント解析 API

VNDetectDocumentSegmentationRequest

利用可能なバージョン: iOS 15+、macOS 12+

カスタムカメラ UI や後処理のためにドキュメントの境界を検出します。

let request = VNDetectDocumentSegmentationRequest()
let handler = VNImageRequestHandler(ciImage: image)
try handler.perform([request])

guard let observation = request.results?.first as? VNRectangleObservation else {
    return  // No document found
}

// Get corner points (normalized)
let corners = [
    observation.topLeft,
    observation.topRight,
    observation.bottomLeft,
    observation.bottomRight
]

VNDetectRectanglesRequest との違い:

  • ドキュメント: ML ベースで、ドキュメント専用にトレーニングされています
  • 矩形: エッジベースで、あらゆる四角形を検出します
RecognizeDocumentsRequest (iOS 26+)

利用可能なバージョン: iOS 26+、macOS 26+

セマンティック解析による構造化されたドキュメント理解です。

基本的な使い方
let request = RecognizeDocumentsRequest()
let observations = try await request.perform(on: imageData)

guard let document = observations.first?.document else {
    return
}
DocumentObservation の階層
DocumentObservation
└── document: DocumentObservation.Document
    ├── text: TextObservation
    ├── tables: [Container.Table]
    ├── lists: [Container.List]
    └── barcodes: [Container.Barcode]
テーブルの抽出
for table in document.tables {
    for row in table.rows {
        for cell in row {
            let text = cell.content.text.transcript
            let detectedData = cell.content.text.detectedData
        }
    }
}
検出されるデータ型
for data in document.text.detectedData {
    switch data.match.details {
    case .emailAddress(let email):
        let address = email.emailAddress
    case .phoneNumber(let phone):
        let number = phone.phoneNumber
    case .link(let url):
        let link = url
    case .address(let address):
        let components = address
    case .date(let date):
        let dateValue = date
    default:
        break
    }
}
TextObservation の階層
TextObservation
├── transcript: String
├── lines: [TextObservation.Line]
├── paragraphs: [TextObservation.Paragraph]
├── words: [TextObservation.Word]
└── detectedData: [DetectedDataObservation]

Visual Intelligence 連携

Visual Intelligence は、ユーザーがカメラを現実世界のオブジェクトに向けて、アプリをまたいで一致するコンテンツを見つけられるようにするシステムレベルの機能 (iOS 26+) です。これは上記で扱った Vision フレームワーク (VNRequest ベースの画像解析) とは異なります。Vision はアプリ内で画像を解析しますが、Visual Intelligence はユーザーがカメラやスクリーンショットで検索したときにシステムがアプリを呼び出せるようにします。

仕組み
  1. ユーザーが Visual Intelligence カメラを起動するか、スクリーンショットを撮影します
  2. システムがユーザーの見ているものを分析します
  3. システムが IntentValueQuery を介して参加アプリに問い合わせます
  4. アプリはラベルやピクセルデータを含む SemanticContentDescriptor を受け取ります
  5. アプリがコンテンツを検索し、一致する AppEntity の結果を返します
  6. 結果はアプリのブランド表示とともに Visual Intelligence の UI に表示されます
必須フレームワーク
import VisualIntelligence
import AppIntents
SemanticContentDescriptor

システムがユーザーの見ているものを説明するために提供する中核オブジェクトです。

プロパティ型説明
labels[String]検出された項目の分類ラベル
pixelBufferCVReadOnlyPixelBuffer?検出された項目の視覚データ

ラベルを使用すると、コンテンツカタログ内のキーワードとすばやく照合できます。ラベルでは不十分な場合は、ピクセルバッファを画像類似性検索に使用します。

IntentValueQuery

Visual Intelligence がアプリと通信するためのエントリーポイントです。values(for:) を実装して検索リクエストを受け取り、一致するエンティティを返します。

struct LandmarkIntentValueQuery: IntentValueQuery {
    @Dependency var modelData: ModelData

    func values(for input: SemanticContentDescriptor) async throws -> [LandmarkEntity] {
        if !input.labels.isEmpty {
            return try await modelData.search(matching: input.labels)
        }
        guard let pixelBuffer = input.pixelBuffer else { return [] }
        return try await modelData.search(matching: pixelBuffer)
    }
}
複数の結果タイプを返す

1 回の検索で異なるエンティティタイプを返せるアプリでは、@UnionValue を使用します。

@UnionValue
enum VisualSearchResult {
    case landmark(LandmarkEntity)
    case collection(CollectionEntity)
}
表示表現

Visual Intelligence は、エンティティの DisplayRepresentation を使用して結果を表示します。各結果にタイトル、サブタイトル、画像を設定してください。

struct LandmarkEntity: AppEntity {
    var id: String
    var name: String
    var location: String

    static var typeDisplayRepresentation: TypeDisplayRepresentation {
        TypeDisplayRepresentation(
            name: LocalizedStringResource("Landmark", table: "AppIntents"),
            numericFormat: "\(placeholder: .int) landmarks"
        )
    }

    var displayRepresentation: DisplayRepresentation {
        DisplayRepresentation(
            title: "\(name)",
            subtitle: "\(location)",
            image: .init(named: thumbnailImageName)
        )
    }
}
結果からのディープリンク

ユーザーが結果をタップしたときに、アプリは関連するコンテンツを開く必要があります。エンティティに appLinkURL を指定してください。

var appLinkURL: URL? {
    URL(string: "yourapp://landmark/\(id)")
}
「その他の結果」インテント

大量の検索結果がある場合は、アプリの完全な検索 UI を開く VisualIntelligenceSearchIntent を用意します。

struct ViewMoreLandmarksIntent: AppIntent, VisualIntelligenceSearchIntent {
    static var title: LocalizedStringResource = "View More Landmarks"

    @Parameter(title: "Semantic Content")
    var semanticContent: SemanticContentDescriptor

    func perform() async throws -> some IntentResult {
        // Open your app's search view with the semantic content
        return .result()
    }
}
ベストプラクティス
  • 結果をすばやく返す — Visual Intelligence では低遅延の応答が求められます。関連性の高い結果を 10~20 件に絞ってください
  • まずラベルを使用する — ラベル照合はピクセルバッファの分析より高速です。ラベルが空、または不十分な場合はピクセルバッファを使用します
  • すべてをローカライズする — 表示表現はシステム UI に表示されます。ユーザーに表示するすべてのテキストに LocalizedStringResource を使用してください
  • 画像を含める — サムネイル付きの結果は Visual Intelligence オーバーレイで見分けやすくなります
テスト
  1. 実機でビルドして実行します
  2. Visual Intelligence カメラを起動するか、関連するコンテンツのスクリーンショットを撮影します
  3. ビジュアル検索を実行し、アプリの結果が表示されることを確認します
  4. 結果をタップし、ディープリンクで正しいコンテンツが開くことを確認します

API クイックリファレンス

被写体のセグメンテーション
APIプラットフォーム目的
VNGenerateForegroundInstanceMaskRequestiOS 17+クラスに依存しない被写体インスタンス
VNGeneratePersonInstanceMaskRequestiOS 17+最大 4 人を個別に検出
VNGeneratePersonSegmentationRequestiOS 15+すべての人物(単一マスク)
ImageAnalysisInteraction (VisionKit)iOS 16+被写体を切り抜くための UI
ポーズ検出
APIプラットフォームランドマーク座標
VNDetectHumanHandPoseRequestiOS 14+手ごとに 21 個2D 正規化座標
VNDetectHumanBodyPoseRequestiOS 14+体の関節 18 個2D 正規化座標
VNDetectHumanBodyPose3DRequestiOS 17+体の関節 17 個3D メートル単位
顔と人物の検出
APIプラットフォーム目的
VNDetectFaceRectanglesRequestiOS 11+顔のバウンディングボックス
VNDetectFaceLandmarksRequestiOS 11+詳細なランドマークを含む顔
VNDetectHumanRectanglesRequestiOS 13+人物の胴体のバウンディングボックス
テキストとバーコード
APIプラットフォーム用途
VNRecognizeTextRequestiOS 13+テキスト認識(OCR)
VNDetectBarcodesRequestiOS 11+バーコード/QR コードの検出
DataScannerViewControlleriOS 16+ライブカメラスキャナー(テキスト+バーコード)
VNDocumentCameraViewControlleriOS 13+パースペクティブ補正付きの書類スキャン
VNDetectDocumentSegmentationRequestiOS 15+プログラムによる書類のエッジ検出
RecognizeDocumentsRequestiOS 26+構造化された書類の抽出
ビジュアルインテリジェンス
APIプラットフォーム用途
SemanticContentDescriptoriOS 26+ユーザーが見ているものを記述します(ラベル+ピクセルバッファ)
IntentValueQueryiOS 26+ビジュアル検索リクエストを受け取るためのエントリーポイント
VisualIntelligenceSearchIntentiOS 26+アプリへの「その他の結果」ディープリンク
オブザベーションの種類
オブザベーション返される内容
VNInstanceMaskObservation前景/人物のインスタンスマスク
VNPixelBufferObservation人物のセグメンテーション(単一マスク)
VNHumanHandPoseObservation手のポーズ
VNHumanBodyPoseObservation身体のポーズ(2D)
VNHumanBodyPose3DObservation身体のポーズ(3D)
VNFaceObservation顔の検出/ランドマーク
VNHumanObservation人物の矩形
VNRecognizedTextObservationテキスト認識
VNBarcodeObservationバーコードの検出
VNRectangleObservation書類のセグメンテーション
DocumentObservation構造化された書類(iOS 26+)

リソース

WWDC: 2019-234, 2021-10041, 2022-10024, 2022-10025, 2025-272, 2023-10176, 2023-111241, 2023-10048, 2020-10653, 2020-10043, 2020-10099

ドキュメント: /vision, /visionkit, /visualintelligence, /visualintelligence/semanticcontentdescriptor, /vision/vnrecognizetextrequest, /vision/vndetectbarcodesrequest

スキル: axiom-vision, axiom-vision-diag

コメント