OpenCV 4.13.0
Open Source Computer Vision
読み込み中...
検索中...
見つかりません
🤖 AIによる機械翻訳(非公式) — これは OpenCV 4.13.0 公式リファレンス(英語)を AI (Claude) で自動翻訳したものです。訳に誤りを含む場合があります。正確な情報は 公式英語版(原文) を参照してください。
高レベル設計の概要

G-APIの高レベル設計概要

G-APIはヘテロジニアスなフレームワークであり、多数のサポートされているバックエンドを用いて画像処理パイプラインをプログラミングするための統一APIを提供する。

鍵となる設計思想は、パイプラインのコード自体をプラットフォーム非依存に保ちつつ、どのカーネルを使うか、どのデバイスを利用するかをグラフのコンパイル(構成)時に追加の引数で指定する点にある。この要件から、次のアーキテクチャが導かれた。

G-API framework architecture

このアーキテクチャには3つのレイヤーがある。

  • APIレイヤー – これは最上位レイヤーであり、G-APIの公開インターフェイス、その構成要素、およびセマンティクスを実装する。ユーザーがG-APIでパイプラインを構築するとき、ユーザーはこのレイヤーと直接やり取りし、ユーザーが操作するエンティティ(cv::GMatcv::GComputation など)はこのレイヤーが提供する。
  • グラフコンパイラレイヤー – これは中間レイヤーであり、ユーザーの計算をグラフへと展開し、それに対して多数の変換(例:最適化)を適用する。このレイヤーは ADE Framework の上に構築されている。
  • バックエンドレイヤー – これは最下位レイヤーであり、多数の Backends を列挙する。上記2つのレイヤーとは対照的に、バックエンドは低レベルのプラットフォーム詳細と密に結合しており、各バックエンドが各プラットフォームに対応する。バックエンドは処理済みグラフ(グラフコンパイラから渡される)を操作し、特定のプラットフォームまたはデバイス向けにこのグラフを最適に実行する。

APIレイヤー

APIレイヤーは、パイプライン(G-APIの用語ではComputation)を定義し使用するときにユーザーがやり取りする部分である。APIレイヤーは、グラフ内で入力、出力、および中間データオブジェクトとして使用できる一連のG-APIの dynamic オブジェクトを定義する。

APIレイヤーは、これらのデータオブジェクトに対して定義される一連のOperation、いわゆるカーネルを指定する。G-APIがデフォルトでどの操作を提供するかについては、G-APIの core および imgproc 名前空間を参照のこと。

G-APIはこれらの操作だけに限定されない。ユーザーは特別なマクロ G_TYPED_KERNEL() を使って独自のカーネルを容易に定義できる。

APIレイヤーは、パイプライン生成時に操作の引数をマーシャリングして格納する役割も担う。前述のG-API dynamicオブジェクトに加えて、操作は任意の引数も受け取れる(詳しくはこちら)ため、APIレイヤーはその値を捕捉し、実行の瞬間まで内部に格納する。

最後に、cv::GComputationcv::GCompiled はAPIレイヤーの残る重要なコンポーネントである。前者は一連のG-API式をオブジェクト(グラフ)としてラップし、後者はグラフの compilation の成果物である(詳しくはこの章を参照)。

グラフコンパイラレイヤー

G-APIの計算はすべて、実行前にコンパイルされる。コンパイル処理は2つの方法でトリガーされる。

  • 暗黙的に、cv::GComputation::apply() が使われたとき。この場合、グラフのコンパイルの後に即座に実行が続く。
  • 明示的に、cv::GComputation::compile() が使われたとき。この場合、cv::GCompiled オブジェクトが返され、これをC++のファンクタとして呼び出せる。

最初の方法は、入力データの形式が事前にわからない場合(例:任意の入力ファイルから来る場合)に推奨される。2番目の方法は、入力データの特性が通常あらかじめ決まっているデプロイ(本番)シナリオで推奨される。

グラフのコンパイル処理はADE Frameworkの上に構築されている。最初に、APIレイヤーが捕捉した式から二部グラフが生成される。このグラフは2種類のノード、すなわち DataOperations を含む。グラフは常にDataノードで始まりDataノードで終わり、その間にOperationsノードが入る。各Operationノードは入力と出力を持ち、その両方ともDataノードである。

初期グラフが生成された後、実際には passes と呼ばれる多数のグラフ変換によって処理される。ADE Frameworkはコンパイラのパス管理エンジンとして機能し、パスはG-API専用に書かれている。

グラフの妥当性をチェックするもの、操作やデータの詳細を精緻化するもの、親和性(affinity)やユーザー指定の領域分け[TBD]に基づいてノードをクラスタ(「Islands」)に編成するものなど、さまざまなパスがある。バックエンドもまた、バックエンド固有のパスをコンパイル処理に注入できる。詳しくは専用の章を参照のこと。

グラフのコンパイルの結果は、クラス cv::GCompiled で表されるコンパイル済みオブジェクトである。明示的・暗黙的のどちらのコンパイル要求(上記参照)であっても、常に新しい cv::GCompiled オブジェクトが生成される。実際のグラフの実行は cv::GCompiled の内部で行われ、グラフのコンパイルに関与したバックエンドによって決定される。

参照
cv::GComputation::apply(), cv::GComputation::compile(), cv::GCompiled

バックエンドレイヤー

上記の図には2つのバックエンド、OpenCVFluid が挙げられている。OpenCV はいわゆる「リファレンスバックエンド」であり、G-APIの操作を従来からのOpenCV関数を用いて実装する。このバックエンドは、使い慣れた開発システム上でのプロトタイピングに有用である。Fluid はCPU上でのキャッシュ効率の良い実行のためのプラグインであり、異なる実行ポリシーを実装し、独自の特別なカーネルで動作する。FluidバックエンドはCPU上で実行する際に、より少ないメモリフットプリントとより良いメモリ局所性を実現できる。

Halide、OpenCLなど、利用可能なバックエンドはほかにもありうる。G-APIはバックエンドを開発するための統一された内部APIを提供しているため、どの愛好者や企業も自由にG-APIを新しいプラットフォームやアクセラレータに拡張できる。OpenCVのインフラの観点では、新しいバックエンドはそれぞれ独立した新しいOpenCVモジュールであり、OpenCVの一部としてビルドされたときにG-APIを拡張する。

グラフの実行

グラフの実行方法は、コンパイルのために選択されたバックエンドによって定義される。実際、各バックエンドは、実行可能(コンパイル済み)オブジェクトが生成されるグラフのコンパイル処理の最終段階で、独自の実行スクリプトを構築する。例えばOpenCVバックエンドでは、このスクリプトは呼び出すべきOpenCV関数をトポロジカルソートした並びにすぎない。Fluidバックエンドでも同様で、各反復で入力の行を処理する Agents をトポロジカルソートしたリストである。

グラフの実行は2つの方法でトリガーされる。

どちらのメソッドもポリモーフィックであり、可変個の引数を取り、妥当性チェックは実行時に行われる。渡されたデータオブジェクトの個数、形状、形式が想定と異なる場合、実行時例外が送出される。G-APIはこれらのチェックをコンパイル時に移すための typed ラッパーも提供している。cv::GComputationT<> を参照のこと。

G-APIのグラフの実行はステートレスであると宣言されている。これは、コンパイル済みファンクタ(cv::GCompiled)が純粋なC++関数のように振る舞い、同じ入力引数の集合に対して同じ結果を返すことを意味する。

どちらの実行メソッドも \(N+M\) 個の引数を取る。ここで \(N\) は入力の数、\(M\) は cv::GComputation が定義されている出力の数である。なお、定義にはG-APIの型(cv::GMat など)が使われるが、実行メソッドは実際のデータを保持するOpenCVの従来からのデータ型(cv::Mat など)を受け取る。引数のマーシャリングの表を参照のこと。

参照
実装の詳細, Kernel API