OpenGL de プログラミング - IplImage編02::直接アクセス
現在地 >> メニュー >> OpenCV >> IplImage編02 >> IplImage編02::直接アクセス
関連:IplImage編02::間接アクセス



直接アクセス


配列やポインタなどで直接アクセスする場合、
  • 効率的である
  • 範囲外にアクセスした時の処理がない
といった特徴がある。

直接アクセスのおもな方法として以下の方法がある。

[方法1]


リファレンスのFAQに書いてある方法。

この方法は、縦方向(y)はアドレスで移動し、横方向(x)は配列でのアクセスを行っている。


(A).シングルチャネルのbyte(unsigned char)の場合

【例】
IplImage* imgA = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
 ... ...
reinterpret_cast<unsigned char *>(imgA->imageData + y*imgA->widthStep)[x]=255; //(x,y)の位置を255にする


(B).マルチチャネルのbyte(unsigned char)の場合


オペレータ[]内の記述が少し異なる。
【例】
IplImage* imgA=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
... ...
reinterpret_cast<unsigned char *>(imgA->imageData + y*imgA->widthStep)[x*imgA->nChannels]=0;  //B
reinterpret_cast<unsigned char *>(imgA->imageData + y*imgA->widthStep)[x*imgA->nChannels+1]=0; //G 
reinterpret_cast<unsigned char *>(imgA->imageData + y*imgA->widthStep)[x*imgA->nChannels+2]=0; //R


例えば、ループをまわして、ある1部分を書き換える場合は、
for(int y = 50; y < 100 ; ++y)
{
	for(int x = 100; x < 150; ++x)
	{
		reinterpret_cast<unsigned char *>(imgA->imageData + y*imgA->widthStep)[x*imgA->nChannels]=0;  //B
		reinterpret_cast<unsigned char *>(imgA->imageData + y*imgA->widthStep)[x*imgA->nChannels+1]=255; //G 
		reinterpret_cast<unsigned char *>(imgA->imageData + y*imgA->widthStep)[x*imgA->nChannels+2]=0; //R
	}
}
といった感じで書くことができる。

※より効率的に、キャスト回数を少なくした方法は以下の通り
unsigned char* temp_ptr;
temp_ptr = &( reinterpret_cast<unsigned char *>(imgA->imageData + y*imgA->widthStep)[x*imgA->nChannels] ) ;//ピクセル位置(x,y)について
temp_ptr[0]= 255;
temp_ptr[1]= 0;
temp_ptr[2]= 255;

※データがfloat型の時などは?


キャストを部分を変えるだけでよい。
reinterpret_cast<float *>(imgA->imageData + y*imgA->widthStep)[x*imgA->nChannels]=0;  //B




[方法2]


オペレータ[]の中に記述する。

(A).シングルチャネルで1バイトアライメント(char)の場合


IplImage* imgA  = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
... ...
imgA->imageData[y*imgA->widthStep + x] = 0;

(B).マルチチャネルで1バイトアライメント


IplImage* img  = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
... ...
img->imageData[y*img->widthStep + x*img->nChannels] = 100;
img->imageData[y*img->widthStep + x*img->nChannels + 1] = 100;
img->imageData[y*img->widthStep + x*img->nChannels + 2] = 100;

※注意点
imageDataの型が「char型」であって、「unsigned char」でない事に気をつける必要がある。


(C).float(4バイトアライメント)の時は?


widthStepをバイトサイズで割る必要がある。

IplImage* img  = cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
... ...
int step  = img->widthStep/sizeof(float);  //バイトサイズで割る
float * data   = (float *)img->imageData; //floatのポインタとしてわたす

data[y*step+x*img->nChannels] = 150;
data[y*step+x*img->nChannels+1] = 150;
data[y*step+x*img->nChannels+2] = 150;



[方法3]:CV_IMAGE_ELEMマクロ


OpenCVには「CV_IMAGE_ELEMマクロ」が用意されているので、
これを使った方が見やすいかもしれない。

【例】
for(int y = 50; y < 100 ; ++y)
{
	for(int x = 100; x < 150; ++x)
	{
		CV_IMAGE_ELEM(imgA,unsigned char,y,x*imgA->nChannels)= 0;
		CV_IMAGE_ELEM(imgA,unsigned char,y,x*imgA->nChannels+1)= 255;
		CV_IMAGE_ELEM(imgA,unsigned char,y,x*imgA->nChannels+2)= 0;
	}
}

サンプルコード