実行イメージは以下のようになります。
| サンプル動画(ダブルクリックで再生、クリックで一時停止します) |
そもそも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.