OpenCV2の基礎


OpenCVは、2.x系列になってC++ベースのシステムに置き換わり、APIもより構造化されている。

## インストール

```bash
brew tap homebrew/science
brew install opencv
```

## コンパイル

```bash
g++ `pkg-config --cflags --libs opencv` xxx.cpp
```

というように`pkg-config`をつかってコンパイルオプションを設定するとよい。

## リファレンス

ドキュメントはいろいろあるけど、網羅的に把握するには、とりあえず本家のリファレンスを参照するのが良さそう。
[OpenCV API Reference](http://docs.opencv.org/modules/refman.html) ([日本語版](http://opencv.jp/opencv-2svn/cpp/)）

実際に読んだ中では、以下が良かった。

- [Introduction - OpenCV API Reference](http://docs.opencv.org/modules/core/doc/intro.html)
- [OpenCV.jp 逆引きリファレンス](http://opencv.jp/cookbook/)
- [User Guide](http://docs.opencv.org/doc/user_guide/user_guide.html) ([pdf](http://opencv.jp/opencv-2svn_org/opencv_user.pdf)) ([日本語版pdf](http://opencv.jp/opencv-2svn/opencv_user.pdf))



## 基本的なライブラリ

* **core** - 多次元の疎でない配列を扱うMatを含む基本的なデータ構造と関数を定義
* **imgproc** - 画像処理（フィルタ・アフィン変換・色変換等）
* **video** - 動画解析
* **calib3d** - 複数画像解析（カメラキャリブレーション・立体視・3D Reconstruction等）
* **features2d** - 特徴抽出
* **objdetect** - 物体抽出と、顔や車など基本的な物体用のデータ
* **highgui** 動画の取得・画像や動画のコーデック・GUI表示
* **gpu** - GPUで高速化されるアルゴリズム
* **その他** ... FLANN、テスト環境、他言語バインディングなどなど

それぞれ、以下のようにincludeして使う。

```cpp 
#include <opencv2/core/core.hpp>
using namespace cv;
```

とりあえず画像処理をしたい場合は、core, imgproc と highgui あたりを学べば良さそう。

Referenceのこの後の構成は、以下のようになっているので、この順によく使うのかもしれない。

* core
* imgproc
* highgui
* video
* calib3d
* featues2d
* objdetect
* ml (Machine Learning)
* flann (近傍探索)
* gpu
* photo (Computational Photography)
* stitching 
* nonfree (ライセンスがFreeではないもの）
* contrib (実験的なもの)
* legacy (Deprecated)
* ocl (OpenCL-accelerated)
* superres (Super Resolution)
* viz (3D Visualizer) 

## Mat構造

OpenCV.jpの[cv::Matの基本処理](http://opencv.jp/cookbook/opencv_mat.html)がめちゃくちゃいいドキュメントになっている。
本家のチュートリアルだと、[Mat - The Basic Image Container](http://docs.opencv.org/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.html#matthebasicimagecontainer) が良かった。

画像を含めわかりやすかったので、そのまま引用させてもらうと、基本的概念としては、

- チャンネル（channel）：要素の次元 
- 次元（dimension）：複数の要素からなる配列の次元

> ![ch=2, dim=2](http://opencv.jp/cookbook/_images/mat17c2.png) ![ch1, dim=2](http://opencv.jp/cookbook/_images/mat57c1.png) ![ch=3, dim=2](http://opencv.jp/cookbook/_images/mat57c3.png) ![ch=4, dim=3](http://opencv.jp/cookbook/_images/mat57xc4.png)
> http://opencv.jp/cookbook/opencv_mat.html

となっている。1次元ベクトルを表すときも1*xの2次元として扱うことに注意。

### チャンネルについて


チャンネルは、`CV_8UC1`、`CV_64FC2`等、

```
CV_<ビット数><型>C<チャネル数>
```

の形式で表される。

ここで`<型>`は、以下の3つのどれかに限られる。

* **S** - 符号付き整数表現
* **U** - 符号無し整数表現
* **F** - 浮動小数点表現

チャネル数が1の場合、末尾のC1を省略できる。例えば、`CV_8UC1`は`CV_8U`と書ける。
`CV_8UC(n)`というマクロも定義されているので、`CV_8UC(1)`とも書ける。

もちろんこれは`#define`で定義されている定数なので、メジャーなものしか定義されていない。
必要な場合は、以下の`CV_MAKETYPE`を使って作成すると良い。

```types_c.h
#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT))
```


#### RGBの注意点

OpenCVではRGB表現はBGRの順に格納される。

### メモリ管理について

Matは、高速化や前方互換性のために、結構頑張ったメモリ管理構造をしていて以下の様な特徴がある。

- スレッドセーフ
- 参照カウントを用いたメモリ管理
- shallow copy
- 内部的に不連続なメモリでも管理可能

ただ、ここの部分の説明はちゃんと書くしか無いために、長くて嫌になるので、ひとまず飛ばして、困ったら、安全に`mat.clone()`するという戦略が良いと思う。

## highgui

とりあえず基礎だけ。画像の入出力と、GUI操作する時に

```
#include <opencv2/highgui/highgui.hpp>
```

すれば良い。

ちなみに、http://opencv.jp/cookbook/opencv_io.html
が良かったので、基本的にこちらを参照すればOKな気がする。


### 画像の読み込みと書き込み

OpenCVは画像のフォーマットをファイル名の拡張子で判断する。
なので以下のように名前を変えればフォーマットを変換できる。

```image_convert.cpp
Mat img = imread("image.jpg")
imwrite("image.png", img)
```

なお、`imwrite`は3引数目にパラメータを取り、画像の品質などを指定できる。


### 読み込んだイメージをGUIで表示する

```image_show.cpp
Mat img = imread("image.jpg");
namedWindow("window", CV_WINDOW_AUTOSIZE);
imshow("window", img);
waitKey();  // キー入力を待つ
```

namedWindowを付けないで`imshow`すると、デフォルトのウィンドウ設定で表示してくれる。

### カメラ画像入力

カメラのとった画像をただ流すだけのサンプル。
コメントの部分に何か処理を書くと、リアルタイムに顔認識したり、モザイクをかけたり、移動物体を追跡するプログラムが書ける。

```camera.cpp
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;

int main(int argc, char *argv[]) {
  VideoCapture cap(0);
  cap.set(CV_CAP_PROP_FRAME_WIDTH, 640);
  cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
  if (!cap.isOpened()) return -1;

  namedWindow("Capture", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
  for(;;) {
    Mat frame;
    cap >> frame;
    // write image processing here ...
    imshow("Capture", frame);
    if (waitKey(30) >= 0) {
      break;
    }
  }
  return 0;
}
```

## 応用へ

さてさて、本番の画像解析などの応用プログラムを書きたい時どうするかという話。
ここまで来たら基本概念は理解しているはずなので、「やりたいこと+OpenCV」でググって、ブログを読むとか、すると良い。

まとまったドキュメントとしては、
http://opencv.jp/cookbook/opencv_img.html
をベースに、上のカメラ画像入力のサンプルと組み合わせてみると良い。

本家のチュートリアルからは、以下ががオススメ
http://docs.opencv.org/doc/tutorials/imgproc/table_of_content_imgproc/table_of_content_imgproc.html