基本構造体
作成者: 怡土順一, 最終変更者: 怡土順一, 最終変更リビジョン: 366, 最終変更日時: 2008-02-11 21:51:13 +0900 (月, 11 2月 2008)
■ IplImage
OpenCVでは,IPL(Intel Image Processing Library)で使われていた構造体 IplImage フォーマットの一部をサポートしている. OpenCVの多くの関数が,構造体 IplImage を含む CvArr を,その引数に取る. 構造体 IplImageのメンバ,imageData に,実際のピクセルの値が格納されており, その画像の幅と高さはそれぞれ,width,heightで示される. また,メンバ変数 widthStep は,画像の水平方向1ライン分をバイト単位で表す値であり, これは,imageData のデータに直接アクセスする際に利用される. widthStep はメモリのアライメント(alignment)により,width と同じか,それよりも大きい値となる.サンプル
ピクセルデータへの直接アクセス IplImage
8ビット3チャンネルカラー画像を読み込み,ピクセルデータを変更する
サンプルコード
#include <cv.h> #include <highgui.h> int main (int argc, char **argv) { int x, y; uchar p[3]; IplImage *img; if (argc != 2 || (img = cvLoadImage (argv[1], CV_LOAD_IMAGE_COLOR)) == 0) return -1; // (1)ピクセルデータ(R,G,B)を順次取得し,変更する for (y = 0; y < img->height; y++) { for (x = 0; x < img->width; x++) { p[0] = img->imageData[img->widthStep * y + x * 3]; // B p[1] = img->imageData[img->widthStep * y + x * 3 + 1]; // G p[2] = img->imageData[img->widthStep * y + x * 3 + 2]; // R img->imageData[img->widthStep * y + x * 3] = cvRound (p[0] * 0.7 + 10); img->imageData[img->widthStep * y + x * 3 + 1] = cvRound (p[1] * 1.0); img->imageData[img->widthStep * y + x * 3 + 2] = cvRound (p[2] * 0.0); } } cvNamedWindow ("Image", CV_WINDOW_AUTOSIZE); cvShowImage ("Image", img); cvWaitKey (0); cvDestroyWindow ("Image"); cvReleaseImage (&img); return 0; }
// (1)ピクセルデータ(R,G,B)を順次取得し,変更する
画像の各ピクセルデータ(カラー画像ならば,各ピクセルのRGB値であることが多い)を取得する(つまり,色を取り出す),
あるいは値を格納するという処理は,画像処理の基本操作である.
OpenCVでは,構造体 IplImage のメンバである imageData 配列にピクセルデータが格納されている.
この配列の値を取り出して,適当な演算により値を変更している.
今回は,R(赤)チャンネルの値を 0 に,B(青)チャンネル値を約0.7倍にしている.
また,これらのピクセルデータは,以下のようにして取り出すこともできる.
char *pt1, *pt2;
for(pt1 = img->imageData; pt1 < img->imageData + img->widthStep*img->height; pt1 += img->widthStep) {
for(pt2 = pt1; pt2 < pt1 + img->width*3; pt2 += 3) {
p[0] = pt2[0];
p[1] = pt2[1];
p[2] = pt2[2];
}
}
さらに,OpenCVの配列アクセス関数を用いて,以下のようにCvScalarとして値を得ることも可能である.
CvScalar s;
for(y = 0; y < img->height; y++) {
for(x = 0; x < img->width; x++) {
s = cvGet2D(img, x, y);
}
}
しかし,関数cvGet*Dを用いたアクセスは,関数呼び出しのオーバヘッドもあり,非常に低速である.
ある特定ピクセルの値に対してのみアクセスしたい場合を除いて,関数cvGet*Dを利用した方法は推奨されない.
