Processingで人がぐにゃんぐにゃんになるスリットスキャン動画を作ってみました

f:id:karaage:20180619233817p:plain:w640

スリットスキャン動画を作ってみる

 Processingを使ってスリットスキャン動画を作ってみました。元々は「ツブゾロッタフィルム」さんの『【動画】人間が液体のようにたぷんたぷんになる不思議な映像手法「スリット・スキャン」』という記事を見て、こりゃ面白い、やってみたいなと思ったのがきっかけです。
 元記事では、Adobe AfterEffectsを使っているのですが、大抵の人はそんなソフト持っていないはずです。そんなときは「お金がないなら作ればいいじゃない」精神で、Processingというプログラミング言語を使って挑戦してみました。

スリットスキャンって何?

 スリットスキャンは、映画で使われる特殊技法です。方法に関しては、調べれば色々出てきますが、個人的にはツブゾロッタフィルムさんの元記事が一番分かりやすかったです。アナログでやると凄い難しい特殊技法になるのですが、デジタルだと実は簡単にできてしまいます。
 簡単に説明すると、下図のように映像をn分割してやり、1フレームずつ再生する時間をずらしていってやるのです。

130623_slitscan

 たったこれだけで、映像がタプンタプンになってしまうのです。では早速実例を見てみましょう。

実例(動画)

 結構たぷんたぷんでしょ?

ソースコード

 Processing使います。Processingダウンロードして下さい(バージョンは1.5.1を使って下さい)。Processingの使い方とかは「こちら」とか見て下さい。

 後は以下のソースコードコピペして実行して、好きな動画ファイルを指定するだけです。動画が作られて行くので、気が済んだところでスペースキーを押せばソースコードを保存したフォルダに「slitscan.mov」という動画が出来上がります。動画は三脚等で固定して撮った動画の方が基本的にはよい感じになります。
 この夏、低予算でSF映画を作ってみたい方、お子様の夏休みの宿題にぴったり!ご自由に使用下さい。

import hypermedia.video.*;
import processing.video.*;

int fps = 60;

OpenCV opencv;
MovieMaker mm;

// number of frame
final int N_Frame = 180;

// Frame count
int FrameCont = 0;

//Window Size
final float pic_x = 1920;
final float pic_y = 1080;

PImage[] images = new PImage[N_Frame];
PImage[] slit_images = new PImage[N_Frame];

int slitwidth;

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

  println("select movie."); 
  String moviePath = selectInput();

  opencv = new OpenCV( this );
  opencv.movie(moviePath, (int)pic_x, (int)pic_y);

  mm = new MovieMaker(this, (int)pic_x, (int)pic_y, "slitscan.mov", fps, MovieMaker.VIDEO, MovieMaker.LOSSLESS); 
  frameRate(fps);

  opencv.read();
  for(int i=0; i<N_Frame; i++){
    images[i] = opencv.image();
  }
  slitwidth = (int)(pic_y / (float)N_Frame);
}

void draw(){
  opencv.read();
  images[FrameCont] = opencv.image();

  int tmpFrame;

  for(int i=0; i<N_Frame; i++){
    tmpFrame = FrameCont + i + 1;
    if(tmpFrame > N_Frame-1){
      tmpFrame = tmpFrame - N_Frame;
    }
    slit_images[i] = images[tmpFrame].get(0, i*slitwidth, (int)pic_x, slitwidth);
  }

  for(int i=0; i<N_Frame; i++){
    image(slit_images[i], 0, i*slitwidth, (int)pic_x, slitwidth);
  }

  mm.addFrame(); 

  FrameCont++;
  if(FrameCont > N_Frame-1){
    FrameCont = 0;
  }
}

void keyPressed() {
  if (key == ' ') { 
    mm.finish(); 
    println("save movie."); 
    exit();
  }
}