cvl-robot's diary

研究ノート メモメモ https://github.com/dotchang/

おまけ:RICOH THETAのJPG画像を平面-球変換してOpenGLで表示する

f:id:cvl-robot:20131031202038j:plain

RICOHのTHETAが来たので、全方位画像をOpenGLで表示出来るようにしてみます。いつものように、openFrameworksのpointCloudExampleを改造して作ります。おそらく単純な極座標変換で大丈夫なので*1、画像座標を極座標(球面座標)値と見立てて、半径Rの球状の点群として3次元位置を計算しています。

#include "testApp.h"

#define _USE_MATH_DEFINES

#include <math.h>

 

//--------------------------------------------------------------

void testApp::setup() {

ofSetVerticalSync(true);

 

// load an image from disk

img.loadImage("R0010032.JPG");

 

// we're going to load a ton of points into an ofMesh

mesh.setMode(OF_PRIMITIVE_POINTS);

 

// loop through the image in the x and y axes

float r = 10.0f; // radius

for(int y = 0; y < (int)img.getHeight(); y++){

for(int x = 0; x < (int)img.getWidth(); x++){

ofColor cur = img.getColor(x, y);

cur.a = 255;

 

float theta = (float)y * M_PI / img.getHeight();

float phi = -(float)x * 2.0f * M_PI / img.getWidth();

float px = r * sin(theta) * cos(phi);

float py = r * sin(theta) * sin(phi);

float pz = r * cos(theta);

 

mesh.addColor(cur);

ofVec3f pos(px, py, pz);

mesh.addVertex(pos);

}

}

 

ofEnableDepthTest();

glEnable(GL_POINT_SMOOTH); // use circular points instead of square points

glPointSize(3); // make the points bigger

 

cam.setAutoDistance(false);

cam.setPosition(0,0,0);

cam.lookAt(ofVec3f(r,0,0),ofVec3f(0,0,1));

cam.setDistance(1.0);

}

 

//--------------------------------------------------------------

void testApp::update() {

}

 

//--------------------------------------------------------------

void testApp::draw() {

ofBackgroundGradient(ofColor::gray, ofColor::black, OF_GRADIENT_CIRCULAR);

 

// even points can overlap with each other, let's avoid that

cam.begin();

mesh.draw();

cam.end();

}

 

//--------------------------------------------------------------

void testApp::keyPressed(int key){

}

 

//--------------------------------------------------------------

void testApp::keyReleased(int key){

 

}

 

//--------------------------------------------------------------

void testApp::mouseMoved(int x, int y){

 

}

 

//--------------------------------------------------------------

void testApp::mouseDragged(int x, int y, int button){

 

}

 

//--------------------------------------------------------------

void testApp::mousePressed(int x, int y, int button){

 

}

 

//--------------------------------------------------------------

void testApp::mouseReleased(int x, int y, int button){

 

}

 

//--------------------------------------------------------------

void testApp::windowResized(int w, int h){

 

}

 

//--------------------------------------------------------------

void testApp::gotMessage(ofMessage msg){

 

}

 

//--------------------------------------------------------------

void testApp::dragEvent(ofDragInfo dragInfo){ 

 

}

 ファイル名を決めうちで与えていますが、引数渡しなどに適当に修正してください。ofxThreadedImageLoaderなどを利用すれば、URLからも画像を指定できるようになります。ほぼRICOH THETAの付属ビューアと同じことができますが、距離を遠くすると、裏側が見えるようになってしまうという制限があります。これを回避するには、球に法線を定義して、視線ベクトルと対抗しない面を表示しないようにしてやれば解決できます。OpenGLの関数では、

glEnable(GL_CULL_FACE); 
glCullFace(GL_BACK);

の2行を呼び出します。

f:id:cvl-robot:20131031192053p:plain

fig.座標変換

THETA HACKが下記のページでまとめられています。

まだやられていないことをやろう。

http://blog.mobilehackerz.jp/2013/10/ricoh-thetahdriblimage-based-lighting.html

EXIF情報から加速度情報もとれるそうです。面白いなぁ。

http://d.hatena.ne.jp/xanxys/20131110/1384094832

 

 

早くTheta Sを買わないと!時代に取り残される気がする。 

*1:正距円筒座標とのこと