続:Processingを使って感動的な結婚式動画を作る方法

Processing Advent Calendar参加記事です

はじめに

 今年もProcessing Advent Calendarなる企画に参加させていただきましたので、久しぶりのProcessingの記事です。Processingといえば、ちょっとしたら動画を作るのにピッタリということで、結婚式のスライドショーの作り方を題材として取り上げてみたいと思います。タイトルに続と書いてあったので気づいた方もいるかもしれませんが、この結婚式の動画を作るシリーズは2回目です。1回目は実に半年以上前というね。そんなわけで、今回は2回目にして多分最終回です。刮目して見よ!!

 というわけで、今回は写真が右から左にヒュンヒュン流れて行くスライドショーを作りたいと思います。ちょっとだけ3D的要素を入れて、写真に奥行きを出したり遠くの写真はぼけたりするようにしています。言葉の説明だとイメージができない方は、後で動画出てきますのでご心配なく。わりとありふれた演出ですが、意外にiMovieとかではできなかったりします。
 実は、Motionってソフトでこの演出作っている人がいて、自分の結婚式の動画で真似しようと思いMotion買ったのですが自分には使いこなすことができず泣く泣くProcessingでプログラミングしたという悲しい思い出がありますMotion使いこなせない自分のような人にもProcessingは強い味方です。

ソフト使い方

 本記事最後に載せてあるソースコードをコピペして適当なフォルダに保存してやりましょう。同じフォルダに"data"というフォルダを作ってその後に自分が使いたい写真をtex0.jpg〜tex23.jpgという名前にリネームしてやります。
 あとは実行するだけ!映像が流れて行くと同時にプログラムがあるフォルダに framesというフォルダが作成されその中に 0000.tif, 0001.tif…といった感じに1フレーム毎に画像が鬼のように作られて行きます。いい感じのところでESCボタンを押してやれば終了です。
 void X_Scroll_Setup()関数のパラメータを弄ると、写真の位置が変わりますので気に入らない方は適当に弄ってみて下さい。

動画生成

 Processing2での動画の生成方法はProcessing1とは異なるので要注意です。といっても簡単で、以下の3ステップでできます。

  1. Processing2を立ち上げる
  2. Processing2のメニュからTools -> Movie Maker を選択してMovie Makerを立ち上げる
  3. 右側のChooseボタンを押して、先ほど鬼のように画像ファイルを作成した frames フォルダを選択する
  4. サイズを入力する(プログラムのsize_xとsize_yに合わせようね、今回は960 x 540だね)。入力できない場合は、same size as originalsのチェックボックスを外しましょう
  5. Create Movieボタンを押して動画作成

※2014/12/15追記
 久しぶりに同じことやろうとしたら、いつの間にかMovie Makerが自分の環境では使えなくなっていましたので他の方法で動画生成しました。自分と同じような不幸な人は下記記事参照下さい。


完成した動画

 完成した動画がこちらです。今回は、愛知県岡崎市が誇るゆるキャラ、オカザえもんを題材に作ってみました。写真は全部自分が撮影したものです。

 写真の枚数、位置変更等簡単にできますので試してみて下さい。
背景が寂しいと思ったときは、バックグラウンドの色を白から緑か青に変更して、iMovieのクロマキー合成機能で好きな動画と合成するといった高等テクニックを使うのもよいかもしれませんね☆

プログラム

 今回は自分には珍しくProcessing2.0対応で書きました。では早速ソースコードを。
解説は…特に無いです!まあこんな簡単なプログラムで結構良い感じの動画ができるよということです。

int size_x = 1920/2;
int size_y = 1080/2;

int rotX = -2000;
int x_move = 5;
float x_far = 5000;
float x_step = 2000;
int camera_z = 1500;

FlyScreen[] FlyScreens = new FlyScreen[24];

class FlyScreen{
  PImage img;
  String name;
  float x, y, z;

  FlyScreen(String name, float x, float y, float z){
    this.name = name;
    this.x = x;
    this.y = y;
    this.z = z;
    this.img = loadImage(name);
    int tmp_blur = (int)((camera_z*0.7 - z)/450);
    if(tmp_blur > 0){
      this.img.filter(BLUR, tmp_blur);
    }
  }

  void DrawImage(){
    image(this.img, this.x, this.y);
  }
}


void setup(){
  size(size_x, size_y, P3D);
  colorMode(RGB, 255);
  Init();
  imageMode(CENTER);
}

void Init(){
  float x, y, z;

  X_Scroll_Setup();

  background(255,255,255);
}

void X_Scroll_Setup(){
  FlyScreens[0] = new FlyScreen("tex0.jpg", x_far-2.4*x_step, float(height/2)-100, 200);
  FlyScreens[1] = new FlyScreen("tex1.jpg", x_far-2.2*x_step, float(height/2)+200, 400);
  FlyScreens[2] = new FlyScreen("tex2.jpg", x_far-2.1*x_step, float(height/2)-300, 210);
  FlyScreens[3] = new FlyScreen("tex3.jpg", x_far-1.9*x_step, float(height/2)+130, 400);
  FlyScreens[4] = new FlyScreen("tex4.jpg", x_far-1.7*x_step, float(height/2)-200, 320);
  FlyScreens[5] = new FlyScreen("tex5.jpg", x_far-1.5*x_step, float(height/2)+150, 250);
  FlyScreens[6] = new FlyScreen("tex6.jpg", x_far-1.35*x_step, float(height/2)-300, 330);
  FlyScreens[7] = new FlyScreen("tex7.jpg", x_far-1.1*x_step, float(height/2)-50, 250);
  FlyScreens[8] = new FlyScreen("tex8.jpg", x_far-0.8*x_step, float(height/2)+25, 300);
  FlyScreens[9] = new FlyScreen("tex9.jpg", x_far-0.6*x_step, float(height/2)-150, 250);
  FlyScreens[10] = new FlyScreen("tex10.jpg", x_far-0.5*x_step, float(height/2)+300, 340);
  FlyScreens[11] = new FlyScreen("tex11.jpg", x_far-0.3*x_step, float(height/2)-100, 400);
  FlyScreens[12] = new FlyScreen("tex12.jpg", x_far-2.31*x_step, float(height/2)+200, -150);
  FlyScreens[13] = new FlyScreen("tex13.jpg", x_far-2.42*x_step, float(height/2)-500, -50);
  FlyScreens[14] = new FlyScreen("tex14.jpg", x_far-1.95*x_step, float(height/2)+300, -200);
  FlyScreens[15] = new FlyScreen("tex15.jpg", x_far-1.82*x_step, float(height/2)-500, -100);
  FlyScreens[16] = new FlyScreen("tex16.jpg", x_far-1.75*x_step, float(height/2)+350, -100);
  FlyScreens[17] = new FlyScreen("tex17.jpg", x_far-1.45*x_step, float(height/2)-200, 0);
  FlyScreens[18] = new FlyScreen("tex18.jpg", x_far-1.35*x_step, float(height/2)+350, -20);
  FlyScreens[19] = new FlyScreen("tex19.jpg", x_far-1.24*x_step, float(height/2)+25, -250);
  FlyScreens[20] = new FlyScreen("tex20.jpg", x_far-1.1*x_step, float(height/2)+550, -350);
  FlyScreens[21] = new FlyScreen("tex21.jpg", x_far-0.92*x_step, float(height/2)+350, -600);
  FlyScreens[22] = new FlyScreen("tex22.jpg", x_far-0.83*x_step, float(height/2)-300, -200);
  FlyScreens[23] = new FlyScreen("tex23.jpg", x_far-0.7*x_step, float(height/2)+160, -150);
}

void X_Scroll(){
  camera(width/2+rotX, height/2, camera_z, width/2+rotX, height/2, 0, 0, 1, 0);
  rotX += x_move;

  for(int i = 0; i < FlyScreens.length; i++){
    pushMatrix();
    translate(FlyScreens[i].x, 0, FlyScreens[i].z); 
    FlyScreens[i].DrawImage();
    popMatrix();
  }
}

void draw(){
  lights();
  background(255,255,255);
  X_Scroll();

  saveFrame("frames/####.tif");
}

関連記事