OpenCVはC++で書くことにする

OpenCVを学ぶ時には確か

Objective-Cとの相性もあるし、Cで統一することにする」

と書いたと思うが、初版の事情でC++に統一して書くことにする。
理由は色々あるが、OpenCVというライブラリイ(というかもうこれはプラットホームだよな)の学習を進めるに従って以下のことが大きかった。

cv::Mat

OpenCVは2.0からC++のインタフェースが用意されて本格的にOOPに対応した。幾つかの構造体はクラスに設計し直されたり統合されたり廃止されたりされたが、その中の中心となっているのがこのcv::Matクラスだ。Matクラスはそれだけで画像データ、配列(多次元配列)、ベクトル(正確には違うが)、等、殆どの算術データを抽象化しており、OpenCV中で広く使える。
あまりに広く使えるために、所謂OOPバッドノウハウである「スイスアーミーナイフ」なクラスとも捉えることが出来そうだが、この巨大なライブラリを覚えるに際して、覚える型は少ない方が好ましいことも確かだ。

//InplImage構造体による画像データの生成
IplImage* tmp = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 3);

//cv::Matクラスによる画像データの生成
cv::Mat tmp = cv::Mat(src.size(), IPL_DEPTH_8U, 3);
メモリ管理

cv::Matのもう一つの有り難いことが、Objective-Cでも使われているのと同じ技術であるARC(Automatic Reference Counting)が導入されていることだ。cv::Mat はデータ領域がどこからも参照されなくなると自動的にメモリを解放する。デストラクタを明示的に呼び出すことはまずない。
このおかげで最新のOpenCVはほとんどの関数において関数呼び出しの前に出力用のメモリ領域を確保しておく必要がなくなった。

書くコードが少ない

cv::Matクラス、メモリ管理の自動化等のおかげで、同じ機能のコードを書くのにコード量をかなり少なくすることができる。
特に、CvMemStorage構造体によるワーキングメモリを確保する機会が大幅に減っており、メモリ管理の負担も減った。

  • C++で書いた2値化
+ (cv::Mat)binarize:(cv::Mat)src
{
    cv::Mat tmp = cv::Mat(src.size(), IPL_DEPTH_8U, 1);
    cv::Mat bin = cv::Mat(src.size(), IPL_DEPTH_8U, 1);
    cv::cvtColor(src, tmp, CV_BGR2GRAY);
    cv:threshold(tmp, bin, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
    return bin;
}

良い書き方かどうかは別にして、平滑化を行わないならばたったこれだけで2値化が書けてしまう。

正直な所、CからC++へのコンバートはファンクションの機能が変わったり、関数だったのがクラスのインスタンスメソッドになったり、名前自体が変わったものやパラメタの型が変わったものもあり、全て簡単にとはいかないものもあり混乱しているが、そこは我慢して慣れようと思う。