Seriously.jsで動画・画像にリアルタイムエフェクトをかける方法【ほりぼーいドッキリ編】


Seriously.jsで動画・画像にリアルタイムエフェクトをかける方法【ほりぼーいドッキリ編】

みなさんこんにちは、エンジニアののびすけです。

最近はWeb上で動画背景を使った表現のサイトが増えてきてますね。Webブラウザの性能が上がってきている昨今では、(スペックにもよるのですが)ブラウザ側でそういった処理もガンガンできます。

今回はそんなリッチな表現ができる「Seriously.js」をご紹介します。

Seriously.jsとは

少し前に話題になった、動画や画像にブラウザ上でリアルタイムエフェクトを掛けることができるライブラリ。複雑なエフェクトをたくさん使えるにもかかわらず、簡単なJavaScriptの記述で操作できます。

サンプルを触ってみよう

まずは、どんなことができるのかが気になると思います。Seriously.jsの公式デモを紹介してきます。
こちらのページにデモへのリンクがあるので試してみましょう。
  
※執筆時点ではGoogleChromeで動作確認をしています。

クロップ(トリミング)

クロップ処理をリアルタイムに行えます。けっこう使いどころがあるのではないでしょうか。

ブラー

よくある表現ですね。画像や動画のぼかしをリアルタイムに変更できます。

パノラマ写真

パノラマ写真に対して、エフェクトやスケールなどをリアルタイムで変更できます。

Three.js利用

WebGLをサポートしているので、Three.jsを使ってWebGLを操作しつつ、リアルタイムエフェクトを掛けることができます。

Web Cameraを使ったサンプル

PCのWebカメラを使ってエフェクトを掛けることができます。

Seriously.jsを使ってみよう (準備)

実際に使ってみましょう。公式チュートリアルは少し分かりにくい気がしたので、独自で説明してみます。

Seriously.jsのダウンロードはこちらからできます。

ページ右下のDownload ZIPからダウンロードするか、git cloneしましょう。

$ git clone git@github.com:brianchirls/Seriously.js.git

Seriously.js本体

ダウンロードした場合、Seriously.js-master/seriously.jsを使います。

Effectsモジュール

さまざまなエフェクトがSeriously.js-master/effectsフォルダにあります。このフォルダごとコピーしましょう。

対象画像や動画

Seriously.jsでエフェクトを掛ける対象の画像や動画を用意する必要があります。
とりあえず、サンプルの色鉛筆ロボットの画像をダウンロードしておきます。

ファイルの設置

effectsフォルダ、seriously.js、require.jsを以下のように設置しましょう。

mysample
├─ img
│  ├─ pencils.jpg
│  └─ robot.jpg
│
├─ js
│  ├─ require.js
│  ├─ seriously.js
│  └─ effects
│     ├─ seriously.accumulator.js
│     ├─ seriously.ascii.js
│     └─ ・・・省略
│
└─ index.html //メインのhtmlファイル

コピペ実装でSeriously.jsを使ってみよう

index.htmlに以下のコードをコピペで貼り付けてみましょう。

<!DOCTYPE html>
<html>
<head>
  <title>Seriously.js Gradient Wipe Example</title>
  <style>
  canvas {
    display: block;
    margin: auto;
    border: black solid 1px;
  }

  img {
    display: none;
  }
  </style>
</head>

<body>
  <img id="robot" src="img/robot.jpg"/>
  <img id="pencils" src="img/pencils.jpg"/>
  <canvas id="canvas" width="960" height="540"></canvas>
  <div id="controls">
    <label>Transition <input id="transition" type="range" min="0" max="1" step="0.0001" value="0"/></label>
    <label>Smoothness <input id="smoothness" type="range" min="0" max="1" step="0.0001" value="0.1"/></label>
  </div>

  <script src="js/seriously.js"></script>
  <script src="js/effects/seriously.gradientwipe.js"></script>
  <script src="js/effects/seriously.simplex.js"></script>
  <script src="js/effects/seriously.blend.js"></script>
  <script>
  (function (Seriously) {
    // declare our variables
    var source = document.getElementById('source'),
    seriously, // the main object that holds the entire composition
    gradientwipe, // gradientwipe node
    ctx, grd,
    reformatRobot,
    reformatPencils,
    blend,
    target; // a wrapper object for our target canvas

    seriously = new Seriously();
    gradientwipe = seriously.effect('gradientwipe');
    blend = seriously.effect('blend');
    target = seriously.target('#canvas');
    reformatRobot = seriously.transform('reformat');
    reformatPencils = seriously.transform('reformat');

    reformatRobot.source = '#robot';
    reformatRobot.width = 960;
    reformatRobot.height = 540;
    reformatRobot.mode = 'cover';

    reformatPencils.source = '#pencils';
    reformatPencils.width = 960;
    reformatPencils.height = 540;
    reformatPencils.mode = 'cover';

    noise = seriously.effect('simplex');
    noise.width = 960;
    noise.height = 540;
    noise.noiseScale = [5, 5];
    noise.octaves = 3;

    gradientwipe.source = reformatRobot;
    gradientwipe.gradient = noise;
    gradientwipe.transition = '#transition';
    gradientwipe.smoothness = '#smoothness';

    blend.bottom = reformatPencils;
    blend.top = gradientwipe;

    target.source = blend;

    //render
    seriously.go();
  }(window.Seriously));
</script>
</body>
</html>

 

パソコンのローカルサーバーなどでindex.htmlにアクセスしてみましょう。
http://localhost/mysample/index.htmlなどになると思います。

デモ

メモリの位置を変更することで、2枚重なった写真のエフェクトを調節できます。

クロスドメインは注意

index.htmlにファイルアクセスしようとすると、Unable to access cross-domain imageというエラーが出て画像や動画は表示されません。Seriously.js側でクロスドメイン制御をしているみたいです。
同じサーバー(ドメイン)に画像や動画を設置するようにしましょう。

応用:複数の角度から撮影した動画を重ねよう

今回の記事を書くにあたり、ゴキブリおもちゃでドッキリ動画を作りました。

動画の関連人物

13f9be7d6a9e030491456f9eab1000ed 人物紹介:せいと
フロントエンドエンジニア。通称ほりぼーい。今回のドッキリ動画の対象者。
141e9976c95ede4a69e20e6287fd707f 人物紹介:まろ
フロントエンドエンジニア。通称まろ氏。ブログネタに困るとほりぼーいを使う。
77ae5580ee4b9fd679eb3d4d77ee4170 人物紹介:のびすけ
バックエンドエンジニア。通称のびすけ。上京するまでゴキブリは見たことがなかった。

動画内容

ほりぼーいが昼休みから帰ってきたときに、パソコンにゴキブリのおもちゃを仕込んで驚かす動画です。まろ氏は、撮影していることをほりぼーいに悟られないようにトランプタワーをしています(謎)

実装内容(デモ)

2つのカメラで撮影した動画を使ってエフェクトをかけてみます。メインの動画上にマウスホバーをすることで、もう1つの角度から撮影した動画がマスクとなって表示されます。マウスを動かすことで違う視点で動画を見ることができます。

↓動画スタート!のボタンを押すと、開始されます。

ソースコード

プロジェクトのルートにvideoフォルダを作成して、利用する2つ動画を設置しておきます。

mysample2
├─ video
│  ├─ boy_main.mov //今回使った動画1
│  └─ boy_sub.mov //今回使った動画2
│
├─ js
│  ├─ require.js
│  ├─ seriously.js
│  └─ effects
│     ├─ seriously.accumulator.js
│     ├─ seriously.ascii.js
│     └─ ・・・省略
│
└─ index.html //メインのhtmlファイル

これもコピペで使えると思います。

 

もし、動画読み込みで403エラーなどが発生した場合は以下のように権限を変更してみましょう。

$ pwd
/path/to/maysample2
$ chmod 644 ./video/*.mov

 

動画の拡張子がvideoタグで利用できるものなのかという確認もしておくと良いです。動画が動作しない場合の原因はほぼこれで解決できる気がします。

<!DOCTYPE html>
<html>
<head>
  <title>Seriously.js Channels Example</title>
  <style type="text/css">
  img, video {
    display: none;
  }
  </style>
</head>
<body>
  <button name="button" id="start_btn">動画スタート!</button>※音が出ます。Chromeなどモダンブラウザ推奨。<br/>
  <video src="./video/boy_main.mov" id="main_video"></video>
  <video src="./video/boy_sub.mov" id="sub_video"></video>
  <canvas id="canvas" width="640" height="619"></canvas>
  <script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
  <script src="./js/require.js"></script>
  <script>

  var main_v = document.getElementById("main_video");
  var sub_v = document.getElementById("sub_video");

  require.config({
    baseUrl: './js'
  });

  require([
    'seriously',
    'effects/seriously.channels',
    'effects/seriously.blend'
    ], function (Seriously) {
      // declare our variables
      var seriously, // the main object that holds the entire composition
      channels, // a split effect
      blend,
      target, // a wrapper object for our target canvas
      scaleSub,
      scaleMain,

      moveMask,
      resizeMask,
      mask = document.createElement('canvas'),
      ctx = mask.getContext('2d');

      seriously = new Seriously();
      target = seriously.target('#canvas');
      channels = seriously.effect('channels');
      blend = seriously.effect('blend');

      scaleSub = seriously.transform('2d');
      scaleSub.source = seriously.source('#sub_video');
      scaleSub.scale(440/989);

      scaleMain = seriously.transform('reformat');
      scaleMain.source = seriously.source('#main_video');
      scaleMain.width = 640;
      scaleMain.height = 619;
      scaleMain.mode = 'cover';

      //draw mask
      mask.width = 100;
      mask.height = 100;

      ctx.fillColor = 'black';
      ctx.fillRect(0, 0, 400, 400);
      ctx.fillStyle = 'white';
      ctx.fillRect(0, 0, 160, 160);

      console.log(ctx);

      resizeMask = seriously.transform('reformat');
      resizeMask.source = mask;
      resizeMask.width = target.width;
      resizeMask.height = target.height;

      moveMask = seriously.transform();
      moveMask.source = resizeMask;
      // moveMask.rotation = 30;
      moveMask.scale(0.7);

      channels.source = scaleSub;
      channels.alphaSource = moveMask;
      channels.alpha = 'red';
      channels.blue = 'green';
      channels.green = 'blue';

      blend.bottom = scaleMain;
      blend.top = channels;

      target.source = blend;

      window.addEventListener('mousemove', function (evt) {
        var canvas = target.original,
        x = evt.pageX - canvas.offsetLeft,
        y = evt.pageY - canvas.offsetTop;
        moveMask.translateX = x - canvas.width / 2;
        moveMask.translateY = canvas.height / 2 - y;
      }, false);

      $('#start_btn').on('click', function(){
        main_v.play();
        sub_v.play();
        seriously.go();
      });
    });

  </script>
</body>
</html>

基本的にはChannel Mappingのデモを参考にして書いています。

まとめ

対象とした動画はネタな感じになりましたが、最近は動画を使ったサイトが多くなってきていて、2015年トレンドとも言われているみたいです。Seriously.jsのように、簡単に動画エフェクトを行えるライブラリの使い方を覚えておくと流行の表現ができると思います。

2つの動画を重ね合わせるという表現はまだまだ一般的ではないかもしれませんが、表現したい内容によってはかなり活きてくると思いますので、参考になれば幸いです。

それでは!

 

【表現の幅を広げよう】

p5.jsでProcessingのようにリッチなWeb表現を作るチュートリアル

圧倒的な3D表現にWebの未来を感じるWebGLを使ったサイト・デモ20選

デザイナー・ノンプログラマにおすすめしたいThree.jsのカンタン3D体験

刀でズバッと斬るようなアニメーションをHTML・CSS・JS(jQuery)で実装する方法

CSS3とjQueryでオリジナル画像のスプライトアニメーションを実装する方法

この記事を書いた人

のびすけ
のびすけ バックエンドエンジニア 2014年入社
dotstudio株式会社 ( https://dotstud.io )

岩手から上京してきました。

ギークハウスを経て、現在は0円シェアハウスに住んでいます。

好きなスポーツはフットサル/雪合戦/わんこそばです。

2015年は東京Node学園で登壇してみたいです。

・milkcocoa公認エバンジェリストになりました。(https://mlkcca.com/)
・gihyo.jpで記事書いてます (http://gihyo.jp/dev/feature/01/milkcocoa-baas)
・html5experts.jpで記事書いてます。(https://html5experts.jp/n0bisuke/)