![]() |
OpenCV 5.0.0
Open Source Computer Vision
|
G-APIはヘテロジニアスなフレームワークであり、多数のサポートされているバックエンドを用いて画像処理パイプラインをプログラミングするための統一APIを提供する。
鍵となる設計思想は、パイプラインのコード自体をプラットフォーム非依存に保ちつつ、どのカーネルを使うか、どのデバイスを利用するかをグラフのコンパイル(構成)時に追加の引数で指定する点にある。この要件から、次のアーキテクチャが導かれた。
このアーキテクチャには3つのレイヤーがある。
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::GComputation と cv::GCompiled はAPIレイヤーの残る重要なコンポーネントである。前者は一連のG-API式をオブジェクト(グラフ)としてラップし、後者はグラフの compilation の成果物である(詳しくはこの章を参照)。
G-APIの計算はすべて、実行前にコンパイルされる。コンパイル処理は2つの方法でトリガーされる。
最初の方法は、入力データの形式が事前にわからない場合(例:任意の入力ファイルから来る場合)に推奨される。2番目の方法は、入力データの特性が通常あらかじめ決まっているデプロイ(本番)シナリオで推奨される。
グラフのコンパイル処理はADE Frameworkの上に構築されている。最初に、APIレイヤーが捕捉した式から二部グラフが生成される。このグラフは2種類のノード、すなわち Data と Operations を含む。グラフは常にDataノードで始まりDataノードで終わり、その間にOperationsノードが入る。各Operationノードは入力と出力を持ち、その両方ともDataノードである。
初期グラフが生成された後、実際には passes と呼ばれる多数のグラフ変換によって処理される。ADE Frameworkはコンパイラのパス管理エンジンとして機能し、パスはG-API専用に書かれている。
グラフの妥当性をチェックするもの、操作やデータの詳細を精緻化するもの、親和性(affinity)やユーザー指定の領域分け[TBD]に基づいてノードをクラスタ(「Islands」)に編成するものなど、さまざまなパスがある。バックエンドもまた、バックエンド固有のパスをコンパイル処理に注入できる。詳しくは専用の章を参照のこと。
グラフのコンパイルの結果は、クラス cv::GCompiled で表されるコンパイル済みオブジェクトである。明示的・暗黙的のどちらのコンパイル要求(上記参照)であっても、常に新しい cv::GCompiled オブジェクトが生成される。実際のグラフの実行は cv::GCompiled の内部で行われ、グラフのコンパイルに関与したバックエンドによって決定される。
上記の図には2つのバックエンド、OpenCV と Fluid が挙げられている。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 など) を受け取ることに注意 – パラメータマーシャリング の表を参照。