![]() |
OpenCV 5.0.0
Open Source Computer Vision
|
OpenCV (Open Source Computer Vision Library: http://opencv.org) は、数百種類のコンピュータビジョンアルゴリズムを含むオープンソースライブラリである。本ドキュメントでは、いわゆるOpenCV 2.x APIについて説明する。これは本質的にC++ APIであり、CベースのOpenCV 1.x API(C APIは非推奨であり、OpenCV 2.4リリース以降は「C」コンパイラでテストされていない)とは対照的なものである。
OpenCVはモジュール構造を持っており、パッケージにはいくつかの共有ライブラリまたは静的ライブラリが含まれている。次のモジュールが利用できる:
本ドキュメントの以降の章では、各モジュールの機能について説明する。ただしその前に、ライブラリ全体で広く使われている共通のAPIの概念に必ず慣れておくこと。
OpenCVのすべてのクラスと関数は cv 名前空間に配置されている。したがって、自分のコードからこの機能にアクセスするには、cv:: 指定子または using namespace cv; ディレクティブを使う:
または:
現在または将来のOpenCVの外部名の一部は、STLや他のライブラリと衝突する可能性がある。その場合は、明示的に名前空間指定子を使って名前の衝突を解決する:
OpenCVはすべてのメモリを自動的に処理する。
まず、std::vector、cv::Mat、および関数やメソッドで使用されるその他のデータ構造は、必要なときに内部のメモリバッファを解放するデストラクタを持つ。これは、Matの場合のように、デストラクタが常にバッファを解放するとは限らないことを意味する。デストラクタはデータ共有の可能性を考慮する。デストラクタは、行列データバッファに関連付けられた参照カウンタをデクリメントする。バッファが解放されるのは参照カウンタがゼロに達したとき、つまり他のどの構造も同じバッファを参照していないときに限られる。同様に、Matインスタンスがコピーされるとき、実際のデータはコピーされない。代わりに、同じデータの別の所有者がいることを記憶するために参照カウンタがインクリメントされる。行列データの完全なコピーを作成する cv::Mat::clone メソッドもある。以下の例を参照のこと:
Matやその他の基本構造の使用が簡単であることがわかる。しかし、自動メモリ管理を考慮せずに作成された高水準クラスやユーザー定義データ型についてはどうだろうか。それらのために、OpenCVはC++11のstd::shared_ptrに似た cv::Ptr テンプレートクラスを提供している。そのため、素のポインタを使う代わりに:
次のように書ける:
または:
Ptr<T> は、T型インスタンスへのポインタと、そのポインタに関連付けられた参照カウンタをカプセル化する。詳細は cv::Ptr の説明を参照。
OpenCVはメモリを自動的に解放し、また多くの場合、出力関数引数のメモリも自動的に割り当てる。したがって、関数が1つ以上の入力配列(cv::Mat インスタンス)といくつかの出力配列を持つ場合、出力配列は自動的に割り当てまたは再割り当てされる。出力配列のサイズと型は、入力配列のサイズと型から決定される。必要に応じて、関数は出力配列のプロパティを判断するのに役立つ追加の引数を取る。
例:
ビデオフレームの解像度とビット深度はビデオキャプチャモジュールが把握しているため、配列frameは >> 演算子によって自動的に割り当てられる。配列edgesはcvtColor関数によって自動的に割り当てられる。これは入力配列と同じサイズおよびビット深度を持つ。色変換コード cv::COLOR_BGR2GRAY が渡されており、これはカラーからグレースケールへの変換を意味するため、チャンネル数は1である。frameとedgesは、それ以降のすべてのビデオフレームが同じ解像度を持つため、ループ本体の最初の実行時に一度だけ割り当てられることに注意。もし何らかの方法でビデオ解像度を変更すると、配列は自動的に再割り当てされる。
この技術の鍵となる構成要素は cv::Mat::create メソッドである。このメソッドは、希望する配列のサイズと型を受け取る。配列がすでに指定されたサイズと型を持っている場合、メソッドは何もしない。そうでない場合は、以前に割り当てられたデータがあればそれを解放し(この処理には参照カウンタのデクリメントとゼロとの比較が含まれる)、その後、必要なサイズの新しいバッファを割り当てる。ほとんどの関数は各出力配列に対して cv::Mat::create メソッドを呼び出すため、出力データの自動割り当てが実現される。
このスキームの注目すべき例外として、cv::mixChannels、cv::RNG::fill、およびその他いくつかの関数やメソッドがある。これらは出力配列を割り当てられないため、事前に自分で割り当てておく必要がある。
コンピュータビジョンライブラリとして、OpenCVはしばしばチャンネルあたり8ビットまたは16ビットというコンパクトな形式でエンコードされ、そのため値の範囲が限られた画像ピクセルを多く扱う。さらに、色空間変換、明るさ・コントラスト調整、シャープニング、複雑な補間(バイキュービック、Lanczos)といった画像に対する特定の演算は、利用可能な範囲を超える値を生成しうる。結果の下位8(16)ビットだけを保存すると、視覚的なアーティファクトが生じ、その後の画像解析に影響を及ぼす可能性がある。この問題を解決するために、いわゆる飽和 (saturation) 演算が用いられる。例えば、演算結果 r を8ビット画像に保存するには、0..255の範囲内で最も近い値を求める:
\[I(x,y)= \min ( \max (\textrm{round}(r), 0), 255)\]
同様の規則が8ビット符号付き、16ビット符号付きおよび符号なしの型にも適用される。このセマンティクスはライブラリ全体で使われている。C++コードでは、標準的なC++のキャスト演算に似た cv::saturate_cast<> 関数を使って行われる。上で示した式の実装を以下に示す:
ここで cv::uchar はOpenCVの8ビット符号なし整数型である。最適化されたSIMDコードでは、paddusb、packuswbなどのSSE2命令が使われる。これらはC++コードとまったく同じ動作を実現するのに役立つ。
テンプレートは、非常に強力で効率的かつ安全なデータ構造やアルゴリズムの実装を可能にするC++の優れた機能である。しかし、テンプレートを多用すると、コンパイル時間とコードサイズが劇的に増大する可能性がある。さらに、テンプレートだけを使う場合、インターフェースと実装を分離することが難しくなる。これは基本的なアルゴリズムには問題ないが、1つのアルゴリズムが数千行のコードに及ぶこともあるコンピュータビジョンライブラリには適していない。このため、また、テンプレートをまったく持たないか、限られたテンプレート機能しか持たないPython、Java、Matlabといった他言語向けのバインディング開発を簡素化するためにも、現在のOpenCVの実装は、テンプレートよりも多態性と実行時ディスパッチに基づいている。実行時ディスパッチが遅すぎる箇所(ピクセルアクセス演算子など)、不可能な箇所(汎用の cv::Ptr<> の実装)、あるいは単に非常に不便な箇所(cv::saturate_cast<>())では、現在の実装は小さなテンプレートクラス、メソッド、関数を導入している。現在のOpenCVバージョンのそれ以外の場所では、テンプレートの使用は限定的である。
その結果、ライブラリが扱える基本データ型は限られた固定の集合である。すなわち、配列の要素は次の型のいずれかでなければならない:
これらの基本型に対して、以下の定義が適用される:
マルチチャンネル(nチャンネル)型は、次のオプションを使って指定できる:
#CV_32FC1 == #CV_32F, #CV_32FC2 == #CV_32FC(2) == #CV_MAKETYPE(CV_32F, 2)、および #CV_MAKETYPE(depth, n) == (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT))。これは、型定数がビット深度(最下位のCV_CN_SHIFTビット、現在は5に設定されている)とチャンネル数から1を引いた値(次の log2(CV_CN_MAX) ビット)から構成されることを意味する。例:
より複雑な要素を持つ配列は、OpenCVを使って構築したり処理したりすることはできない。さらに、各関数やメソッドは、可能なすべての配列型の一部しか扱えない。通常、アルゴリズムが複雑になるほど、サポートされる形式の部分集合は小さくなる。このような制限の典型的な例を以下に示す:
各関数がサポートする型の部分集合は実用上の必要性から定められており、将来的にユーザーの要望に応じて拡張される可能性がある。
多くのOpenCV関数は、密な2次元または多次元の数値配列を処理する。通常、このような関数は cv::Mat を引数として取るが、場合によっては std::vector<>(たとえば点集合の場合)や cv::Matx<>(3x3のホモグラフィ行列など)を使う方が便利なこともある。APIに多くの重複が生じるのを避けるため、特別な「プロキシ」クラスが導入されている。基本となる「プロキシ」クラスは cv::InputArray である。これは、関数の入力として読み取り専用の配列を渡すために使用される。InputArrayから派生した cv::OutputArray クラスは、関数の出力配列を指定するために使用される。通常、これらの中間型を気にする必要はない(また、これらの型の変数を明示的に宣言すべきではない)。すべて自動的に動作する。InputArray/OutputArrayの代わりに、常に cv::Mat、std::vector<>、cv::Matx<>、cv::Vec<>、または cv::Scalar を使用できると考えてよい。関数が省略可能な入力配列または出力配列を持ち、それを持っていない、または渡したくない場合は、cv::noArray() を渡す。
OpenCVは致命的なエラーを通知するために例外を使う。入力データが正しい形式で指定された値の範囲に属しているにもかかわらず、何らかの理由でアルゴリズムが成功できない場合(例えば最適化アルゴリズムが収束しなかった場合)は、特別なエラーコード(通常は単なるブール変数)を返す。
例外は cv::Exception クラスまたはその派生クラスのインスタンスとなりうる。さらに、cv::Exception は std::exception の派生クラスである。そのため、他の標準C++ライブラリのコンポーネントを使ってコード内で適切に処理できる。
例外は通常、#CV_Error(errcode, description) マクロ、またはそのprintf風の #CV_Error_(errcode, (printf-spec, printf-args)) 亜種を使うか、あるいは条件をチェックしてそれが満たされない場合に例外をスローする CV_Assert(condition) マクロを使ってスローされる。性能が重要なコードのためには、Debug構成でのみ保持される CV_DbgAssert(condition) がある。自動メモリ管理のおかげで、突然のエラーが発生した場合でも、すべての中間バッファは自動的に解放される。必要に応じて例外をキャッチするために、try文を追加するだけでよい:
現在のOpenCV実装は完全にリエントラント(再入可能)である。すなわち、同じ関数や異なるクラスインスタンスの同じメソッドを異なるスレッドから呼び出せる。また、参照カウント操作にはアーキテクチャ固有のアトミック命令を使用するため、同じMatを異なるスレッドで使用できる。