OpenCVの使い方を勉強するために公式ドキュメント(https://docs.opencv.org/3.4.2/d1/dfb/intro.html) を読書した。理解した内容や追加で調べた内容を以下に残す。
1. cv Namespace
All the OpenCV classes and functions are placed into the cv namespace. Therefore, to access this functionality from your code, use the cv:: specifier or using namespace cv; directive:
すべてのOpenCVクラスやメソッドは、cv名前空間に置かれている。したがって、自作コードからOpenCVにアクセスするためには、「cv::」指定子もしくは、usingディレクティブ「using namespace cv;」を使う必要がある。usingディレクティブに関しては、「 http://marycore.jp/prog/cpp/using-directive/ 」 を参照すると勉強になる。
# include "opencv2/core.hpp"
cv::Mat H = cv::findHomography(points1, points2, CV_RANSAC, 5);
「cv::」指定子を使用した例
# include "opencv2/core.hpp"
cv::Mat H = cv::findHomography(points1, points2, CV_RANSAC, 5);
using ディレクティブを使用した例
Some of the current or future OpenCV external names may conflict with STL or other libraries. In this case, use explicit namespace specifiers to resolve the name conflicts:
またOpenCVで使われる外部名は、STLや他のライブラリで使われる外部名と衝突することがある。このような場合は、名前空間を指定子で明示的に示し、解決する。(下記のコード例では cv::、std::、Scalar::を使って名前解決をしている。)
Mat a(100, 100, CV_32F);
randu(a, Scalar::all(1), Scalar::all(std::rand()));
cv::log(a, a);
a /= std::log(2.);
2. Automatic Memory Management(自動メモリ管理)
OpenCV handles all the memory automatically.
First of all, std::vector, Mat, and other data structures used by the functions and methods have destructors that deallocate the underlying memory buffers when needed. This means that the destructors do not always deallocate the buffers as in case of Mat. They take into account possible data sharing. A destructor decrements the reference counter associated with the matrix data buffer. The buffer is deallocated if and only if the reference counter reaches zero, that is, when no other structures refer to the same buffer. Similarly, when a Mat instance is copied, no actual data is really copied. Instead, the reference counter is incremented to memorize that there is another owner of the same data. There is also the Mat::clone method that creates a full copy of the matrix data. See the example below:
OpenCVはすべてのメモリを自動的に管理する。
まずはじめに、std::vector、Mat、などのデータ構造はメモリを開放するデストラクタを持っている。OpenCVで使われるMatのデストラクタは常にメモリを開放するわけではなく、参照されていない場合にのみ開放される。具体的に説明すると、あるデストラクタは、マトリックスデータバッファーの参照カウンタをデクリメントする。この参照カウンタは参照している相手の数を表す。そしてマトリックスバッファは参照カウンタがゼロ(他の相手から参照されていない状態)になったときにのみ開放される。また、Matが代入演算子を用いてコピーされるときは、データ値そのものはコピーされない(浅いコピー)が行われる。そして、参照カウンターをインクリメントし、そのデータには他にも所有者がいることを覚えておく。Mat::cloneメソッドを用いたコピーは、データの単なる参照によるコピーではなく、データ値そのものをコピーする(深いコピー)。
以下に例を示す。
// create a big 8Mb matrix
// 8Mbの巨大な行列Aをつくる。
Mat A(1000, 1000, CV_64F);
// create another header for the same matrix;
// this is an instant operation, regardless of the matrix size.
// 行列Aを参照する行列Bをつくる。
// これはデータ値そのものをコピーするわけではないため、
// 行列サイズにかかわらず、高速な処理である。
// しかし参照であるため、行列Aの値を書き換えると行列Bの値も書き換わる。
Mat B = A;
// create another header for the 3-rd row of A; no data is copied either
// 行列Bの3行目(実体は行列Aの3行目)を参照する行列Cをつくる
Mat C = B.row(3);
// now create a separate copy of the matrix
// 行列B(実体は行列A)のデータ値そのものをコピーした行列Dをつくる
// 参照によるコピーではないため、処理は遅い。
// 行列A、B、Cのいずれを書き換えても、行列Dの値は書き換わらない
Mat D = B.clone();
// copy the 5-th row of B to C, that is, copy the 5-th row of A
// to the 3-rd row of A.
// 行列Bの5行目を行列Cにコピーする。
// これは、すなわち行列Aの5行目を行列Aの3行目にコピーすることになる。
B.row(5).copyTo(C);
// now let A and D share the data; after that the modified version
// of A is still referenced by B and C.
// では、行列Dを行列Aに参照させてみよう。
// 行列B、Cは行列Aを参照し続けるため、行列B、Cも行列Dを参照することになる。
A = D;
// now make B an empty matrix (which references no memory buffers),
// but the modified version of A will still be referenced by C,
// despite that C is just a single row of the original A
// 行列Bをメモリバッファを参照しない空の行列にしてみる。(行列Aを参照させなくする)
// 行列Cは行列Bをコピーしたものであるが、行列Aを参照したままとなる。
B.release();
// finally, make a full copy of C. As a result, the big modified
// matrix will be deallocated, since it is not referenced by anyone
// 最後に行列Cを行列Aの参照をではなく、Aの完全なコピーにする。
//この結果、巨大な行列Aは誰からも参照されなくなり、行列Aのメモリは開放されるようになる。
C = C.clone();
3. Automatic Allocation of the Output Data(出力データの自動メモリ確保)
OpenCV deallocates the memory automatically, as well as automatically allocates the memory for output function parameters most of the time. So, if a function has one or more input arrays (cv::Mat instances) and some output arrays, the output arrays are automatically allocated or reallocated. The size and type of the output arrays are determined from the size and type of input arrays. If needed, the functions take extra parameters that help to figure out the output array properties.
OpenCVはメモリ開放だけではなく、メモリ確保も自動的に行う。もし、ある関数が入力用のMatインスタンスと出力用のMatインスタンスを持っていた場合、出力用のMatは自動的にメモリ確保や、再割当てが行われる。出力用のMatサイズ(行数、列数)や型は、入力されたMatのサイズや型によって自動的に決められるが、明示的に指定することもできる。以下に例を示す。
# include "opencv2/imgproc.hpp"
# include "opencv2/highgui.hpp"
using namespace cv;
int main(int, char**)
{
// VideoCaptureはビデオファイルやカメラデバイスからビデオキャプチャをするために用いる。
// コンストラクタの引数は、カメラデバイスを指定するインデックスである。
// 接続されているカメラが1台の場合は、0を指定する。
VideoCapture cap(0);
// カメラデバイスがオープンできたかを確認する
if(!cap.isOpened()) return -1;
Mat frame, edges;
// ウィンドウを作成する
namedWindow("edges",1);
for(;;)
{
// frameのメモリを確保する
cap >> frame;
// 画像の色空間を変換する
// 第1引数:入力画像、第2引数:出力画像、第3引数:色空間変換コード
cvtColor(frame, edges, COLOR_BGR2GRAY);
// ガウシアンフィルタを用いて平滑化をする
GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);
// Cannyアルゴリズムを用いて,画像のエッジを検出する
Canny(edges, edges, 0, 30, 3);
// 指定したウィンドウ内に画像を表示する
// 第1引数:ウィンドウの名前、第2引数:表示する画像
imshow("edges", edges);
if(waitKey(30) >= 0) break;
}
return 0;
}
The array frame is automatically allocated by the >> operator since the video frame resolution and the bit-depth is known to the video capturing module. The array edges is automatically allocated by the cvtColor function. It has the same size and the bit-depth as the input array. The number of channels is 1 because the color conversion code COLOR_BGR2GRAY is passed, which means a color to grayscale conversion. Note that frame and edges are allocated only once during the first execution of the loop body since all the next video frames have the same resolution. If you somehow change the video resolution, the arrays are automatically reallocated.
VideoCaptureモジュールが解像度や、ビット深度を知っているため、frame行列は、「>>」演算子によって自動的にメモリ確保される。edges行列のメモリは、cvtColor関数によって、自動的に確保される。確保されるサイズ(行数、列数)やビット深度は入力行列であるframeと同じであるが、チャネル数は変換する色空間が_BGR2GRAY (グレースケール)のため1である。frame、edges行列のメモリ確保は、すべてのビデオのフレームが同じ解像度を持つため、ループの初回のみに実行される。また、ビデオの解像度を変更すると、frame、edges行列のメモリに対して再割り当てが行われる。
The key component of this technology is the Mat::create method. It takes the desired array size and type. If the array already has the specified size and type, the method does nothing. Otherwise, it releases the previously allocated data, if any (this part involves decrementing the reference counter and comparing it with zero), and then allocates a new buffer of the required size. Most functions call the Mat::create method for each output array, and so the automatic output data allocation is implemented.
Some notable exceptions from this scheme are cv::mixChannels, cv::RNG::fill, and a few other functions and methods. They are not able to allocate the output array, so you have to do this in advance.
この技術の鍵は、Mat::createメソッドである。このメソッドは引数に、サイズ(行数、列数)と型名をとる。createメソッドを呼ぶMatインスタンスが既に、指定されたサイズや型をもっている場合は、このメソッドは何もしない。もし持っていない場合は、Mat::release() を呼び出して,以前のデータに対して参照外しを行う。そして、指定されたサイズのバッファを新しく確保する。ほとんどの関数がMat::createメソッドを出力する行列に対して、呼び出し、出力行列のメモリを暗黙的に確保する。例外として、cv::mixChannels, cv::RNG::fillや少数のメソッドは、出力行列を暗黙的に確保しないため、注意が必要である。
4. Saturation Arithmetics(飽和演算)
As a computer vision library, OpenCV deals a lot with image pixels that are often encoded in a compact, 8- or 16-bit per channel, form and thus have a limited value range. Furthermore, certain operations on images, like color space conversions, brightness/contrast adjustments, sharpening, complex interpolation (bi-cubic, Lanczos) can produce values out of the available range. If you just store the lowest 8 (16) bits of the result, this results in visual artifacts and may affect a further image analysis. To solve this problem, the so-called saturation arithmetics is used. For example, to store r, the result of an operation, to an 8-bit image, you find the nearest value within the 0..255 range:
I(x,y)=\min_{} ( \max_{} ( round_{} (r), 0), 255 ) -(1)
コンピュータビジョンのライブラリとして、OpenCVでは、8ビットや16ビットに符号化されたピクセル画像を扱うため、画素値の表現に制限がある。さらに言うと、特定の操作(色空間変換、輝度/コントラスト調整、鮮明化、バイキュービックやランチョスによる複素補間)を画像に対して行うと、利用可能な範囲外の値を生成する可能性がある。結果として、8ビット(16ビット)の画素値を格納するだけではなく、視覚的なアーチファクトを作り出し、画像解析に影響を与える可能性がある。この問題を解決するために、飽和演算が使われる。例えば、8ビット画像に対する操作結果としてrを格納するとき、0から255の値の中で、最も近い値が格納される。式(1)はこの際に近傍値を求めるときに使用される。
5. Fixed Pixel Types. Limited Use of Templates(画素値の型には、テンプレートではなく決まった型を使用する)
Templates is a great feature of C++ that enables implementation of very powerful, efficient and yet safe data structures and algorithms. However, the extensive use of templates may dramatically increase compilation time and code size. Besides, it is difficult to separate an interface and implementation when templates are used exclusively. This could be fine for basic algorithms but not good for computer vision libraries where a single algorithm may span thousands lines of code. Because of this and also to simplify development of bindings for other languages, like Python, Java, Matlab that do not have templates at all or have limited template capabilities, the current OpenCV implementation is based on polymorphism and runtime dispatching over templates. In those places where runtime dispatching would be too slow (like pixel access operators), impossible (generic Ptr<> implementation), or just very inconvenient (saturate_cast<>()) the current implementation introduces small template classes, methods, and functions. Anywhere else in the current OpenCV version the use of templates is limited.
Consequently, there is a limited fixed set of primitive data types the library can operate on. That is, array elements should have one of the following types:
・8-bit unsigned integer (uchar)
・8-bit signed integer (schar)
・16-bit unsigned integer (ushort)
・16-bit signed integer (short)
・32-bit signed integer (int)
・32-bit floating-point number (float)
・64-bit floating-point number (double)
・a tuple of several elements where all elements have the same type (one of the above). An array whose elements are such tuples, are called multi-channel arrays, as opposite to the single-channel arrays, whose elements are scalar values. The maximum possible number of channels is defined by the CV_CN_MAX constant, which is currently set to 512.
テンプレートは、効率的に安全なデータ構造とアルゴリズムの実装を可能にするC++の非常に優れた機能である。しかし、テンプレートを広範囲に使用すると、テンプレートはコンパイル時に展開するため、コンパイル時間とコードサイズが大幅に増加する。さらにインターフェースと実装を分けることが難しい。これは、簡単なアルゴリズムであれば、問題にはならないが、1つのアルゴリズムが数千行に及ぶコンピュータビジョンのライブラリには適さない。OpenCVの実装は上記の理由に加え、テンプレートを持たないあるいは使用に制限がある言語(Python, Java, Matlab)とのバインディング開発をより単純にするために、ポリモーフィズムとランタイムディスパッチをベースとしている。例外として、実行時のディスパッチが非常に遅くなる操作(例:ピクセルアクセス)、あるいは非常に不便な場所(例:voidポインタ)に限って、現在の実装では局所的なテンプレートクラスやテンプレート関数を許容している。その他の場所では、テンプレートの使用は制限されている。
したがってMatの要素は、以下に示す言語仕様にある最も基本的なデータ型を使用する必要がある。
・8-bit unsigned integer (uchar)
・8-bit signed integer (schar)
・16-bit unsigned integer (ushort)
・16-bit signed integer (short)
・32-bit signed integer (int)
・32-bit floating-point number (float)
・64-bit floating-point number (double)
・各要素が同じ型(上記の1つ)を持つ複数要素のタプル
(マルチチャネル配列と呼ばれ、最大チャンネル数は512であり、CV_CN_MAX定数によって定義されている)
For these basic types, the following enumeration is applied:
これらの基本型には、以下の列挙型が適用される。
enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 };
Multi-channel (n-channel) types can be specified using the following options:
CV_8UC1 ... CV_64FC4 constants (for a number of channels from 1 to 4)
マルチチャンネル(nチャネル)に対しては、以下のオプションがある。
CV_8UC1 ... CV_64FC4(チャネル数が1から4の定数)
Examples:
// make a 3x3 32bit floating-point matrix
// 3x3の32bitのfloat型の行列をつくる
Mat mtx(3, 3, CV_32F);
// make a 10x1 2-channel 64bit floating-point matrix (10-element complex vector)
// 10x1の2チャンネルの64bitのfloat(double)型の行列をつくる
Mat cmtx(10, 1, CV_64FC2);
// make a 3-channel (color) image of 1920 columns and 1080 rows.
// 1920x1080の3チャネルのカラー画像をつくる
Mat img(Size(1920, 1080), CV_8UC3);
// make a 1-channel image of the same size and same channel type as img
// 行列imgと同じチャネル型、同じサイズ(幅、高さ)の1チャネルの画像をつくる
Mat grayscale(img.size(), CV_MAKETYPE(img.depth(), 1));
Arrays with more complex elements cannot be constructed or processed using OpenCV. Furthermore, each function or method can handle only a subset of all possible array types. Usually, the more complex the algorithm is, the smaller the supported subset of formats is. See below typical examples of such limitations:
The face detection algorithm only works with 8-bit grayscale or color images.
Linear algebra functions and most of the machine learning algorithms work with floating-point arrays only.
Basic functions, such as cv::add, support all types.
Color space conversion functions support 8-bit unsigned, 16-bit unsigned, and 32-bit floating-point types.
The subset of supported types for each function has been defined from practical needs and could be extended in future based on user requests.
上記以外の複雑な要素を持つ行列は、OpenCVを使用して構築または処理することはできない。 さらに、各メソッドは、すべての型の行列をサポートしているわけではない。 アルゴリズムが複雑になればなるほど、サポートされる行列の種類は少なくなる。 このような制限の例を次に示す。
顔検出アルゴリズムは、8ビットグレースケールまたはカラー画像でのみをサポートする。線形代数関数と機械学習アルゴリズムのほとんどは、浮動小数点型の配列でのみをサポートする。cv::addなどの基本関数はすべての型をサポートする。色空間変換関数は、8ビットの符号なし、16ビットの符号なし、および32ビットの浮動小数点型をサポートする。各機能のサポートされている型は、実際のニーズから定義されており、将来ユーザ要求に基づいて拡張ができる。
6. Error Handling(エラーハンドリング)
OpenCV uses exceptions to signal critical errors. When the input data has a correct format and belongs to the specified value range, but the algorithm cannot succeed for some reason (for example, the optimization algorithm did not converge), it returns a special error code (typically, just a boolean variable).
The exceptions can be instances of the cv::Exception class or its derivatives. In its turn, cv::Exception is a derivative of std::exception. So it can be gracefully handled in the code using other standard C++ library components.
The exception is typically thrown either using the CV_Error(errcode, description) macro, or its printf-like CV_Error_(errcode, printf-spec, (printf-args)) variant, or using the CV_Assert(condition) macro that checks the condition and throws an exception when it is not satisfied. For performance-critical code, there is CV_DbgAssert(condition) that is only retained in the Debug configuration. Due to the automatic memory management, all the intermediate buffers are automatically deallocated in case of a sudden error. You only need to add a try statement to catch exceptions, if needed: :
OpenCVは例外を使用して重大なエラーを通知することができる。入力データの形式が正しく、指定された値域に属していているが、何らかの理由でアルゴリズムが成功できない場合(たとえば、最適化アルゴリズムが収束しなかった場合など)は、特殊なエラーコード(通常はブール変数)を返す。
例外は、cv::Exceptionクラスまたはその派生クラスのインスタンスとして、インスタンス化できる。さらに、cv::Exceptionはstd:: exceptionの派生クラスである。したがって、他の標準C++ライブラリコンポーネントを使用してコード内で正常に例外を処理をすることができる。
例外をスローするためには通常、CV_Error(errcode, description)マクロ、またはprintfのようなCV_Error_(errcode, printf-spec, (printf-args))を使用するか、条件を満たさない場合にスローするCV_Assert(condition)マクロを使用する。パフォーマンスが重要なコードでは、デバッグモードでのみ例外をスローするCV_DbgAssert(condition)を使用することもできる。OpenCVは自動メモリ管理を行うため、突然のエラー時には、すべての中間バッファが自動的に開放される。必要であればtry文を追加するだけで、例外をキャッチすることができる。
try
{
... // call OpenCV
}
catch( cv::Exception& e )
{
const char* err_msg = e.what();
std::cout << "exception caught: " << err_msg << std::endl;
}