View in English

  • メニューを開く メニューを閉じる
  • Apple Developer
検索
検索を終了
  • Apple Developer
  • ニュース
  • 見つける
  • デザイン
  • 開発
  • 配信
  • サポート
  • アカウント
次の内容に検索結果を絞り込む

クイックリンク

5 クイックリンク

ビデオ

メニューを開く メニューを閉じる
  • コレクション
  • トピック
  • すべてのビデオ
  • 利用方法

その他のビデオ

ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。

  • 概要
  • トランスクリプト
  • コード
  • Computer Vision APIの探求

    Core Image、Vision、およびCore MLを組み合わせることで、AppにComputer Vision のインテリジェンスを導入する方法について学びます。機械学習だけにとどまらず、画像や動画の理解を深めましょう。Core ImageおよびVisionにおける新しいAPIを見つけ、新しいしきい値フィルター、輪郭検出(Contour Detection)、フレーム間予測(Optical Flow)などのAppにComputer Visionを取り入れます。また、Core Imageを使用して、これらの結果の前処理と可視化を行う方法を検討します。 基盤となるフレームワークについては、"Vision Framework: Building on Core ML" および "Core Image: Performance, Prototyping, and Python" を参照してください。Computer Vision APIについてさらに詳しく知るには、"Detect Body and Hand Pose with Vision" および "Explore the Action & Vision app"セッションも必ずチェックしてください。

    リソース

    • Vision
      • HDビデオ
      • SDビデオ

    関連ビデオ

    WWDC21

    • Visionによるドキュメントデータの抽出

    WWDC20

    • Action & Vision Appの探求
    • Visionで身体や手のポーズを検出する

    WWDC19

    • Understanding Images in Vision Framework
    • Visionフレームワークでのテキスト認識
  • ダウンロード

    こんにちは WWDCへようこそ

    “Computer Vision APIの探求” WWDCへようこそ 私フランク・ドープケと 同僚のデイビッド・ヘイワードが 今日はコンピュータビジョンAPIに関して ご説明します

    実はコンピュータビジョンは アプリケーションを強化することができます またビジネスの中心でない場合でも コンピュータビジョンは実際に アプリケーションに新しいものをもたらします

    例を挙げてみましょう

    銀行アプリケーションでは 小切手を入金することができます 小切手を実際に読み取るために カメラのコンピュータビジョンを使用すると もはや情報を入力する必要はありません コンピュータビジョンが 銀行業界の中心にないことは明らかです しかし コンピュータビジョンを使用することで ユーザーは多くの手順を省けます ユーザーは もはや 何も入力する必要はありません

    他にも例えば QRコードを読み取る場合や 領収書を読み取る場合があります これは アプリケーションで 必ず実行したいことではないかもしれませんが カメラを使用することにより ユーザーにとって非常に簡単になります それでは コンピュータビジョンで 利用できるAPIは何でしょうか

    最上位レベルには VisionKitがあります これは実際にドキュメントをスキャンするために メモ メッセージまたはメールで確認した― VNDocumentCameraのホームです 次に Core Imageを使用して 実際に画像処理を行い Visionを使用して画像を分析し 最後に Core MLを使って機械学習の推論を行います 本日は Core ImageとVisionに焦点を当てます これらのAPIは ただ並んで立っている 柱のようなものではなく 実際にはうまく結びついています 画像の前処理を行い それをVisionに実行して結果を取得し その結果をCore MLに入力したり Core Imageに戻って エフェクトを作成したりすることができます Core Imageを使ってコンピュータビジョンの 画像を前処理する方法については 同僚のデイビッド・ヘイワードがご説明します

    ありがとう この機会に Core Imageを使用して コンピュータビジョンアルゴリズムを 向上させる方法をご説明します

    Core ImageはMetal上に構築され 最適化された使いやすい 画像処理フレームワークです 詳細については このテーマに関する WWDC 2017のプレゼンをご覧ください

    アプリケーションがVisionと共にCore Imageを 使用するべき主な理由は2つあります

    Core Imageを使用して Visionへの入力を前処理することで アルゴリズムをより速く より堅牢にすることができます

    Core Imageを使用して Visionからの出力を後処理することで これらの結果をユーザーに表示する 新しい方法をアプリケーションに提供できます

    また Core Imageは 機械学習トレーニングを増やす優れたツールです 2018年のWWDCのプレゼンテーションでは このすばらしい例をいくつか紹介しています

    分析用に画像を処理する最良の方法の1つは 最高のパフォーマンスを得るために 画像を縮小することです 総合的に最高の品質を持つスケーラーは CILanczosScaleです

    このフィルタは コード内で非常に簡単に使用できます まずは CIFilterBuiltinsヘッダーを インポートします その後 フィルタインスタンスを作成し 入力プロパティを設定して outputImageを取得するだけです

    しかし これはCore Imageのいくつかの リサンプリングフィルタの1つにすぎません アルゴリズムによっては 線形補間CIAffineTransformを 使用する方がよい場合があります

    モルフォロジー演算は 画像内の小さな特徴を より目立たせるための優れた手法です

    CIMorphologyRectangleMaximumを使用して ダイレートを実行すると 画像の明るい領域が大きくなります

    CIMorphologyRectangleMinimumを使用して エロードを実行すると 明るい領域が小さくなります

    さらによいのは CIMorphologyRectangleMinimumに続いて CIMorphologyRectangleMaximumを使用して Closeを実行することです これは アルゴリズムに 影響を与える可能性のある小さなノイズ領域を 画像から削除する場合に非常に便利です

    一部のアルゴリズムでは モノクロ入力のみが必要です この場合 Visionは 自動的にRGBをグレースケールに変換します 入力画像に関するドメインの知識がある場合は Core Imageを使用してグレーに変換すると よりよい結果が得られる可能性があります

    CIColorMatrixを使用すると この変換に必要な任意の重みを指定できます

    または CIMaximumComponentを使用すると 最大信号のチャネルが使用できます

    画像解析前のノイズ低減も 考慮する必要があります

    CIMedianFilterを2回通すと エッジを 柔らかくすることなくノイズを低減できます

    CIGaussianBlurおよびCIBoxBlurも ノイズを低減するための高速な方法です

    また CINoiseReductionフィルタの使用も 検討してください

    Core Imageには さまざまなエッジ検出フィルタもあります

    Sobelエッジ検出では CIConvolution3X3を使用できます

    さらに優れているのは CIGaborGradientsを使用することです これにより ノイズに対する耐性が高い 2Dグラデーションベクトルが生成されます

    画像のコントラストを強調すると オブジェクトの検出に役立ちます

    CIColorPolynomialでは 任意の3次コントラスト関数を指定できます CIColorControlsは 線形コントラストパラメータを提供します

    今年は Core Imageには画像を白黒に変換できる 新しいフィルタもいくつか用意されています

    例えば CIColorThresholdを使用すると アプリケーションコードで しきい値を設定できます CIColorThresholdOtsuは 画像のヒストグラムに基づいて 最適な“しきい値”を自動的に決定します

    Core Imageには2つの画像を 比較するためのフィルタもあります このフィルタは ビデオのフレーム間の動きを 検出するための処理に役立ちます

    例えば CIColorAbsoluteDifferenceは この問題を解決するための 今年の新しいフィルタです

    また 人間の色に対する知覚に合わせて 設計された数式を使用して CILabDeltaEは2つの画像を比較します

    これらは Core Imageに組み込まれている― 200以上のフィルタのうちの 単なるサンプリングです

    これらの組み込みフィルタを 使用しやすくするために このドキュメントには パラメータの説明 サンプル画像 そしてサンプルコードが含まれています

    これらのフィルタがニーズに合わない場合は CoreImage Metalを使用して 簡単に独自のフィルタを作成できます そして 今年も利用可能にしたセッションを ご覧になることをお勧めします

    画像処理とコンピュータビジョンにより 画像をさまざまなカラースペースに入れることが 可能だという点に注意してください

    アプリケーションは― 従来のsRGBからワイドガモットP3 さらに現在対応しているHDRカラースペースまで さまざまなスペースで 画像を受け取る可能性があります

    アプリケーションは こうした多様なカラースペースに 対応できるように準備しておく必要があり Core Imageを使用すると この作業が非常に簡単になります Core Imageは自動的に入力を機能している スペースに変換します 非クランプ リニア Bt.709プライマリなどです

    ただし アルゴリズムでは別のカラースペースの 画像が必要になる場合があります その場合は次の操作を実行する必要があります CGColorSpaceから 使用したいカラースペースの変数を取得します そして image.matchedFromWorkingSpaceを 呼び出します

    スペースにアルゴリズムを適用してから image.matchedToWorkingSpaceを呼び出します 行うべき作業は これだけです

    最後に Core Imageを使用してVisionからの 出力を後処理する方法をご紹介します この1つの例では Core Imageを使用して Visionバーコード認識から バーコード画像を再生成します

    コード内で必要なのは フィルタインスタンスを作成し barcodeDescriptorプロパティを Visionの認識プロパティに設定して 最後に出力画像を取得するだけです 結果はこのようになります

    同様にアプリケーションでは Visionの 顔認識に基づいてフィルタを適用できます

    例えば この機能を使用すると ビネット効果を非常に簡単に使用できます

    コードは実際には非常に単純です 意識する必要があることは Visionの正規化座標系から Core Imageの デカルト座標系に変換することだけです

    ビネットフィルタを作成したら 合成を使用して そのビネットを画像の上に配置できます

    Core Imageを使用して ベクトルフィールドを使用することもできます このベクトルフィールドについては フランクが後ほど説明します

    私からは以上です この後 フランクがVisionについてご説明します

    ありがとう デイビッド ここでは Visionを使用して画像を 理解する方法について説明します

    タスク 装置 結果がありますね タスクはあなたがしたいことで 装置は実際に作業をするものです そして 結果とはあなたが手に入れたいものです

    タスクはコンパイラである VNRequestsの中にあります VNDetectFaceRectanglesRequestと同様です 装置は2つのうちの1つです VNImageRequestHandlerまたは VNSequenceRequestHandlerがあります そして手に入れる結果は VNObservationと呼ばれています 結果は 検出された長方形の VNRectangleObservationなど 実行したタスクによって異なります

    まず VNImageRequestHandlerに対して リクエストを実行します そこから認識を取得します 具体的な例を見てみましょう

    テキストを読みたいので VNRecognizeTextRequestを使用します

    次に 画像を伴う VNImageRequestHandlerを作成します

    その中で ただのプレーンテキストである 認識を取得します

    それでは 2020年のVisionには 新しく何があるのでしょうか

    まず 手と体の姿勢を使用します 詳細については“Hand and Body Pose” セッションを参照してください

    次に 軌跡検出を見たことがあると思います 詳細は “Exploring the Action and Vision Application”で参照してください

    今日は輪郭検出と オプティカルフローに焦点を当てます

    輪郭検出を使用すると 画像内のエッジを検出できます

    ご覧のように 赤い線は この図で見つけた輪郭を示しています

    まず画像を用意し 次にVNDetectContourRequestを作成します

    画像のコントラストを設定して コントラストの一部がどのように 出てくるかなどを強調できます この明るい背景を使用するか 暗い背景で 実行するかどうかを切り替えることができます これにより 前景と背景が 分離される可能性があります 最後に 最大の画像寸法を挿入して パフォーマンスと精度を比較できます

    例えば― 低い解像度で見た場合でも 輪郭は得られますが ぴったりとエッジをなぞらない可能性があります しかし 低い解像度で実行できるため はるかに高速に実行されます それとは対照的に 後処理で 実行する可能性がある高い解像度を使用すると より正確な輪郭が得られますが より多くの作業を行う必要があるため 少し時間がかかります

    それでは 手に入れる認識を見てみましょう

    ここでは 円が描かれた2つの正方形の 非常に単純な画像を表示します

    VNContoursObservationを再び取得しています

    topLevelContoursでは 2つの長方形が確認できます

    それらの中にある子輪郭は 多重化された円です

    次に 実際にすべての輪郭を確認するために 使用できるcontourCountを取得します しかし 例えばインデックスパスを使用する方が はるかに簡単です ご覧のように これらは互いに多重化されており 図を横断できます

    最後にnormalizedPathも取得します これは レンダリングに簡単に使用できる CGPathです

    VNContourとは何でしょうか この例では VNContourを取得しており 親である最も外側の輪郭です その内側には 子輪郭が多重化されており これらは内側の輪郭です

    輪郭にはインデックスパスがあります もちろん すべての子輪郭にも インデックスパスがあり これを再度使用して図を横断できます

    次に pointCountで normalizedPointsを取得します normalizedPointsは実際に輪郭の基本であるのは 発見した各線を描写しているからです ピクセルを検出するだけでなく パスである輪郭を取得します

    アスペクト比については 次のスライドでご説明します

    次に レンダリングする normalizedPathを指定します 輪郭を操作する場合は いくつかの点に注意する必要があります ここにある画像を見てみましょう

    この画像は1920×1080ピクセルで 中央に円があります 円の高さと幅はちょうど1080ピクセルです ただし Visionでは 正規化された座標空間を使用します そのため画像の高さは1.0 幅は1.0です したがって 円の高さは1.0になります しかし幅は0.5625です そのため検出した形状の寸法を 考慮する場合は 計算された元の画像のアスペクト比を 確認する必要があります

    ここで輪郭を解析すると 非常に興味深いものになります またそのためのユーティリティも いくつか用意されています

    VNGeometryUtilsはAPIを提供します 例えば検出した輪郭を完全にカプセル化する 最小の円であるboundingCircleがあります これは輪郭を 相互に比較するのに最適です

    次に面積を計算します そして境界も計算します 輪郭を使用して次にできることは 実際には単純化されています 画像から輪郭を取得すると ノイズが発生する傾向があります ここで例を見てみましょう

    撮影した長方形があります しかし そこには小さなねじれがあり 実際には輪郭はこれらに沿っています そのため角だけにすべてのポイントが あるわけではなく 真ん中などにもあります

    Epsilonを使用して ポリゴンの近似を使用できるようになりました Epsilonのおかげでエッジの周囲にある 小さなノイズ部分をすべて除去でき 強力な輪郭エッジのみが 実際に維持されます

    ここで完璧な長方形が表示されます 4つのポイントだけです 図形を分析する必要がある場合は 非常に簡単です 単純に“4点あれば四角形だ”と言えば どんな形をしているのかを検出しました

    ではこれらの使い方を 具体的な例で見てみましょう

    例えばパンチカードで作成された 非常に古いコンピュータコードを復活させて 世界を救うとします

    パンチカードリーダーがないため パンチカードのくぼみを識別する必要があります

    そこで識別方法について説明している コンピュータビジョンのブログを見つけます しかしPythonで書かれています もちろんプラットフォームに ネイティブに取り込むことで 最善の方法で実行できるようにします

    Pythonコードのセクションができました 理解できなくても すぐに説明しますので 安心してください コンセプトは常に同じで まず画像処理を行います

    次に画像分析を行い

    視覚化する必要がある結果を取得します Pythonを理解していない場合でも 確認するのは最初の3行だけなのです 実際にはいくつかのライブラリを インポートする必要があります Pythonには付属しておらず 実際に含む必要がある サードパーティ製ライブラリです

    ではネイティブで行うには?

    画像処理部分の場合は 画像をロードする必要があります ご存知の通りCGImageSourceを使用して UIImageを取得しCIImageにロードし 名前を付けます 次にCore Imageを使用して CIFiltersにより画像を処理する方法があります CIAbsoluteThresholdまたは 他の多くの場合と同様です

    ここで画像分析を行います そのためには処理したCIImageから VNImageRequestHandlerを作成します 次にVNDetectContourRequestのような リクエストを実行します 画像を前処理する必要さえない かもしれないところが利点です

    そして結果を視覚化する場合も Core Imageを使用してこれを行うことができ 実際に持っている画像の上に 同じコンテキストで直接合成できます CIMeshGeneratorまたは CITextGeneratorを使用できます

    CoreGraphicsまたはUIKitを使用して 画像の上のレイヤに レンダリングすることもできます

    では すべてのスライドの後に 実際のデモを見てみましょう

    ここに活動領域を準備しました 画像をロードしたことが確認できます

    contourRequestを作成し

    そして ただ実行します ご覧ください 求めていたくぼみを含め すべての輪郭が表示されます 387個の輪郭が見つかりましたね 望んだ数よりも少し多いかもしれません そのためこれらの輪郭をすべて 除外する必要があります 少し準備をして ここに隠しておいたコードがあります 一部を明らかにしましょう このコードでは― 実際には輪郭が青色の背景であるという ドメインの知識を使用します CIFilteringを使用して 最初にすべてのノイズをぼかします

    次にカラーコントロールを使用して コントラストを出します その後フィルタ処理された画像を使用して 輪郭検出を実行します ここでは最初に気にしていた 32個の輪郭だけが検出されます

    それではスライドに戻りましょう

    通常はデモで何をしたかを 説明しますが 実際には何をする必要がなかったかが より重要です

    これはすべてOSの一部であるため サードパーティのパッケージを ロードしませんでした 私が使ったのはUIKitとCore Image そしてVisionだけです

    パイプラインにいたので 最適な処理パスを使用することにより 画像パイプラインを離れませんでした

    画像をマトリックスに変換しませんでした メモリをすべて節約し 計算コストも大幅に削減しました

    これが輪郭検出です 次にオプティカルフローに進みましょう オプティカルフローとは何でしょう?

    2つのフレーム間の移動を解析したい時

    従来はレジストレーションを使用していました それはかなり長い間Visionの一部でした 画像全体の位置合わせを行います ここで例を見てみましょう

    この2つの点をカメラの画像として捉えてから カメラを移動してみましょう

    2つの点が右上に移動しました

    レジストレーションにより 画像がどの程度右上へ移動したかを示すことで 2つの画像間の位置合わせを 行うことができます

    もう一方のオプティカルフローは 異なります 今年のVisionの新機能で XとYの間のピクセルごとのフローが得られます

    この例でも2つの点があります

    しかし移動して離れました

    そのため画像レジストレーションでは この画像が正しく取得されません しかしオプティカルフローを使用すれば 各ピクセルがどのように移動したかが分かります オプティカルフローの結果を 見てみましょう

    オプティカルフローから VNPixelBufferObservationを取得します これは浮動小数点画像です XとYの移動が交互に配置されています

    このようなビデオがある場合 これらの値を単独で見ているだけでは 起こっていることを視覚化するのは困難でしょう それは後のアルゴリズムでの処理を 目的としているだけだからです しかしチェックアウトしたい場合は 実際にCore Imageを使用して 結果を視覚化できます デイビッドがセッションの前半に 取り組んでいたようにこれを行う方法があります 小さなカスタムカーネルを作成しました これで すべての移動を確認できます 移動の強さを示すカラーコーディングがあり 小さな三角形が実際に移動の方向を示しています

    実行の方法を簡単に説明します カスタムフィルタを作成しました カーネルをロードし スライドの添付ファイルで 利用できるようにします そして基本的には このカーネルを 必要な矢印のサイズのパラメータで適用し フィルタとして 実行することだけです そしてVisionコードでVNGenerateOpticalFlow リクエストを実行するだけです 認識をpixelBufferに入力し これをCIImageにラップすることができます その後それをフィルタに入力して 出力画像を取得します

    それでは 本日お話しした内容を まとめましょう

    コンピュータビジョンは難しくある必要はなく アプリケーションを強化します 当社のネイティブAPIを使用すると 迅速かつ簡単に導入できます これらの機能を組み合わせることで 興味深いものを作ることができます

    皆さんのすばらしいアプリケーションと 大きな革新を楽しみにしています セッションにご参加いただき ありがとうございます 残りのWWDCもお楽しみください

    • 19:24 - Reading punchcards playgrounds

      import UIKit
      import CoreImage
      import CoreImage.CIFilterBuiltins
      import Vision
      
      
      public func drawContours(contoursObservation: VNContoursObservation, sourceImage: CGImage) -> UIImage {
      	let size = CGSize(width: sourceImage.width, height: sourceImage.height)
      	let renderer = UIGraphicsImageRenderer(size: size)
      	
      	let renderedImage = renderer.image { (context) in 
      		
      		let renderingContext = context.cgContext
      		
          // flip the context
          let flipVertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: size.height)
          renderingContext.concatenate(flipVertical)
              
      		// draw the original image
      		renderingContext.draw(sourceImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
      		
      		renderingContext.scaleBy(x: size.width, y: size.height)
      		renderingContext.setLineWidth(3.0 / CGFloat(size.width))
      		let redUIColor = UIColor.red
      		renderingContext.setStrokeColor(redUIColor.cgColor)
      		renderingContext.addPath(contoursObservation.normalizedPath)
      		renderingContext.strokePath()
      	}
      	
      	return renderedImage;
      }
      
      let context = CIContext()
      if let sourceImage = UIImage.init(named: "punchCard.jpg")
      {
      	var inputImage = CIImage.init(cgImage: sourceImage.cgImage!)
      	
      	let contourRequest = VNDetectContoursRequest.init()
          
      // Uncomment the follwing section to preprocess the image
      //	do {
      //			let noiseReductionFilter = CIFilter.gaussianBlur()
      //			noiseReductionFilter.radius = 1.5
      //			noiseReductionFilter.inputImage = inputImage
      //
      //			let monochromeFilter = CIFilter.colorControls()
      //			monochromeFilter.inputImage = noiseReductionFilter.outputImage!
      //			monochromeFilter.contrast = 20.0
      //			monochromeFilter.brightness = 8
      //			monochromeFilter.saturation = 50
      //
      //			let filteredImage = monochromeFilter.outputImage!
      //
      //			inputImage = filteredImage
      //		}
      	
      	let requestHandler = VNImageRequestHandler.init(ciImage: inputImage, options: [:])
      
      	try requestHandler.perform([contourRequest])
      	let contoursObservation = contourRequest.results?.first as! VNContoursObservation
      	print(contoursObservation.contourCount)
      	_ = drawContours(contoursObservation: contoursObservation, sourceImage: sourceImage.cgImage!)
      } else {
      	print("could not load image")
      }
    • 23:05 - Optical Flow Visualizer (CI kernel)

      //
      //  OpticalFlowVisualizer.cikernel
      //  SampleVideoCompositionWithCIFilter
      //
      
      
      kernel vec4 flowView2(sampler image, float minLen, float maxLen, float size, float tipAngle)
      {
      	/// Determine the color by calculating the angle from the .xy vector
      	///
      	vec4 s = sample(image, samplerCoord(image));
      	vec2 vector = s.rg - 0.5;
      	float len = length(vector);
      	float H = atan(vector.y,vector.x);
      	// convert hue to a RGB color
      	H *= 3.0/3.1415926; // now range [3,3)
      	float i = floor(H);
      	float f = H-i;
      	float a = f;
      	float d = 1.0 - a;
      	vec4 c;
      		 if (H<-3.0) c = vec4(0, 1, 1, 1);
      	else if (H<-2.0) c = vec4(0, d, 1, 1);
      	else if (H<-1.0) c = vec4(a, 0, 1, 1);
      	else if (H<0.0)  c = vec4(1, 0, d, 1);
      	else if (H<1.0)  c = vec4(1, a, 0, 1);
      	else if (H<2.0)  c = vec4(d, 1, 0, 1);
      	else if (H<3.0)  c = vec4(0, 1, a, 1);
      	else             c = vec4(0, 1, 1, 1);
      	// make the color darker if the .xy vector is shorter
      	c.rgb *= clamp((len-minLen)/(maxLen-minLen), 0.0,1.0);
      	/// Add arrow shapes based on the angle from the .xy vector
      	///
      	float tipAngleRadians = tipAngle * 3.1415/180.0;
      	vec2 dc = destCoord(); // current coordinate
      	vec2 dcm = floor((dc/size)+0.5)*size; // cell center coordinate
      	vec2 delta = dcm - dc; // coordinate relative to center of cell
      	// sample the .xy vector from the center of each cell
      	vec4 sm = sample(image, samplerTransform(image, dcm));
      	vector = sm.rg - 0.5;
      	len = length(vector);
      	H = atan(vector.y,vector.x);
      	float rotx, k, sideOffset, sideAngle;
      	// these are the three sides of the arrow
      	rotx = delta.x*cos(H) - delta.y*sin(H);
      	sideOffset = size*0.5*cos(tipAngleRadians);
      	k = 1.0 - clamp(rotx-sideOffset, 0.0, 1.0);
      	c.rgb *= k;
      	sideAngle = (3.14159 - tipAngleRadians)/2.0;
      	sideOffset = 0.5 * sin(tipAngleRadians / 2.0);
      	rotx = delta.x*cos(H-sideAngle) - delta.y*sin(H-sideAngle);
      	k = clamp(rotx+size*sideOffset, 0.0, 1.0);
      	c.rgb *= k;
      	rotx = delta.x*cos(H+sideAngle) - delta.y*sin(H+sideAngle);
      	k = clamp(rotx+ size*sideOffset, 0.0, 1.0);
      	c.rgb *= k;
      	/// return the color premultiplied
      	c *= s.a;
      	return c;
      }
    • 23:26 - Optical Flow Visualizer (CIFilter code)

      class OpticalFlowVisualizerFilter: CIFilter {
      	var inputImage: CIImage?
      	
      	let callback: CIKernelROICallback = {
      			(index, rect) in
      				return rect
      			}
      	
      	static var kernel: CIKernel = { () -> CIKernel in
      		let url = Bundle.main.url(forResource: "OpticalFlowVisualizer",
      								  withExtension: "ci.metallib")!
      		let data = try! Data(contentsOf: url)
      		
      		return try! CIKernel(functionName: "flowView2",
      								  fromMetalLibraryData: data)
      	}()
      
      	override var outputImage : CIImage? {
      		get {
      			guard let input = inputImage else {return nil}
      			return OpticalFlowVisualizerFilter.kernel.apply(extent: input.extent, roiCallback: callback, arguments: [input, 0.0, 100.0, 10.0, 30.0])
      		}
      	}
      }
    • 23:42 - Optical Flow Visualizer (Vision code)

      var requestHandler = VNSequenceRequestHandler()
                  var previousImage:CIImage?
      			if (self.previousImage == nil) 
      			{
      				self.previousImage = request.sourceImage
      			}
      			let visionRequest = VNGenerateOpticalFlowRequest(targetedCIImage: source, options: [:])
      			
      			do {
      				try self.requestHandler.perform([visionRequest], on: self.previousImage!)
      				if let pixelBufferObservation = visionRequest.results?.first as? VNPixelBufferObservation
      				{
      					source = CIImage(cvImageBuffer: pixelBufferObservation.pixelBuffer)
      				}
      			} catch {
      				print(error)
      			}
      			// store the previous image
      			self.previousImage = request.sourceImage
      			
      			let ciFilter = OpticalFlowVisualizerFilter()
      			ciFilter.inputImage = source
      			let output = ciFilter.outputImage
  • 特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。

    クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。

Developer Footer

  • ビデオ
  • WWDC20
  • Computer Vision APIの探求
  • メニューを開く メニューを閉じる
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    メニューを開く メニューを閉じる
    • アクセシビリティ
    • アクセサリ
    • App Extension
    • App Store
    • オーディオとビデオ(英語)
    • 拡張現実
    • デザイン
    • 配信
    • 教育
    • フォント(英語)
    • ゲーム
    • ヘルスケアとフィットネス
    • アプリ内課金
    • ローカリゼーション
    • マップと位置情報
    • 機械学習
    • オープンソース(英語)
    • セキュリティ
    • SafariとWeb(英語)
    メニューを開く メニューを閉じる
    • 英語ドキュメント(完全版)
    • 日本語ドキュメント(一部トピック)
    • チュートリアル
    • ダウンロード(英語)
    • フォーラム(英語)
    • ビデオ
    Open Menu Close Menu
    • サポートドキュメント
    • お問い合わせ
    • バグ報告
    • システム状況(英語)
    メニューを開く メニューを閉じる
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles(英語)
    • フィードバックアシスタント
    メニューを開く メニューを閉じる
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(英語)
    • News Partner Program(英語)
    • Video Partner Program(英語)
    • セキュリティ報奨金プログラム(英語)
    • Security Research Device Program(英語)
    Open Menu Close Menu
    • Appleに相談
    • Apple Developer Center
    • App Store Awards(英語)
    • Apple Design Awards
    • Apple Developer Academy(英語)
    • WWDC
    Apple Developerアプリを入手する
    Copyright © 2025 Apple Inc. All rights reserved.
    利用規約 プライバシーポリシー 契約とガイドライン