new C++ template image classes contributed by Daniel Filip (Google inc.).
ここでは紹介程度に。
OpenCV 1.1ではWImageというIplImageのラッパークラスが用意されています。
(‘W’はwrapperの意味で付けられたようです)
このWImageクラスは以下のようにテンプレートクラスとして宣言されています。
1 2 3 4 5 6 7 8 |
// cvwimage.h 109行目? template <typename T> class WImage; template <typename T> class WImageBuffer; template <typename T> class WImageView; template<typename T, int C> class WImageC; template<typename T, int C> class WImageBufferC; template<typename T, int C> class WImageViewC; |
WImageはスーパークラス、WImageBuffer と WImageView はそのサブクラスになっています。
ここから typedef WImage<uchar> WImage_b; のようなtypedefが50行ほど続きます。
ここでピクセルデータへの直接アクセス IplImage(opencv.jp)のコードをWImageクラスを使って書き換えます。
(実際にはそのサブクラスであるWImageBufferクラスを利用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#include <cv.h> #include <highgui.h> #include <cvwimage.h> int main(int argc, char **argv) { // 名前空間は cv cv::WImageBuffer3_b img; // 8ビット3チャンネル画像 uchar p[3]; if(argc != 2) return -1; img.SetIpl(cvLoadImage(argv[1], CV_LOAD_IMAGE_COLOR)); for(int y=0; y<img.Height(); ++y){ for(int x=0; x<img.Width(); ++x){ p[0] = *(img(x,y)); // B p[1] = *(img(x,y)+1); // G p[2] = *(img(x,y)+2); // R *(img(x,y)) = cvRound(p[0]*0.7+10); *(img(x,y)+1) = cvRound(p[1]*1.0); *(img(x,y)+2) = cvRound(p[2]*0.0); } } cvNamedWindow("Image", CV_WINDOW_AUTOSIZE); cvShowImage("Image", img.Ipl()); cvWaitKey(0); cvDestroyWindow("Image"); return 0; } |
07行目の WImageBuffer3_b は WImageBufferC<uchar, 3> をtypedefしたものです。
このように、WImageBuffer[チャンネル数]_[ビット深度] という風に宣言します。
例えば32ビット浮動小数点型1チャンネル画像の場合は WImageBuffer1_f のように書きます。
(CV_32FC1 のようなマクロとチャンネル数・ビット深度の指定順序が逆)
11行目の void SetIpl(IplImage* image) でIplImage(protectedメンバ)に画像データをセットします。
また、領域確保をする場合は void Allocate(int width, int height) を使います。(ステレオ画像処理参照)
(引数にCvSizeを取ってくれないのは少し残念;)
13,14行目の img.Width(), img.Height()はIplImageのwidth, heightを取得するアクセサです。
この他にも Channels() や Depth() などが用意されています。
15行目以降の img(x,y) という書式。これは座標(x,y)の最初のチャンネルへのポインタを返します。
これは以下のように () 演算子のオーバーロードによって実現されています。
画像データへのアクセス部分はよく見慣れたコードですね。
1 2 3 4 5 6 7 8 9 10 |
// Pixel accessors which returns a pointer to the start of the channel inline T* operator() (int c, int r) { return reinterpret_cast<T*>(image_->imageData + r*image_->widthStep) + c*Channels(); } inline const T* operator() (int c, int r) const { return reinterpret_cast<T*>(image_->imageData + r*image_->widthStep) + c*Channels(); } |
実は今回のサンプルではこのクラスの便利な部分をほとんど紹介できていません;
着目領域での処理等はWImageViewクラスを利用すれば簡潔に書けるのでそれについてはいずれ。