実行イメージは以下のようになります。
サンプル動画(ダブルクリックで再生、クリックで一時停止します) |
そもそも1ピクセルはRed、Green、Blue、Alphaの4つの要素から構成されます。具体的にいうと、「cameraPixels[0]」には画像左上1pxのRが、「cameraPixels[1]」にはGが、「cameraPixels[2]」にはBが、「cameraPixels[3]」にはAが、そして「cameraPixels[4]」には画像左上から右に1pxずれた2px目のRが、「cameraPixels[5]」には2px目のGが……となります。
今回作成するサンプルでは、タッチした座標を元に、画面のX軸を画像のR要素に、Y軸をG要素に反映しています。
コードを書き換えてみましょう。
#pragma once #include "ofMain.h" #include "ofxiPhone.h" #include "ofxiPhoneExtras.h" class testApp : public ofxiPhoneApp { public: void setup(); void update(); void draw(); void exit(); void touchDown(ofTouchEventArgs &touch); void touchMoved(ofTouchEventArgs &touch); void touchUp(ofTouchEventArgs &touch); void touchDoubleTap(ofTouchEventArgs &touch); void touchCancelled(ofTouchEventArgs &touch); void lostFocus(); void gotFocus(); void gotMemoryWarning(); void deviceOrientationChanged(int newOrientation); unsigned char * cameraPixels; // the camera image needs to be flipped, so we'll use this memory for that unsigned char * tempPixels; // the camera image needs to be flipped, so we'll use this memory for that. ofxiPhoneImagePicker * camera; ofImage photo; ofPoint imgPos; float r; float g; };
「testApp.h」では、元画像のピクセル情報を保存する「tempPixels」と、タッチした座標によって変化する「r」「g」を追記しました。
unsigned char * tempPixels; float r; float g;
次に「testApp.mmのsetup()」です。こちらも大きな変化はなく、tempPixelsとr、gの初期化を追記しています。
#include "testApp.h" //-------------------------------------------------------------- void testApp::setup(){ // register touch events ofRegisterTouchEvents(this); // initialize the accelerometer ofxAccelerometer.setup(); //iPhoneAlerts will be sent to this. ofxiPhoneAlerts.addListener(this); cameraPixels = NULL; tempPixels = NULL; camera = new ofxiPhoneImagePicker(); camera->setMaxDimension(480); //otherwise we will have enormous images imgPos.x=ofGetWidth()/2; imgPos.y=ofGetHeight()/2; r = 0; g = 0; photo.loadImage("images/instructions.png"); }
update()では、cameraPixelsのロード後、tempPixelsにいったん退避させます。
void testApp::update() { if(camera->imageUpdated){ // the pixels seem to be flipped, so let's unflip them: if (cameraPixels == NULL){ // first time, let's get memory based on how big the image is: cameraPixels = new unsigned char [camera->width * camera->height*4]; } // now, lets flip the image vertically: for (int i = 0; i < camera->height; i++){ memcpy(cameraPixels+(camera->height-i-1)*camera->width*4, camera->pixels+i*camera->width*4, camera->width*4); } tempPixels = cameraPixels;
退避後、cameraPixelsに格納されているそれぞれのピクセルのR、Gに当たる部分を処理しています。r、gはタッチした座標に応じて、0?1が入ります。処理したcameraPixelsをphotoにセットしたら、tempPixelsをcameraPixelsに代入して、書き戻します。
for (int i = 0; i < camera->height*camera->width*4; i+=4){ cameraPixels[i] *= r; cameraPixels[i+1] *= g; } // finally, set the image from pixels... photo.setFromPixels(cameraPixels,camera->width, camera->height, OF_IMAGE_COLOR_ALPHA); imgPos.x=ofGetWidth()/2; imgPos.y=ofGetHeight()/2; camera->imageUpdated=false; cameraPixels = tempPixels; } }
draw()も特に変更はありません。
void testApp::draw() { photo.draw(imgPos.x-photo.width/2,imgPos.y-photo.height/2); }
最後に、タッチイベントです。今回はカメラではなくPhoto Libraryから画像を読み込んでみましょう。Photo Libraryは「camera->openLibrary()」で呼び出せます。
void testApp::touchDown(ofTouchEventArgs &touch) { if(touch.id == 1){ camera->openLibrary(); } }
画面ドラッグ時の座標に応じて、rとgの値を変更します。
void testApp::touchMoved(ofTouchEventArgs &touch){ if(touch.id == 0){ r = touch.x / 320; g = touch.y / 480; camera->imageUpdated = true; } }
今回はopenFrameworksを使った、カメラやPhoto Libraryの扱いとピクセル処理について学びました。ピクセル処理に使った実装を書き換えれば、色の編集だけではなく、モザイクや“ぼかし”などの効果を画像に加えることも可能です。ぜひ、いろいろ書き換えてみてください。
1988年神戸生まれ。UIデザインからプログラミング、表現までやりたい、自称クリエイティブデザイナ。
“さわってみたい”を創ることが目標。フィジカルコンピューティングなどの試作を行う傍ら、コミュニティ活動ではExpression Blendを中心としたセッションを行っている
Copyright © ITmedia, Inc. All Rights Reserved.