目次
openFrameworksとOpenCVについて、2つの画像をリアルタイムで合成するためにはどうしたらいいかというご質問をメールでいただいたので、解説していこうと思います。
まず、次のような画像があるとします。ofxCvGrayscaleImage binaryImg
: どこに画像を当てはめるかを白黒の2値画像で表したものofxCvColorImage sampleImg1
: binaryImgの白に当てはめる画像ofxCvColorImage sampleImg2
: binaryImgの黒に当てはめる画像ofxCvColorImage compositeImg
: 実際に二種類の画像を合成したもの
unsigned char * binaryImgPixels = binaryImg.getPixels();
unsigned char * sampleImg1Pixels = sampleImg1.getPixels();
unsigned char * sampleImg2Pixels = sampleImg2.getPixels();
int nPixels = camWidth*camHeight;
unsigned char * compositeImgPixels = new unsigned char[nPixels*3];
for(int i=0; i<nPixels; i++){
if(binaryImgPixels[i]==255){
compositeImgPixels[3*i] = sampleImg1Pixels[3*i];
compositeImgPixels[3*i+1] = sampleImg1Pixels[3*i+1];
compositeImgPixels[3*i+2] = sampleImg1Pixels[3*i+2];
} else {
compositeImgPixels[3*i] = sampleImg2Pixels[3*i];
compositeImgPixels[3*i+1] = sampleImg2Pixels[3*i+1];
compositeImgPixels[3*i+2] = sampleImg2Pixels[3*i+2];
}
}
compositeImg.setFromPixels(compositeImgPixels, camWidth, camHeight);
以上で二種類の画像が合成されたcompositeImg
が作成されます。
for文の中に3*i
, 3*i+1
, 3*i+2
というものがありますが、それぞれ、i番目のピクセルのRとGとBの値が入っている配列のインデックスを表しています。カラー画像のピクセル情報は配列に(R,G,B,R,G,B,…)という風に入っているので、i番目のピクセルに色をコピーしたい場合は3*i
(R)と3*i+1
(G)と3*i+2
(B)をすべてコピーしなくてはなりません。
次の動画は応用例です。
背景画像をあらかじめ取得しておき、背景との差分をとって2値画像(binaryImg
)を作成します。さらにカメラから取得したそのままの画像(sampleImg1
)と、背景画像を少し拡大した画像(sampleImg2
)を合成することで、光の屈折を表現し、透明人間がいるように表現しています。
以前、掲載したopenFrameworks & OpenCVでColor Tracking(色追跡)の記事と組み合わせて、何かを作りたい場合、ここでいうbinaryImgPixels
がcolorTrackedPixelsRed
に対応します。
3i, 3i+1, 3i+2
番目の値を参照する。画像認識を使うといろいろ面白いことができるので、是非、やってみてはいかがでしょうか。