OpenCV.jsでFace Detectionを試してみた。

こんにちは。
腰を痛めて家で療養中です。あまりにも暇なので、以前から気になっていたOpenCVについて調べてみました。 んで調べてみると、OpenCV.jsなるものがあるんですね。
「ブラウザで動くじゃん、モバイルでも動くかな?」
OpenCVの勉強をするつもりが、主目的がOpenCV.jsをモバイルブラウザで動かすことに代わってしまいました。あるあるですね。
というわけで、そんな勉強がてらOpenCVのFace Detectionをブラウザで動かしてみました。

作ったもの

こんなのです。
youtu.be

もう、どうしようもないくらいカックカクですね。
ASUS ZenfoneAR(Snapdragon 821)なのでそんなにスペック悪くないですけどねー。
PC(Lenovo X260)側だとぬるぬるなので、現時点でのスマホの限界なのでしょうね。
Web Assembly化するともうちょとましになるのかな。暇になったら対応してみよう。

あと、画像がぼやけているせいか、小さな顔は認識しませんでした。寄ると認識します。

作業手順

手順というか、参考にしたサイトの羅列です。

まずここ

qiita.com

そしてそこで紹介されているここ

OpenCV: Build OpenCV.js

emsdkのインストールはここがわかりやすかった

Developer’s Guide - WebAssembly

「./emsdk install」実行後、ものすごく時間がかかるので覚悟することw

そのあと手順通りに実行していくと、
python ./platforms/js/build_js.py build_js」
を実行した後で、opencv.jsが出来上がる。
このコマンドもものすごく時間がかかります。

できたOpencv.jsを使って、チュートリアルで一番簡単そうなのを実装してみた。

OpenCV: Changing Colorspaces

問題なく動いたので、次に本題のFace Detectionです。

OpenCV: Face Detection in Video Capture

これも問題なく動いたので、あとはHTMLとかそこいらへんをいじって全画面化しています。

まとめ

Javascriptは遅い、スマホのは特にって言われているのは知っていましたが、VRとかARとか普通に動くし問題ないんじゃ?ってどこかで思っていましたが、OpenCVを動かしてみたら、カックカクだし「あー、これはだめだぁ」って思いました。
asm.jsやWebAssemblyはこれを解決しようとがんばっているのですね。一人で納得

明らかに重い処理でなければ、ブラウザ上でOpenCVが動くということは様々な使い道があるのではと感じています。
今まで画像を扱う場合、クラウド上にファイルをそのまま送信し下処理の上AIに食わせるという流れでしたが、スマホ上で下処理および軽量化したうえで送信できるので、サーバ負荷が少なくなるでしょう。サーバ側はAI処理に集中できるので良いことだと思いました。

以上

A-FrameでPositionを設定するときの書き方について

新年があけまして、今年こそは少しスリムになろうと運動を始めました。
去年も、一昨年もそうでした。果たしていつまで続くやら。

A-Frameで実装する際、PositionやらRotationやらを設定することが多いのですが、毎回書き方がバラバラで、好き勝手に書いているのが気になっています。
いい機会なので、どういうときにどういう書きかたになるのか整理してみようかと。

Positionの設定方法

entityにposition設定をする際は、大きく分けて

  1. HTML中での設定
  2. Javascript中での設定

に分かれます。

HTML中での設定

HTMLでの設定する際は考える余地もなく

<a-entity position="x y z"></a-entity>

です。
HTMLでは静的に一意に設定します。なので設定方法もこのやり方だけになります。

Javascript中での設定

こっちが面倒です。設定の方法がいくつもあります。

  1. DOMの要素として属性に設定する。
  2. Three.jsのメソッドを使って設定する。
  3. A-FrameのUtilsを使って設定する。

他にもあるかな。基本的に「DOMの要素として設定」することが多いです。
というかほかの方法はよくわかっていないので・・・
なので、これを機にそれ以外の設定方法をまとめておきます。

DOMの要素として設定

setAttributeを使います。
スペース区切りでXYZの順で文字列を作成して設定します。

var box = document.getElementById("box");

// 文字列で設定
box.setAttribute("position", "x y z")

// 連想配列形式で設定
box.setAttribute("position", {x:-1, y:-1, z:-3});

// Vector3形式データも設定できる。
var pos = new THREE.Vector3(-1, 1.5, -3);
box.setAttribute("position", pos);

単純にXYZの値を変更する際はこれが一番楽です。
ですが、例えばYだけを変更する場合、一度文字列加工したうえで設定しなければならず、とても面倒で煩雑なソースになってしまいます。

ということで、知りたいのはこれから下のThree.jsとA-Frameの部分について。
ブログを書きながら調べながら、実装して確認しながらまとめていきます。

Three.jsのメソッドを使って設定

Three.jsでpositionは3つの数値項目を保有するVector3クラスを使って表します。
Vector3の説明は以下を参照。

three.js / documentation

したがって、あるエンティティのpositionを変更したい場合、エンティティからVector3のposition情報を取得し、そのposition情報が保有するVector3のメソッドを使用して変更します。
A-Frameエンティティのpositionは、entity.object3D.positionで取得できます。

var box = document.getElementById("box");
box.object3D.position.set(-1, 2.5, -3);

設定する値がすでにVector3の場合は、こんな書きかたもできます。

var box = document.getElementById("box");
var pos = new THREE.Vector3(-1, 1.5, -3);
box.object3D.position.copy(pos);

それから、XYZのうち一部だけ変更したい場合はこんな感じ

var box = document.getElementById("box");
// メソッドを使って設定
box.object3D.position.setY(2);
// もしくはプロパティ直指定
box.object3D.position.y = 2;

A-FrameのUtilsを使って設定

A-Frameには便利なUtilityがいくつか用意されています。

Utils – A-Frame

そのうち、position設定で使えるのは、AFRAME.utils.entity.setComponentProperty です。

var box = document.getElementById("box");
AFRAME.utils.entity.setComponentProperty(box, 'position', "-1 -2 -3");
// 設定値としては上記文字列以外に、連想配列とVector3も設定可能です。

長いですね。こんな長いの打ちたくないですね。
なのでposition設定で普通はこのUtilityは使わないでしょう。
この関数は他の設定において有用なのですが、それは別の機会に。

まとめ

今までなんとなく使っていたのですが、今回まとめることによりThree.js側で使うべきか、DOM設定として使うべきかなど自分の中で使用用途に応じて切り替えることができそうです。
今まで毎回悩んでいたのが馬鹿らしくなりました。

こういうノウハウや経験則で培ってきたものってDocumentには載っていないものです。自分の知識を整理する意味でも、できるだけブログにアップしていこうと思います。

以上

MercariARハッカソンに参加してきた

こんにちは。最近週末は東京、福岡、岡山と飛び回っていることが多く、部屋がちーとも片付かないで困っています。乾燥機じゃなくて天日で布団干したいです。

MercariAR ハッカソン

さてさて、先週「MercariARハッカソン」に参加してきました。

vrtokyo.connpass.com

ハッカソン自体あまり経験がない上に、東京で、しかも最新技術のARで、たった一日で。。。
我ながら無謀なチャレンジだったなぁと。

一人では心細いし、その場で即興チームを組んでみました。そしたらなんとWebARやらA-Frameやらを知っている人(レア)。しかも同じ福岡の人!! とても心強い。

ハッカソンの様子とかは相方さんのブログがよく書かれているのでそちらをどうぞー

bibinbaleo.hatenablog.com

なので僕の方は、作ったアプリの紹介と実装について書いてみようと思います。
10時間突貫でつくりっぱソースなので、汚いのはご容赦願います。。。

作ったもの

まずはアイデア出しから始めたのですが、どうにも苦手でして。相方さんとうーんうーんと悩んでひねり出して、早一時間。ふと、
「メルカリってことで、商品紹介文をARで表示したら面白そうだね。」
「録画していろいろな角度から見せられたら説明の説得力が上がるね。」
ってことで、商品に吹き出し的なものをARで表示してみようとなりました。

作ったもの  → https://daffodil-bell.glitch.me/

f:id:sgi-don:20171219232551p:plain

専用ブラウザが必要なので、お使いになる際は以下を参考にセットアップ願います。

ソースコード

github.com

使った技術

相方さんには申し訳なかったですけど、私はUnityが使えない人間なのでWebARで頑張らせてもらいました。

WebARonARCore/ARKit/Tango をベースとして、フレームワークにA-Frameを使用。開発環境及び動作環境にglitch.comを使いました。A-Frameのコンポーネントとして、

を使っています。

環境設定からaframe-arの使い方については、吉永さん(師匠(非公認(多分怒られる)))のブログが参考になります。

tks-yoshinaga.hatenablog.com

WebARが使える環境になったところで、具体的に実装したところの説明をしていきます。

実装箇所

やってることは大したことなく

  1. 床面を認識してマーカーを表示する。
  2. 始点を選択する。
  3. 終点を選択する。
  4. コメントを入力して表示する。

順に説明していきます。

床面を認識してマーカーを表示する

index.htmlのL149~L173が実装部分です。

    // リングの位置を更新する。
    ar_raycaster.addEventListener('raycaster-intersection', function(evt) {
      var pos = evt.detail.intersections[0].point; 
      mark.setAttribute('color', 'green');
      if (line) {
        // 線描画中
        var box = document.querySelector("#sample");
        var boxPos = box.object3D.getWorldPosition();
        mark.setAttribute("position", boxPos.x+" "+boxPos.y+" "+boxPos.z);
        AFRAME.utils.entity.setComponentProperty(line, 'line.end', boxPos.x+" "+boxPos.y+" "+boxPos.z);        

      } else {
        // 線描画中以外
        mark.setAttribute('position', pos); 
      }
      
    });

    // トラッキングが外れたらマーカーを赤くする。
    ar_raycaster.addEventListener('raycaster-intersection-cleared', function (evt) {
      if (!line) {
        // Turn the mark red.  FIXME: lerp position
        mark.setAttribute('color', 'red');
      }
    });

2つのイベント内にマーカーの処理を書いていきます。

raycaster-intersection

認識した床面とraycasterが交わる座標をとってきて、マーカーの位置としています。これで床面を這うようにマーカーが移動します。線描画中は、スマホの位置・向きを基に、マーカーの位置を取得しています。

今気が付いたけど、これってraycaster-intersection内で実装しちゃだめじゃん。
床面取れなくなったら(raycaster外れたら)位置取れなくなる。
カメラにregisterComponent付けて追随させるのがよいかな。

raycaster-intersection-cleared

raycasterが外れてしまった場合、マーカーの表示を赤色にして外れたことがわかるようにします。

上の実装はコメツケAR用に線描画とかいろいろと書いてあるので、シンプルな実装を確認したい人は、aframe-arのGithubにあるReadme.mdに記載のサンプルを参考にするとよいと思います。

github.com

始点を選択する

index.htmlのL89~L110が実装部分です。

    window.addEventListener('click', function(evt) {
      if (!line && !endPos) {
        // 線描画スタート
        startPos = mark.getAttribute("position").clone();
        startCameraPos = document.querySelector('[camera]').object3D.position.clone();
        line = document.createElement("a-entity");
        line.setAttribute("mixin","lineObj");
        AFRAME.utils.entity.setComponentProperty(line, 'line.start', startPos);
        AFRAME.utils.entity.setComponentProperty(line, 'line.end', startPos);
        scene.appendChild(line);
        
        if (!box) {
          var camera = document.querySelector("[camera]");
          box = document.createElement("a-box");
          box.setAttribute("id","sample");
          box.setAttribute("position","0 0 " +startPos.distanceTo(startCameraPos)*-1);
          box.setAttribute("scale", "0.01 0.01 0.01 ");
          box.object3D.visible = false;
          camera.appendChild(box);          
        }

        mark.object3D.visible = false;

線描画は THREE.Line を使って書いています。始点、終点、色を設定するとサッと線を描いてくれる便利な子。

line – A-Frame

線描画中がわかるようにマーカーを非表示にして、変わりに適当なBOXを配置しています。
このBOXは線描画終了後に削除する予定だったけど、消す実装忘れてた。。。

線描画中は変数の「line」にエンティティが入っているので、上で説明したマーカー位置特定の際に以下のロジックに入ります。

      if (line) {
        // 線描画中
        var box = document.querySelector("#sample");
        var boxPos = box.object3D.getWorldPosition();
        mark.setAttribute("position", boxPos.x+" "+boxPos.y+" "+boxPos.z);
        AFRAME.utils.entity.setComponentProperty(line, 'line.end', boxPos.x+" "+boxPos.y+" "+boxPos.z);        

線描画中のマーカー位置情報は、床面に沿ってではなく、BOXの位置(カメラから見て常に真ん中の一定距離)に配置しています。LINEの終点も同様にBOX位置を指定します。

終点を選択する

index.htmlのL112-L116です。

      } else if (line && !endPos) {
        // 日本語入力中
        line = null;
        endPos = mark.object3D.position.clone();
        document.querySelector("#commentText").focus();

状態判定用にライン変数(line)をクリア、および終点位置を変数(endPos)に格納しています。そのままコメント入力できるよう、テキストボックスにフォーカスを合わせています。

コメントを入力して表示する

A-Frameには<a-text>~</a-text>という文字表示エンティティがあるのですが、マルチバイト文字非対応という残念無念。
さてどうしようと思ったら、相方さんがサクッと参考になるサイトを見つけてくれました。すごいね!!

vr-lab.voyagegroup.com

まずは、描画用のHTMLソース。

index.htmlのL74-77

    <!-- HTML2Canvas -->
    <div style="background: rgba(255,255,255,0.01);color: #333; width: 100%; height: 100%; position: fixed; left: 0; top: 0; z-index: -1; overflow: hidden">
      <center><div id="htmlElement" style="background: rgba(255,255,255,0.01); color: #333; font-size: 48px; width:100%"></div></center>
    </div>

このHTML表示情報をAR空間上のPLANEに張り付けています。

次は、コメントの設定とPLANEの生成

index.htmlのL133-143

    // コメント入力したら描画した線の終端に反映する。
    function inputComment() {
      var htmlElement = document.querySelector("#htmlElement");
      htmlElement.innerHTML = document.querySelector("#commentText").value;

      plane = document.createElement("a-plane");
      plane.setAttribute("position", endPos);
      plane.setAttribute("scale", "0.2 0.1 0.1");
      plane.setAttribute("material","shader: html; target: #htmlElement; opacity:0.99");
      plane.setAttribute("look-at", "[camera]");
      scene.appendChild(plane);
    }

テキストボックスのコメントを上記描画用のHTMLソースに追加。html-shaderでPLANEに張り付けています。加えて、look-atで常にカメラの方向を向くようにしています。

まとめ

細かいところは飛ばしていますが、「どんなことをしたくて、どんな実装をしているか」はなんとなくわかっていただけたのではないでしょうか。
動画をとってアップロードする機能まではできませんでしたが、アイデア出しから始まって、初めて触るARCoreの挙動に戸惑いながら、約10時間ほどでここまで作れたのは自分でもびっくりしています。

MercariARハッカソンの参加者方々の作品を拝見して回り感じたこととして、音声認識と位置共有は今後ARを使っていく上で必須機能かなぁと感じました。あと、実装をUnityに乗り換えようかと本気で迷いました。実装楽そうだし、アセットとか、サードパーティライブラリとかがそろってて、成果物の完成度が段違いですもん。超嫉妬w
ARCore機が手元にないのでまたWebVRに戻りますが、機会があればWebARでアイデア練って一週間くらい本気で作りこんで見たいです。

終わり

別視点のサブ画面を出したい in A-Frame

ハンズオンで使っている題材の迷路についてちょっと改良を加えたいなと思っていろいろとアイデアをひねってます。

1シーンを多角的視点で見るのはどうだろう?

以前、同じVR世界に複数人で集まれたらいいなと思って、複数人参加型のコンテンツをnode.jsで作ったことはありますが、逆に1つのシーンを複数視点で見れるかな?と考えました。
カメラから見る一人称視点以外にも、頭の後ろくらいから見下ろす感じの3人称視点でみれたら面白いかな~
ただA-Frameでは1シーンに配置できる(アクティブにできる)カメラは1つのみのはずだし、どうしよう。

iFrameって使えるんじゃね?

ぱっと思いついたのが、iFrameでサブウインドウを表示する方法。
様々なBlogで小窓的にA-Frameサンプルを表示しているものを、A-Frameの上に重ねられるんじゃないかと。

でも、違うシーンになるため2つのシーンの同期を考えないといけない。
WebSocketか、あるいはWebRTCか。
面倒くさいな。

で他に楽な方法はないかといろいろ調べてみると、ありました。 同一ドメイン配下であれば、iFrameもDOMとして扱えるようです。 もちろん、iFrame側から親DOM(?)もDOM操作できそう。 これは便利だ。

で作ってみたサンプルがこちら。

Hello, World! with subwindow

メイン画面はいつもの一人称ですが、サブ画面は後ろ斜め上45度から見た3人称視点となっています。 もちろん、メイン画面で動けばサブ画面も連動します。

ソース

htmlが2ファイルと、cssが1ファイルになります。
(ハテブのMarkdownのコード表記って、色とか行番号とかつかないんだな。。。)

まずはメインとなるindex.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Hello, World! with subwindow</title>
    <meta name="description" content="Hello, World! - A-Frame">
    <script src="https://aframe.io/releases/0.3.2/aframe.min.js"></script>
    <link rel="stylesheet" type="text/css" href="./css/style.css"></link>
    <script>
      // サブWindow内のユーザ情報。変数の取り回しがわからないためグローバルに持たせる。改善したい。
      var user;

      // カメラエンティティの位置情報をサブWindowのユーザと同期させるコンポーネント
      // コンポーネント名がキャメル形式だと動いてくれない不思議。
      AFRAME.registerComponent('sync-user', {
        schema: {
          userId: {default: "userPosition"},
        },

        init: function() {
          this.camera = this.el;
          var userId = this.data.userId;
          document.getElementById("iframe").onload = function(e) {
            var doc = this.contentDocument;
            // TODO:このuser変数をAFRAME.registerComponent内のスコープにできないか?
            user = doc.getElementById(userId);
          }
        },

        tick: function(e) {
            if ((typeof user !== "undefined") && (user != null)) {
              var pos = this.camera.getAttribute("position");
              var rot = this.camera.getAttribute("rotation");
              user.setAttribute("position", pos);
              user.setAttribute("rotation", {"x":0, "y":rot.y, "z": 0});
            }
        }
      });
    </script>

  </head>
  <body>
    <a-scene id="sceneId" class="aframe-scene">
      <a-entity id="camera" camera="userHeight: 1.6;" look-controls wasd-controls sync-user="userId: userPosition"></a-entity>
      <a-box id="box" position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
      <a-sphere id="sphere" position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
      <a-cylinder id="cylinder" position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
      <a-plane id="plane" position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
      <a-sky color="#ECECEC"></a-sky>
    </a-scene>
    <div class="subwindow">
      <iframe id="iframe" src="./index2.html" />
    </div>

  </body>
</html>

次にサブ画面側のindex2.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Hello, World! - A-Frame</title>
    <meta name="description" content="Hello, World! - A-Frame">
    <script src="https://aframe.io/releases/0.3.2/aframe.min.js"></script>
  </head>
  <body>
    <a-scene id="sceneId" class="aframe-scene" vr-mode-ui="enabled: false">
      <a-sphere id="userPosition" position="0 0 0" rotation="0 0 0" radius=0.25 color="#0000FF">
        <a-entity position="0 3 3" rotation="-30 0 0">
          <a-entity camera="userHeight: 0"></a-entity>
        </a-entity>
      </a-sphere>
      <a-box id="box" position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
      <a-sphere id="sphere" position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
      <a-cylinder id="cylinder" position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
      <a-plane id="plane" position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
      <a-sky color="#ECECEC"></a-sky>
    </a-scene>
  </body>
</html>

最後にサブウインドウの位置などを決めるcss

@charset "utf-8";

.aframe-scene{
    position: absolute;
    z-index: 1;
}
.subwindow{
    position: absolute;
    top: 10px;
    left: 10px;
    width: 300px;
    height: 200px;
    padding: 10px;
    z-index: 3;
}

改善したいところ

このままでも動きますが、何とか改善したいポイントが2点あります。
どなたかヒントだけでもいただけるとありがたいです。

  1. グローバル変数の除外
    iFrameの読み込みが遅いため、コンポーネントのinit内でiFrameのonload終了後にiFrameのDOMを持ってくるように実装しています。
    その際、変数の受け渡しがわからないため、グローバルに変数を持たせて、tick内で利用しています。
    コンポ―ネント内で閉じた変数にできれば汎用性が高まると思うのですが、変数の引き渡し方がわかりません。

  2. コンポーネントのupdateは何の契機で動く?
    tickにて毎フレーム毎にサブ画面SCENEと同期をとっていますが、初めはEntityのPositionやRotationが変更された契機で動きそうなupdateで実装していました。ですがupdateだと動かなかったです。というかsetAttributeなどを使ってEntityを更新してもupdateが動くことはありませんでした。
    何か条件が足りないのでしょうか?

RICOH THETA Sの画像ビューアーを作ってみた

Thetaで撮った画像はふつうの画像ビューアーでは見れません。
いや見れるけど、上下がノビノビのメルカトル図法です。
やっぱり360度天球画像として見たいですよね。

ということで、JPEG画像を360度全天球画像として参照できるビューアーを
作ってみました。

ビューアー

http://theta360test.azurewebsites.net/theater.html

使い方

サイトにアクセスして、左下にある「ファイルを選択」をクリック
出てきたダイアログから、画像を選択します。
しばらくすると360度天球画像を見ることができます。

残念ながらいくつかのブラウザでは動きません。
動作確認が取れているものは

以下のブラウザでは動きません。

上記以外は未確認です。Macとか触ったことないし。

せっかく撮った写真ですから、みんなに見てもらいたいですよね。
気軽に使ってもらえればありがたいです。

RICOH THETA Sでバイクの走行中動画を撮影(自撮り)する

RICOH THETA Sを買う前からやりたいことがありまして。
それはバイクの車載動画の撮影です。
バイクに設置したThetaで、360度のバイク動画を撮影したら楽しいだろうな~って。
今回、設置するための道具もそろったところで、いろいろなところにThetaを設置して
どのような動画がとれるか確かめてみました。

設置場所

設置できる場所はいろいろとあるが、今乗っているSUZUKI Bandit1200Sで設置できる場所で絞り込んでみた。

f:id:sgi-don:20160723232053j:plain

  1. ミラー
  2. ハンドルバー
  3. エンジンガード
  4. パニアケースの上
  5. 後ろタイヤ横

こんなもんかな。
ほかに、エンジン前、前輪横、ヘルメットの上、ナンバープレートのさらに後ろ など
様々な設置場所は考えているが、オーソドックスなところから攻めることにした。

設置するために必要な道具

今回の撮影に伴い、設置のためにRAM MOUNTというパーツを使ってみた。

RAMMOUNT タフ・クローS ARAP-B-400U

RAMMOUNT タフ・クローS ARAP-B-400U

すでにスマホのマウントでRAM MOUNTは使っていますが、がっちり固定されてスマホが落ちることや振動でずれることもなくとても快適。
Thetaの設置もこれがベストだろうと思っている。

設置方法

見てもらったほうが早いだろう。順にどうぞ。

1. ミラー

f:id:sgi-don:20160723232114j:plain

2. ハンドルバー

f:id:sgi-don:20160723232121j:plain

3. エンジンガード

f:id:sgi-don:20160723232130j:plain

4. パニアケースの上

RAM MOUNTパーツ+自撮り棒で、Thetaを上方向に伸ばしている。
伸ばせば伸ばすほど、ブレて見づらくなるだろうから、どの程度まで
許容できるか?

f:id:sgi-don:20160723232152j:plain

一番縮めた状態

f:id:sgi-don:20160723232158j:plain

一番伸ばした状態

f:id:sgi-don:20160723232204j:plain

伸ばした状態の見た感じ、ちょっと異様だな。
これだけ伸ばしてしまうと、どうせブレブレ見てられない動画になるんだろうな、と、この時は思っていました。

5. 後ろタイヤ横

Thetaを逆さにつけています。
Thetaは天頂補正があるため、本体が逆さでも出力結果は天井が上にくるよう補正されます(画像、動画ともに)。すごいね。

f:id:sgi-don:20160723232209j:plain

撮影結果(画像)

動画撮影の前に、360度画像がどのように見えるか確認します。

1. ミラー

前方の視界が開けて見やすいですね。
あと、バイクと乗っている人が一緒に撮影できているので、この構図が好きな人にはお勧めです。
この位置だと、やっぱり顔は映りますね。(なんか俺、変な顔)

ThetaSでバイクの撮影(自撮り)を行う。 1. ミラーに設置 - Spherical Image - RICOH THETA

2. ハンドルバー

乗っている人に近い視点で撮影できます。
計器類も一緒に映るので、気にする人は気にしますかね。
カウルがある車種だと、Thetaを雨風・小石・虫などから守ることができます。これ結構重要だと思っています。

ThetaSでバイクの撮影(自撮り)を行う。 2. ハンドルバーに設置 - Spherical Image - RICOH THETA

3. エンジンガード

下からのアングルで撮影となります。
360度画像になると、エンジン超じゃまですね。

ThetaSでバイクの撮影(自撮り)を行う。 3. エンジンガードに設置 - Spherical Image - RICOH THETA

4. パニアケースの上

パッセンジャー目線での撮影になります。
自撮り棒の長さにより、低~中~高の3種類撮ってみました。

まずは低

ThetaSでバイクの撮影(自撮り)を行う。 4. パニアケース上に設置(低い) - Spherical Image - RICOH THETA

次に中

ThetaSでバイクの撮影(自撮り)を行う。 4. パニアケース上に設置(中) - Spherical Image - RICOH THETA

最後に高

ThetaSでバイクの撮影(自撮り)を行う。 4. パニアケース上に設置(高い) - Spherical Image - RICOH THETA

高を見た後で低を見ると、すごい落差ですね。

5. 後ろタイヤ横

後ろの人を撮影するようでしょうか。だったらThetaでとる意味ないような。
とりあえず、動画撮影だけはしてみましょう。

ThetaSでバイクの撮影(自撮り)を行う。 5. 後ろタイヤ横 - Spherical Image - RICOH THETA

撮影結果(動画)

これも見てもらったほうが早いですね。どうぞー スマホで見ている人は、youtubeアプリで見ると360度天球動画としてみることができます。

1. ミラー


ThetaSでバイクの撮影(自撮り)を行う。 1. ミラーに設置

2. ハンドルバー


ThetaSでバイクの撮影(自撮り)を行う。 2. ハンドルバーに設置

3. エンジンガード


ThetaSでバイクの撮影(自撮り)を行う。 3. エンジンガードに設置

4. パニアケースの上

はじめは一番低い位置で、動画の真ん中あたりで、最高位置まで伸ばして動画撮影しています。


ThetaSでバイクの撮影(自撮り)を行う。 4. パニアケースの上に設置

5. 後ろタイヤ横


ThetaSでバイクの撮影(自撮り)を行う。 5. 後ろタイヤ横

まとめ

自撮り棒を思いっきり伸ばした状態での撮影が、思ってた以上に面白い。
伸ばしたほうが逆にブレずに見やすくなるなんて思ってもみなかったし、
自分の走行中の姿を上空2mちょい後ろのところから見るなんて
普通できないですし、しかもそれが360度全方位撮影できてしまう。

カメラ全般そうですが、レンズに傷や汚れがついてしまう場合があります。
今回の撮影でも、レンズに虫がついてしまいノイズが混じってしまいました。
(エンジンガードの撮影の途中からです)
折角撮影したけど、虫がついていて台無しにならないように、こまめに確認しながら
撮影したほうがよさそうですね。
f:id:sgi-don:20160723232215j:plain

おわり

Ricoh Theta Sの活動限界

Thetaとともにバイクに乗って動画撮影することが多いのですが、毎回電源ON/OFFするのがとても面倒。しかも最近ハードケースをGETしたのですよ。
こんなの、

THETA用ハードケース TH-1 防滴 ポリカーボネート製 6910717

THETA用ハードケース TH-1 防滴 ポリカーボネート製 6910717

これに入れてると、撮影したいときにいちいちバイク止めて、ケースから取り出して、電源ON/OFFなんてもう正気の沙汰ではない。
もういっそ電源ONのままでいいんじゃと思った。が、こいつの活動限界はどのくらいなんだろう?と事前に知っておく必要があるな。
と思いたって、電源つけっぱなしでどのくらい持つのか確認してみました。

活動限界

いきなり結論

活動時間: 約2時間(動画撮影: 合計32分30秒、写真撮影: 1枚)

これだけ持つなら、乗ってる間は電源つけっぱなしでもいいかな。 バイク降りたら、モバイルバッテリーで充電必須だな。
#あれ?Thetaってモバイルバッテリーで充電できたっけ?

数々の問題が

つけっぱなしにしてみてわかったのですが、こいつ熱い。「温かい」ではなく、「熱い」
TH-1に入れてつけっぱなししてたら、熱暴走で電源切れやがった。(走ったのは夜の10時なのに)
何のためのケースだよ。熱で内側曇ってるし、だめじゃ~ん。

防滴はあきらめて通気口を開けようかな。ついでに充電できるような穴もあけたら便利かも。構造的にむずかしそう。