宙玉レンズを作った次の日に無料の宙玉レンズiPhoneアプリが出たからむしゃくしゃしてProcessingで宙玉レンズソフト作った後悔はしていないので公開する

そもそものはじまり

 タイトルままです。一説によるとタイトルは32文字にするとアクセス数が増えるらしいですが、もうそんなことはどうでもいいです。前回「宙玉レンズ作ったというか買って」このレンズがあればおしゃれな写真撮れる、これで私もおしゃれフォトグラファの仲間入りだ!ともうルンルン気分(死語)に浸っていたわけです。
 さてと、おしゃれ写真をInstagramにでもアップして「いいね」と沢山言われることで優越感に浸ろう、あわよくばモテモテになろうと思ってまさに写真をアップしようとしたそのとき、私は我が目を疑いました。大量の宙玉レンズで撮った写真。そんなバカな、なんでみんな宙玉レンズ持っているの!?調べたら、正体はMarbleCamというiPhoneアプリ。


 これを使えばどんな写真も宙玉レンズ風写真になるという最高におしゃれなアプリ。もうくやしい!ビクンビクン!せっかく苦労してレンズ自作したのに!これみよがしにアプリつくって!無料で公開して!お前も、お前もモテモテになりたいのか!
 というわけで、もてたくて頭おかしくなって自分もソフト自作することにしました。

宙玉ソフト 作成方法

 画像加工ということで、例の如くProcessingを使います。
 一番難しいであろう宙玉の部分ですが、3Dモデルの球に写真をテクスチャとして貼付ければそれっぽく見えるんじゃないかと考えました。

 球の描画とテクスチャの貼付けに関しては、三角関数を使った計算レベルでいけそうだと思い考えてみました。思ったより頭が固くなっていて時間がかかりました、たまには頭使わなきゃだめですね。細かい説明は面倒くさいので、考えるときに書いたイメージ図の板書の写真をおきます。

120527_SORATAMA_Board
 多分これを見れば、50人に1人くらいはわかりやすい!と涙流しながら理解してくれるのではないかと期待しています。わかるよね!?

 画像をぼかしたりする部分は、Processingだと関数が用意してあって1行で終わってしまいました。便利過ぎですね。

成果物

 いつものように題材は天使のミクさん

120517_mikucomic_01
 ミクさんまじ天使!

120527_SORATAMA_MarbleCam
 これがMarbleCam。中々いい感じ。

120527_SORATAMA_LENS
 これが実際の宙玉レンズで撮った写真、暗いところで感度上げて適当に撮ってしまったとはいえちょっといまいち・・・

120527_SORATAMA_Processing
 これが今回つくった自作ソフト!うん、ちょっと不自然だね!

 結論はMarbleCamが一番いい感じということがわかりました。く、くやしいビクンビクン!

今後の予定

 気が向いたらもうちょっと改良します。後は、多分1時間くらい頑張れば動画の宙玉レンズ風エフェクトもできるようになるはずなので気が向いたら作ります。でも多分気は向かないと思います。万一欲しい人がいたらリクエストして下さい。

ソースコード

 最後にProcessingのソースコードも置いておきます。プログラムの最初の方の定数を変えると宙玉の大きさとか、背景のぼけ具合とか色々調整できます。

 使い方は、起動したら好きな画像ファイルを選んでしばらく待つだけ(画像ファイルの名前は英語だけにしてね☆)、宙玉レンズ風写真が自動で出来上がります。「p」ボタンを押すと「screenshot.jpg」という名前で画像がプログラムと同じフォルダに保存されます。
 あんまりにも画像が出てくるの遅かったら、final float step_ang = 180; final float step_rad = 50;の数を小さくして下さい。宙玉が荒くなりますが、早く出てきます。逆に奇麗な宙玉レンズつくりたいときは、ここの部分を大きくしてやるとキレイになります。

PImage tex;
PImage img_blur;

final float pic_x = 1024;
final float pic_y = 768;
final float camera_z = 30;
final float sphere_size = 5; // from 0 to camera_z/2
final float backimg_blur_level = 5;
final float soratama_blur_level = 0;
final float backimg_size = 0.1; // from 0 to 0.5
final float soratama_size = 0.9; // from 0 to 1

final float step_ang = 180;
final float step_rad = 50;

void setup() {  
  size((int)pic_x, (int)pic_y, P3D);

  println("select photo."); 
  String imgPath = selectInput();

  textureMode(NORMALIZED);

  img_blur = loadImage(imgPath);
  img_blur.filter(BLUR, backimg_blur_level);
  
  tex = loadImage(imgPath);
  tex.filter(BLUR, soratama_blur_level);
}

void draw() {
  // Camera Setting
  camera(0, 0, camera_z,
         0, 0, 0,
         0, 1, 0);
  
  // draw blur image background
  float frame_x = pic_x / (camera_z/2);
  float frame_y = pic_y / (camera_z/2);

  noStroke();
  beginShape();
  texture(img_blur);
  vertex(-frame_x, -frame_y, 0, backimg_size, backimg_size);
  vertex(frame_x, -frame_y, 0, 1-backimg_size, backimg_size);
  vertex(frame_x, frame_y, 0, 1-backimg_size, 1-backimg_size);
  vertex(-frame_x, frame_y, 0, backimg_size, 1-backimg_size);
  endShape();  

  // draw soratama
  final float rad_sphere = camera_z /2 - sphere_size;
  final float step_sphere = TWO_PI / step_ang;
  final float step_sphere2 = rad_sphere / step_rad;

  noStroke();
  beginShape();
  texture(tex);
  for(float x = 0; x < rad_sphere; x += step_sphere2){
    for(float ang = 0; ang < TWO_PI; ang += step_sphere){
      vertex(x*cos(ang), x*sin(ang), sqrt(rad_sphere*rad_sphere - x*x),
             soratama_size*(-x/rad_sphere*cos(ang)/2)+0.5, soratama_size*(-x/rad_sphere*sin(ang)/2) + 0.5);
    }
  }
  endShape();  
}


void keyPressed() { 
  // save image
  if(key == 'p' || key == 'P') {
    save("screenshot.jpg"); 
    println("screen saved."); 
  }

  // exit
  if(key == ' ') {
    exit();
  }
}