自習室

こもります

CreateJS で背景前景ともに動かしながら曇りガラス的表現をする

はじめに

磨りガラスってこんなかんじ。

f:id:AMANE:20150113153912j:plain

photo by Johnny Jet

友人氏がそういうのをやりたい、と言っていたのを思い出してやってみました。

完成品はこちら

コード

あげてあります

環境

  • EaselJS 0.8.0

参考にしたもの

Cacheについて

DisplayObject.cache() は、オフスクリーンレンダリング用に document.createElement('canvas') して、そこにデータを書き込む操作で、そこに書き込んだ物をなんども使い回したり、できあがった画像全体にポストエフェクトを掛けたりするのに使います。

上記ブログでは、DisplayObject.cacheCanvas でオフスクリーンレンダされている画像にアクセスできることが説明されています。スーパーナイスです。

blurのかけ方、マスクの仕方

上で先に書いちゃいましたが、.cache() 関数でオフスクリーンレンダした結果に対して、ブラーをかけたりできます。

このサンプルではDisplayObject.maskcreatejs.Shape のオブジェクトを登録することで、Shapeの形状に切り抜いています。graphics.drawHOGE() で描ける単純な形状で抜きたい場合はこちら。

こちらの AlphaMaskFilter では、 フィルタになるアルファを持った絵を作り(最終的にcacheCanvasを入力に使うので、Shape等にかぎらない)、そのアルファチャネルを使って対象のDisplayObjectにマスクをかけます。アルファを持つ画像等をもとに複雑なマスキングをしたい場合はこちら。

最後に

今回やっていること図示するとこんな感じです。詳しくはコードをご参照ください。

f:id:AMANE:20150117214412p:plain

ブラー元の画像を作って cacheCanvas で引っこ抜くために 1キャッシュ, ブラーをかけてマスクで抜くためにもう1キャッシュ、計2キャッシュ使いそれらを毎フレーム更新するのでやや重いのが問題です。

どうにか改善したいのですが…

html から node.js を介して oF の画像処理をコントロールし、ブラウザ上で閲覧する

はじめに

前回の記事で ycapture を使って、oF の描画内容を Windows のビデオデバイスとして流すことで、ブラウザからも見ることが出来るようにする手法について紹介しました。

前回やったことを図でまとめるとこんな感じ(再掲)

f:id:AMANE:20150111151631p:plain

ブラウザからoFアプリをコントロールする

今回はそれを発展させて、HTML側からカメラエフェクトを変更・調整できるようにしてみます。

できあがりはこんな感じ。ブラウザから、ネイティブアプリ(oF)に指令を送って、エフェクトを調整しています。

完成時のシステムは以下の様になります。

f:id:AMANE:20150112093523p:plain

ブラウザで選んだエフェクトの種類や強度の情報をWebSocket で Node.js にわたし、 Node.js からは OSCでリレーしてエフェクトの種類の情報をoFに渡します

環境とつかったもの

  • Windows 7
  • Visual Studio Express 2012
  • openFrameworks v0.8.4
    • ofxOSC
    • ofxCv
    • ofxOpenCV
    • ycapture.dll
  • node.js v0.10.29
    • node-osc
    • express
    • socket.io

あげてあります

今回のコードは、 node.js(およびhtml) の部分と、 oFの部分で二つに分けてアップしてあります。 oFのプロジェクトは ycapture の存在を前提にしているので、前回の記事を参考に導入してみてください。

ycapture に関しては前回記事参照

ycapture をつかって画像処理の結果を windwos のビデオデバイスとして流すやり方については、前回から変わっていません。今回は、三つの登場人物間で増えた通信部についてメモをしておきます。

html - node.js 側

  • NORMAL(エフェクトなし)
  • CANNY (エッジ抽出)
  • BLUR (ぼかし)

ラジオボタンを選択すると、どれが選ばれたかをNode.js 側に伝えます。

また、CANNY と BLUR については、その効果の効きをレンジスライダーで調整してNode.js側に伝えます。

これらの通信には、エフェクトの効きをリアルタイムに反映させたかったので、WebSocket(Socket.io) を利用しています。Socket.io の使い方については特殊なことはしていないので、ソースコードをご参考下さい。

要素使いこなし

<p><label>THRESH1<input type="range" name="canny_thresh1" min ="1" max="400"></label></p>
// 1~400 の間を、1刻みで選択出来る。

<p><label>SIZE<input type="range" name="blur_size" min="1" max="201" step="2"></label></p>
// 1~201 の間を、2刻みで選択出来る

後者が特徴的です。ofxCv::blur は内部的に cv::GaussianBlur を呼んでいて、ガウシアンカーネルサイズは奇数で無くてはいけません。そこで、上記のような指定にすることで、<input> の出力を奇数に限定しています。

また、<input type="range"> 要素は、value が string となっているため、Socket.io で送り込む際に、number要素に変換しておきます。

document.cv_effect.blur_size.oninput = function() {
  // ドラッグ中も数値を取りたかったら oninputを使う
  // リリース時のみ取りたかったら onchange
  socket.emit('blur size', parseInt(this.value));
}

node.js - oF 側

node.js 側

Socket.io でブラウザから送られてくるメッセージをoscに載せ替えて送り出しています

  socket.on('blur size', function(value){
    oscclient.send('/blursize', value);
  });

oF 側

OSCのメッセージを受け取って、CVのエフェクトを切り替えたり、効果の強さを調整したりします

// ofApp.cpp

while(oscReceiver.hasWaitingMessages()){
  ofxOscMessage m;
  oscReceiver.getNextMessage(&m);

  std::string oscaddress = m.getAddress();

  if(oscaddress == "/changeeffect"){
    std::string typeStr = m.getArgAsString(0);
    if(typeStr == "non") {
      effectType = EffectType::NONE;
    } else if(typeStr == "canny" ) {
      effectType = EffectType::CANNY;
    } else if(typeStr == "blur" ) {
      effectType = EffectType::BLUR;
    } else {

    }
  } /*中略*/ else if(oscaddress == "/blursize") {
    blurSize = m.getArgAsInt32(0);
  }

  // このあと effectType や blurSize を使う
}

追記

本記事の投稿後、 凹先生から助言をいただきました。

ofxLibWebsockets 試してみたところ確かにお手軽に oF 上で WebSocket が扱えて、Node.js が不要になるので良いと思いました!

最後に

WebRTC を使ってビデオチャットにする

今回は扱っていませんが、今回の物に PeerJS (WebRTC)を加えると、画面エフェクトが可能なビデオチャットシステムが完成しますね。

他プラットフォーム

前回ご紹介した内容は、デバイスやOSの仕組みが関わるところだったので Windows 限定でしたが、今回ご紹介した内容は node.js と oFのaddonで出来るので、すべてのプラットフォームで実現可能です。 前回の記事で言う ycapture の仕事を linuxやMac OSX でやる手法についても、前回の記事の最後に調査だけしてあるので、それと組み合わせることで、他のプラットフォームでも同様の機能を実現できるのではと思います。

ycapture で OpenCV での処理結果を Windows のビデオソースとしてブラウザに流し込む

はじめに

WebRTC を使ってビデオチャットアプリを作る際に、ビデオ画像にエフェクトをかけたくなりました。モザイクとか、ブラーとか、漫画カメラとか。

ブラウザ上でJavaScriptでごりごり画像処理をするのはさすがに厳しそうですので、画像処理を行うのは別のアプリケーションで行うことにしました。

最終的に WebRTC で MediaStream として扱うことを考えると、画像処理の結果が通常のWebカメラと同様に navigator.getUserMedia() できれば一番手っ取り早いんじゃないかなーと思っていろいろ手法を探してみました。

便利なソフトを教えていただいた

しかし調べれば調べるほど、Windows上だと DirectShowのお勉強しなきゃとかつらそうな気配が漂っていたのですが、Twitterに泣きついたところ、@jnakano さんが ycapture(わいきゃぷちゃ) の存在を教えて下さいました。

ycapture(わいきゃぷちゃ)

説明から引用

ycaptureとは、WindowsのVideo Capture Sourceのような振る舞いをするDLL(の基本ソース)です。このDLLを使用すると、あたかもビデオキャプチャデバイスのように、任意のプログラムからビデオデータを供給することができます。

これだー!と言うことで、今回試してみました。開発者の谷沢さん、ありがとうございます。

開発の前に

今回やりたいこと

f:id:AMANE:20150111151631p:plain

  1. openFrameworks 上で、OpenCVを使ってカメラ画像を処理し、
  2. ycapture.dll からWindowsのビデオデバイスとして流します。
  3. ブラウザで navigator.getUserMedia() でストリームを取得します

注意

今回のアプローチがベストかどうかはケースバイケースだと思うので、手法の一つとしてご参考にしていただければと思います

環境

ycaptureのビルドは、

の2つの組み合わせで確認しています。openFrameworks に関しては、Visual Studio 版が 2012(v110) にしか対応していないため、今回のシステム全体としては、Visual Studio 2012 を利用しています。

ycapture の準備

公式に載っている利用法に従って下さい。公式ページでは VS2008で、と書いてありますが上記の通りの環境でもビルド & 利用可能でした。以下、ポイントだけメモっておきます。

Release か Debug か。ビルドの種類とパスの設定に注意。

Visual Studio は ライブラリ類のパスを通すのが面倒なので、私は Release ビルドに統一してやっています。Visual Studioのプロパティをいじる際は、毎回 Configuration の表示に気をつけましょう。

f:id:AMANE:20150111092217p:plain

Windows SDK を導入し、DirectShowの baseclasses をビルドして静的ライブラリを作る

Windows SDK アーカイブ – Windows デベロッパー センター

今回はこちらの Windows 7 および .NET Framework 3.5 SP1 用 Windows SDK を使っています。

baseclasses ライブラリのソリューションを Visual Studio 2012(2013) で開こうとすると、変換の際に大量の警告が出ますが、ビルドは出来ます。

配布されている ycapture プロジェクトのビルド準備

ycaptureプロジェクトのプロパティで、インクルードやリンクがうまくいくよう設定を変更します。先述の DirectShow/baseclasses の在処を教えてあげます(配布された状態だと、Windows SDKのバージョンが違ったりしています)

私の場合は以下の通り

  • 追加のインクルードディレクトリ
    C:\Program Files\Microsoft SDKs\Windows\v7.0\Samples\multimedia\directshow\baseclasses;

  • 追加のライブラリディレクトリ
    C:\Program Files\Microsoft SDKs\Windows\v7.0\Samples\multimedia\directshow\baseclasses\Release;

これでビルドが出来ます。

ycaptureclient と testclienet のビルド

この二つは、配布状態のままでビルド可能です。

testclientは、ソリューション内でycaptureclientに対してプロジェクトの依存関係が組まれているので、特にライブラリの場所とか気にしなくて大丈夫なようです。

ycapture.dll の登録

regsvr32.exe を使ってdllを登録する際は、 powershell/cmd を管理者権限で立ち上げないと怒られます。

>regsvr32.exe ycapture.dll

サンプルを試す

ycapture で配布されている testclient で、以下の流れが確認出来ます。

  1. testclient を起動します。
  2. 受け側として、ブラウザで https://simpl.info/getusermedia/sources/ を開きます。 navigator.getUserMedia のサンプルアプリです。
    受け側はSkypeなどのアプリでももちろん大丈夫です。
  3. 画面に、testclientが流している赤い帯が表示されれば成功です

f:id:AMANE:20150111151857p:plain

testclient が生成するカメラが見つからないときがある

ドライバの読み込み順の関係かキャッシュか正確なことは分かりませんが、作った仮想カメラがクライアントから見つからないことがあります。こういうときは、ページのリロードや、既に刺さっているウェブカムの抜き差しなどをすると、見つかるようになります。

ycapture を oF 内で利用する

ycapture を oF 内で利用する事で、oF での描画結果やCVを使った画像処理の結果を、仮想カメラデバイスとして流すことが出来るようになります。

プロジェクトの準備

ここでは Visual Studio での oF プロジェクトの生成等については割愛いたします。

以下の点をプロジェクトのプロパティに設定していきます

  • baseclasses/ycapture のビルドにあわせて、configuration を Release にする
  • 追加のインクルードディレクトリに、ycaptureとycaptureclient のソースコードがある場所を追加する
<ycaptureをおいた場所>\ycapture-src-0.1.1\ycapture\ycaptureclient
<ycaptureをおいた場所>\ycapture-src-0.1.1\ycapture\ycapture
  • 追加のライブラリディレクトリに、ycapture/ycaptureclientのビルド結果がある場所を追加する
<ycaptureをおいた場所>\ycapture-src-0.1.1\ycapture\Release
  • ライブラリの入力に、以下の物を追加する
ycapture.lib
ycaptureclient.lib

コード

ycapture さんで配布されているtestclient を参考に書いていきます。

// ofApp.h

// 前略
#include "ofxCv.h"
#include "CaptureSender.h"
#include "ycapture.h"

class ofApp : public ofBaseApp {

public:
  // 中略
  ofVideoGrabber cam;
  ofImage raw;
  ofImage blur;
  CaptureSender *sender;  // ycaptureのオブジェクト
};
// ofApp.cpp
int CAM_WIDTH = 640;
int CAM_HEIGHT = 480;
unsigned long avgTimePF = 1000 / 30;    // 30fps ストリームのタイミングを作るのに使うらしいが詳細不明

void ofApp:setup(){
  cam.initGrabber(CAM_WIDTH, CAM_HEIGHT); // カメラの初期化
  sender = new CaptureSender(CS_SHARED_PATH, CS_EVENT_WRITE, CS_EVENT_READ); // ycaptureのセットアップ
  // 後略
}

void ofApp::update(){
  cam.update();

  if(cam.isFrameNew()){
    raw.setFromPixels(cam.getPixels(), CAM_WIDTH, CAM_HEIGHT, OF_IMAGE_COLOR); // カメラ画像をコピー
    raw.mirror(1, 0); // そのまま送るとブラウザ側で垂直方向に反転する
  
    ofxCv::blur(raw, blur, 51); // ブラーをかけてみるテスト
    HRESULT hr = sender->Send(counter * avgTimePF, CAM_WIDTH, CAM_HEIGHT, blur.getPixels() ); //★★ここがポイント★★
    // 後略
  }
}

void ofApp::draw() {
  cam.draw(0, 0);
}

要するに、何かしらの方法で画像を作った後、 RGBの順の unsigned char 配列にして、sender->Send() すれば良いようです。oFやCVには、RGBの順の unsigned char 配列 への変換関数が用意されているので楽ちんです。

さいごに

ウェブブラウザ上で、oFで処理した結果の画像が見られれば完成です。oFのウィンドウに表示されているカメラのスルー画と並べて見ても、遅れは感じられません。良い感じ。

f:id:AMANE:20150111104337j:plain

次は、せっかくブラウザ上でやっているので、ブラウザでのユーザの入力を受け付けて、エフェクトを変更したりする仕組みを作ってみようと思います。

他プラットフォーム

Linuxの場合

余り詳しくないので間違いがあるといけないのですが、、Linux環境だと、gstreamer や V4L2loopback といったモジュールを使うと、割と簡単に動画ストリームをビデオデバイスとして取り扱うことが出来るようです。実際、openFrameworksの addons に arturoc/ofxGstV4L2Sink · GitHub と言う物があって、リポジトリのREADMEによれば、

Uses v4l2sink gst element to create a virtual device which can be used as a camera in any application that supports v4l2

とのことで、今回狙っていることが出来そうです。ただし私は試していません。

Mac OSX の場合

rsodre/ofxFakam · GitHub と言う物があり、これも

ofxFakam is an Open Frameworks addon that streams screen data to a fake camera driver.

ということで、狙っていることが出来そうです。ただし私は試していません。

FFmpegで WebM の半透過動画を作成し、Chromeで再生する

はじめに

f:id:AMANE:20141216172917j:plain

ウェブアプリで画面全体にわたるようなリッチなエフェクトを掛ける手段のひとつとして、デザイナさんに作ってもらう動画(たとえばAfter Effectsで)をそのまま使う、なんてことは出来ないかと考えてトライしてみました。

HTML要素の上に半透過の動画を <video> 要素で置くことで、もとのHTMLを動画で演出、みたいなことができています。

f:id:AMANE:20141216134814p:plain

できあがった物はこちらで確認出来ます

ブラウザは Chrome しか対応しておりません!ご注意。

環境

ちなみに、WebM を透過して表示できるのは、PC/MacChrome だけのようです。悪しからず。

Firefox@Mac だと、アルファチャンネルが捨てられて、全画面カラフルに塗りつぶされます

Safari@Mac だと、そもそも再生されません

元ネタ

今回の記事は、こちらの記事を足がかりに、追加でいろいろ調べてまとめた物になります。

動画の作り方

普段からデザイナさんに After Effects で動画を作ってもらっているので、この記事では After Effects を使ってにアルファ付き WebM 動画を作ってみます。

もしかしたら最新の After Effects では既にアルファ付き WebM の書き出しに対応しているかもしれませんが、私が使える 5.5 では出来なかったので、エンコードには FFmpeg に梱包されている vp8 (libvpx) を利用します。

f:id:AMANE:20141216152454p:plain

After Effectsコンポジション作成

新規プロジェクトから普通にコンポジションを作成し、そこに要素・アニメーションを加えていきます。半透過のテストをしたかったので、アルファが変わったり、淡いグラデーションがかかっているような動画を作ろうと思い、今回はこちらの記事を参考にサンプルを作ってみました

WebM は 60fps にも対応しているので、コンポジションのフレームレート設定を 60fpsにしました。

背景はデフォルトの黒です。

f:id:AMANE:20141216173304j:plain

After Effects でアルファ付き QuickTime Movie 書き出し

FFmpegでWebMにエンコードする元になる、アルファ付きの動画を出力します。AVI と QuickTime形式がアルファ付きに対応しているようですが、AVIだと尋常じゃない容量になるので、QuickTimeで書き出しますことにします。

対象のコンポジションを選択した状態で コンポジション > レンダーキューに追加 を選ぶと、レンダーキューウィンドウにひとつ、レンダリング処理が追加されます。

そのレンダーキューの "出力モジュール" を選択して、下記のような設定にします。ポイントは以下の3点です

  • 形式: QuickTime
  • チャンネル: RGB + アルファ
  • カラー: ストレート(マットなし)

f:id:AMANE:20141216142307j:plain

カラーを「合成チャンネル(マットあり)」 にすると、アルファチャンネルだけで無く、RGBのレイヤーも調整された動画が描き出されます。 出力された MOV ファイル単体を QuickTime で再生するときはこれで良いのですが、WebM にエンコードして他の画面に合成した際に、色味が暗い感じになってしまいます。

ストレートアルファとプリマルチプライド・アルファ(合成チャンネル)の違いは、こちらのページが詳しいです

あとは、出力先で適当に場所を決め、ファイル名を決めてレンダリングを行います。

FFmpeg で WebM にエンコード

インストール

FFmpegは別途インストールしておいてください。 Windowsの場合は、binaryをダウンロードしてきて、どこか適当な場所に解凍し、システム環境変数の path に、ffmpeg/bin のパスを通すと、コマンドプロンプト/PowerShell からコマンドをたたけるようになります。

エンコード

先ほど出力した mov ファイルのあるディレクトリに移動後、以下のコマンドでエンコードを行います。

ffmpeg -i webmtest.mov -crf 10 -b:v 1M webmtest.webm

オプションはいまいちよく理解出来ていないのですが、下記サイト様に説明が載っています。要は、オプション指定しないと結構画質が悪くなるので、VBR(可変ビットレート) の目標値 (1Mbits/s) と、VBRする際の最低品質保障 (4-63 での 10) を指定してね、という感じみたいです。

これでアルファ付きの WebM 動画ファイルが書き出されました。このファイルは、 Chrome にぽいっと投げ込むと、その場で再生してもらえます。が、背景がとくにないので真っ黒に表示され、このままでは透過できているのか分かりません。

f:id:AMANE:20141216173420j:plain

再生

というわけで、背景と適当なHTML要素を加えた上に透過動画をおいてみたのが、一番初めの作例になります。

再掲 → webm transparent test

画質優先で連番.tga を使う場合

AfterEffects から QuickTime(MOV) で書き出した時点で、圧縮率を最低にしたとしても、最終的なWebMにたどり着く前に何かしらの圧縮が入ってしまっていることになります。画質最高とは言えません。

そこで、一度無圧縮のアルファチャネル付き連番画像を書き出し、それから アルファ付き WebM をエンコードする、というパスを取ることもできます。

f:id:AMANE:20141216152504p:plain

連番 TGA 書き出し

新しいレンダリングキューを作成し、出力モジュールを以下の様に設定します。

  • 形式:Targa シーケンス
  • チャンネル: RGB + アルファ
  • カラー: ストレート(マットなし)
  • 形式オプション
    • 解像度 32bits/pixel (アルファチャネル付き)
    • 圧縮はなし!

その上でレンダリングすると、だだーっとTGAファイルが書き出されます。1920x1080、32bit ですと 1枚 8MB ほどもあるのでかなりつらい感じになります。。。

f:id:AMANE:20141216150852j:plain

連番 TGA から WebM にエンコードする

入力を、 MOV から 連番tga に変えるだけです。

ffmpeg -r 60 -i webmtest_%05d.tga -crf 10 -b:v 1M webmtest.webm

tga ファイルのサイズは膨大になりましたが、vp8 としては同じ圧縮を行うので、最終的に出てくる WebM ファイルの容量は、MOV を経由した場合と同程度になります。

さいごに

Chrome 限定な上、 WebM ってぶっちゃけそんなに流行っている気配も無いので、この手法もこれといって使えるシーンが無い可能性は大きいと思います。

けどせっかくちゃんと出来るようになったので、まとめておきました。ちゃんちゃん。

(タブレットで) 鏡餅を光らせて新年を迎えましょう | 実装編

はじめに

前回は、おうちハック Advent Calendar 2014 向けとして記事を書きました。そちらでは全体の紹介と、取り組んだ背景みたいなところにフォーカスして書いたので、今回は自分向けに実装で手こずったところ等をメモしていきます。自分用のメモなので雑多でごめんなさい。

目次

  • socket.io でルーム管理。おもち側が閉じたら、繋いでいるコントローラに伝達する仕組みなど
  • 様々なブラウザ・解像度への対応 (軽めに…
  • さくらのVPSに Node.js アプリをデプロイする際のTips
  • そのほか細かい技

おさらいのコード

記事中にコードを展開していくとバカ長くなりそうなので、言及場所にリンクを貼るスタイル。

おさらいの動画

おさらいのシステム図

f:id:AMANE:20141225104949p:plain

socket.io でルーム管理。おもち側が閉じたら、繋いでいるコントローラに伝達する仕組みなど

前回の記事でもちらっと書きましたが、今回の案件、本来なら(おそらく) WebRTC を使ってやるべき案件です。光る端末に対し、リモコンが直接指示を出します。基本は1対1で、始まった後は間にサーバが挟まっている必要はありません。

しかし今回は、自分の不勉強のため短いスパンで WebRTC を使いこなせそうになかったので、使ったことのあるsocket.io を使い、間にサーバが挟まるシステムにしました。そのため、利用者が増えると明らかに不利です。アドベントカレンダー向けのネタアプリですので勘弁してください。

そんな中でも一応こだわって頑張った辺りについてメモしておきます。

room名によるおもちの重複防止

おもちとコントローラの対応付けは、socket.ioが備えているroomの仕組みを使って行っています。roomは一般的なチャットルームを実装するための基本機能なのですが、

  • 存在しないルーム名でjoinしたら、新たにルームが作られる
  • 既存のルーム名でjoinしたら、既存のルームに入る

という動作になっております。

OMOCHI HACK ではこの仕組みを利用しつつ「おもちは必ずオリジナルな名前のルームとして作って、そこにコントローラが名指しでjoinする」仕組みとし、おもちの名前は重複を許さないことにしました。

  • おもち側で存在しないルーム名で入ろうとしたら、joinする → 新たにルームが作られる
  • おもち側で既存のルーム名で入ろうとしたら、既に使われている名前であると警告を出し、再入力を促す

この辺りの処理は、 server.js L62 - L112 あたり にコーディングしてあります。socket.ioのルーム管理とは別に、独自に現存するおもちのリストを管理することで実現しています。

おもち死亡のおしらせをコントローラ側に通知する

通常利用だと、おもち側が閉じるケースとして以下の様な物があります

  • ページをリロードする
  • ブラウザの戻るボタンを利用するなどページ遷移を行う
  • タブを閉じる
  • スマホを放置してしまい画面がロックされる
  • スマホで別のアプリを開く
  • 別の名前のおもちを作り直す

これらを検出したうえで、以下の事をやらなければなりません

  • ルーム(おもち)をリストから削除する(利用された名前がたまってしまわないよう)
  • おもちが消えたことをコントローラに通知する
window.onpagehide を利用する
  • ページをリロードする
  • ブラウザの戻るボタンを利用するなどページ遷移を行う
  • タブを閉じる

この3パタンについては、window.onpagehide で検出できます。はじめ window.onbeforeunload で書いていたのですが、Safari@iOS8 ではこのイベントが使われなくなって居ることを知り、pagehide に書き換えています。

この辺りの処理は、light.js L133 あたり にコーディングしてあります

socket.io の disconnect イベントを検出する
  • スマホを放置してしまい画面がロックされる
  • スマホで別のアプリを開く

この2パタンの場合、私が調べた限りでは ウェブアプリがそれを検出して何かする、というのが出来ませんでした。しかし、socket.io の方で、クライアント(ここではおもち)が不活性な状態を検出してdisconnect イベントとして処理する仕組みがあるようで、それを利用する事にしました。

具体的には、disconnectイベントを送ってきたsocketのidを調べて、それがおもちリスト(コード内では lightlist )に存在するか調べ、していたら削除する、と言う物です

この辺りの処理は server.js L49 - L55 あたりにコーディングしています

イベントを拾えるケース
  • 別の名前のおもちを作り直す

最後のパタンは、サーバ側で処理しています。自分が既におもちとしてroom名を持っていて、それと同じ名前で作ろうとした場合は、何もせず既存のroomを利用します。新しい名前を指定した場合は、さっきまで使っていたroomを破棄し、新しいroomを作ります。

この辺りの処理は、 server.js L105 - L109 あたりでコーディングしています。

おもちが消えたことをコントローラに通知する

上記パタンでおもちが消えたとき、コントローラ側は、カラーコントロールのUIがdisableされ、再度おもちの名前入力を要求される画面になります。これで、接続が切れたことをコントローラ側からも認識出来ます。この辺りの処理は sever.js L138controller.js L123 にコーディングしてあります。

f:id:AMANE:20141226202130p:plain

様々なブラウザ・解像度への対応 (軽めに…

ちまたのウェブデザイナ、ウェブコーダ様方にあたられましては、日々多様化するディスプレイの解像度や、ブラウザごとの微妙に異なるCSSの解釈に日々頭を悩ませていることと存じ上げますが、私も今回のアプリを作り上げるに当たりまして、「出来る範囲で・時間が許す範囲で」広めに対応を取ってみたところです

動作確認しているのは以下の環境

です。すべて最新の物です。

レスポンシブ的CSS切り分け

  • @media screen and (min-width: 320px) and (max-width: 480px) 的な物を使う

vendor prefix

-webkit-transform -moz-transform とか。

ブラウザごとの対応状況を調べられる。おなじ webkit でも、Chromeではつかえて、 safari@iOS じゃ使えない、とかかなりよくある。

Chrome for Androidborder-radius が微妙に効かない件

コントローラの円形のカラーピッカーを描くのに <div> に対して四隅50% でradius をかけようとしたが、Androidでだけうまくいかない。

f:id:AMANE:20141225220038j:plain

ここを参考に修正

.selector {
/* だめ */
border-radius: 50%;

/* だめ */
border-top-left-radius: 50%;
border-top-right-radius: 50%;
border-bottom-left-radius: 50%;
border-bottom-right-radius: 50%;

/* OK */
border-top-left-radius: 50%;
border-top-right-radius: 50%;
border-bottom-left-radius: 50%;
border-bottom-right-radius: 49.9%; /* ここがポイント */

/* これでもOK */
border-radius: 50% 50% 50% 49.9%;
}

この記事では Galaxy S4 で、 と言っている。私の場合は Nexus7 (2013)。機種依存かもしれない。

さくらのVPSに Node.js アプリをデプロイする際のTips

基本

forever さまさまです。

この記事では /etc/nginx/conf.d/ 内にリバースプロキシの設定を書いていますが、

  1. /etc/nginx/sites-available/ 内に今回のアプリ用の新しい設定ファイルを作っておき
  2. /etc/nginx/sites-enabled/シンボリックリンク しておくのがいまどき、なはず

linux - What is the different usages for sites-available vs the conf.d directory for nginx - Server Fault

自分が作ったサイトの設定ファイルはこんな感じ

# /etc/nginx/sites-available/omochi_hack

upstream omochi {
    server localhost:3000;
}

server {
    listen 80; 
    server_name omochi.izmiz.me;

    proxy_redirect                          off;
    proxy_set_header Host                   $host;
    proxy_set_header X-Real-IP              $remote_addr;
    proxy_set_header X-Forwarded-Host       $host;
    proxy_set_header X-Forwarded-Server     $host;
    proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;

    location / {
        proxy_pass http://omochi/;
    }
}

VPSのポート設定

そういえば以前iptablesで厳しくポートを絞っていたのを忘れていました。express が ポート3000番でサーバをあげているので、あけてあげなくちゃいけません。

sudo ufw allow 3000/tcp

おなまえ.com のDNS設定

リバースプロキシに設定した omochi.izmiz.me がちゃんと解決出来るよう、DNSに覚えていただきます

おなまえ.com > ログイン > 今回のドメイン > (タブ)ドメイン設定 > DNS関連機能設定 > 今回のドメインを選んで「次へ進む」 > DNSレコード設定

ログインした状態で直リンク > https://www.onamae.com/domain/navi/dns_controll/input

普通にたどるととんでもない階層にいます。ほとんどここしか使わないのに…!

ここに、 nginx の sites-availabe に設定した server_name を登録します。

以上

以上で、 http://omochi.izmiz.me にアクセスすると、 さくらVPS内の expressが立てている 3000 番ポートで動いている OMOCHI HACK アプリにアクセス出来るようになりました。

そのほか細かい技

今回のアプリで参考にさせていただいたその他のノウハウをまとめておきます

Canvas + image でカラーピッカー

letter-spacing したテキストをセンタリングする

index.html L25 - L32

letter-spacing: 1em すると、文末にも1文字スペースが空いてしまうので、その分文末に負のマージンを与えるか、文の頭に正のマージンを与える

ブラウザの「ホーム画面に追加」を利用する

これをしてホーム画面からアイコンタップで起動すると、全画面でアプリが開きます。ここで登録されるアイコンについての覚え書き

log4js でログ取り

ロギングのセッティングを json で外部化出来るのが素敵。

内で1行のテキストを垂直方向にセンタリング

.selector {
  height: 100px;
  line-height: 100px; // heightline-height に同じ値を指定する
}

JavaScriptHSV -> RGB 変換

jQuery.delay() が便利

jQuery .val() で form の値を取得

jQueryセレクターを取得

$something.selector で取得 出来るのだけど、 deprecated. どうしましょう。今回使ってしまいました。

カラーホイールの絵の描き方

さいごに

今回、Advent Calendar締切ドリブンで、UI、通信、サーバサイド、サーバへのアプリのデプロイ と1人で通貫でやってみました。できあがった物はまぁしょぼいのですが、個人的には非常に大変でした。良い経験になりました。

(タブレットで) 鏡餅を光らせて新年を迎えましょう

この記事は おうちハック Advent Calendar 2014 25日目(なんと最終日!)の記事です。 前日は @K-A-Z さんの 「Arduino+Raspberrypi+GoBotで恋人たちの聖夜を支援する - Qiita」 でした。

ベッドイン検知、まじめなライフログとして王道な利用法も出来る気がします。わくわくしますね。

はじめに

f:id:AMANE:20141224220523j:plain

今年は業務でウェブのクライアント…特にUI周りを作る機会が多かったのですが、自分でサーバサイドから通信そしてUIまでアプリを全部作りきる、ということをやったことが無かったので、アドベントカレンダー締切ドリブンでやってみようと決めました。

正直、アドベントカレンダーだったら何でも良かった のですが、リストをざーっと見てみると、どうも敷居が高い感じでちょいと難しい。そんななか「おうちハック」という響きの緩さに「これならいけるんちゃうか…」とつられてみたところです。ネタはそこから考えました

おうちハック Advent Calendar さん、登録した時点で最終日しか空きがなかったので、クリスマスは終わったことにして日本人らしくお正月ネタにしよう、おもちじゃん、光ったら素敵じゃん、やったー!\(^_^)/

というわけで、おもちを光らせることにしました。

できたものの紹介

使い方を動画で紹介します。

※注記: OMOCHI 単体でも、じんわりと色と背景が変わっていくオートモードでお楽しみいただけます!

公開してます

PCからももちろん利用できます。ノートPCならお餅をのっけるのも可能ですね!

負荷とかセキュリティとかはわかりません!重かったり落ちてたらすみません。

OMOCHI HACK

システム構成

構成は下図のようになっています。OMOCHI側、CONTROLLER側のUI、ブラウザでそれぞれのアドレスにアクセスするとウェブアプリとして表示されその場で使用できます。OMOCHI側は新規作成時に固有の名前をつける必要があります。

f:id:AMANE:20141225104949p:plain

上の動画にもありましたとおり、コントローラからおもちの光らせ方をコントロールできます。この用法だと 「明らかにWebRTCだろ」 というおしかりを受けそうですが、甘んじて受け入れます。WebRTCに一瞬トライしたのですが、 難しそうだったのでパスしました 。来年頑張ります!

ソースコード

あげてあります。

使った鏡餅

厳密にはこれではないのですが、10インチiPadには「5号」サイズの鏡餅が良かったです!この大きさになると台座も付いてくるので、トップの写真のようにグッと雰囲気が増します。

一応まじめらしい背景

今回のプロジェクトの背景として「おうちハック」の視点から見て2点、抜き出してまとめてみました。

余ったスマホ活用

ここ数年で一気にタブレットスマートフォンが普及し、世代交代も速いため、1人1台や2台にとどまらず、古くなって引出にしまっている端末もたくさん持っている様な状況が(一部のギークの間では)普通になってきたように思います。

Arduino などを使うと従来より非常に簡単にフィジカルな入出力が可能で、しかもネットにつながったツールを作り出すことが出来ますが、入出力の自由度を下げてタッチや液晶表示などに限定して良いケースなら、余剰のスマホや利用頻度のひくいタブレット超高性能 なネットワークのノードになります。そしてソフトウェアのコーディングだけで済むので、敷居もグッと下がります。

こういったムーブメントは既にかなり広がってきていて、余ったスマホを監視カメラ代わりに利用するのは非常にメジャーです。また、高性能なプロセッサを小型な信号処理部として活用することで、筋電義手を材料費3万円ほどで作ろう、というプロジェクトも動いています。

余ったスマホ、スゴイです。専用のデバイスを買わなくても、家に有るもので皆さん楽しめます。

つながり感通信

おうちをハックするので、ハックして/されて嬉しいのが自分だけじゃつまらないです。家には自分の家族も居ますし、また、遠く離れた生まれ故郷の実家には、自分の両親もいます。そんな 「おうち」どうしをつなげるような道具 が欲しいなぁ、と思い、今回ネットワーク越しのコントローラ機能を実装しました。

似たようなプロジェクトで有名どころだと、NTT研究所の一連の研究があります。

また、商品として出ている物もあります。

今回の実装はセキュリティ的にアレゲな感じもしますが、勘弁して下さい。

手軽にパーソナルなクラウド

つながり感通信に関してもう一歩踏み込んでみます。

おうちハック的なプロジェクトは(そんな中から大当たりする物も出てくると信じていますが)、2014年現在は、デバイスやネットワークと使いこなす技術がこなれてきたことによって、多少なりとも技術が使える人が、個人の小さな満足を満たす仕組みを作りやすくなったことから発生している物が多いように思います。俗に言うMAKERSですね。

そういうパーソナルで小規模なサービスをIoTとしてネットワーク上で利用しようと思うと、気軽にクラウドのサーバを利用できることは非常に便利です。今回はさくらのVPSで運用していますが、heroku 的なものも便利だと思います。

実装の話 / さいごに

ざっくり言うと上の図に書いたようなシステムで動いているのですが、自分の技術まとめとして書きます。

ですが、今回は既に記事が長くなってしまっているので、次回に持ち越させてください。

Advent Calendar的にはこんな終わらせ方で良いのかな?? それではみなさん、メリークリスマス & 良いお年を~

UnityでOpenCVを どう使うか - OpenCVSharp vs OpenCV dllを使う環境 vs スタティックライブラリ

はじめに

最近何編かにわたって、Unityで OpenCV を使う方法についてまとめてきました。

扱った手法は大きく分けて三つあります

  1. OpenCVSharp を使う
  2. OpenCV のDLLを使う前提で、必要な関数をラップした Native Pluginを作る
  3. OpenCVの staticlib を必要な分だけ取り込んだ Native Plugin を作る

どの手法を使うか、ちょっと考えてみました

それぞれの特徴

1. OpenCVSharp

長所

  • C# だけですんで楽
  • DLLのビルドとかない

短所

  • C++OpenCVに慣れているとちょいちょい混乱する。ちまたのリファレンスが基本 C++なだけに。
  • C++ のライブラリを全部ぶっ込み、OpenCVSharp の DLLもぶっこみ、とする必要があるのでオーバーヘッド大。特に配布を考えると。
  • あくまで有志の方が作った物で、公式の最新について行けるとは限らない

2. OpenCV のDLLを使う前提で、必要な関数をラップした Native Pluginを作る

長所

  • (OpenCVが事前にインストールしてある人にとっては) 配布物が最小になる
  • 標準の書き方 = C++ で書ける
  • 公式の最新をそのまま使える

短所

  • 利用者がOpenCVをインストールするか、配布物一式にOpenCVのDLLを同封する必要がある
  • ビルドの設定がちょっと複雑
  • デバッグが面倒

3. OpenCVの staticlib を必要な分だけ取り込んだ Native Plugin を作る

長所

  • OpenCVのDLLを使う必要が無いことまで加味すると、Native Plugin の容量が最小になる
  • そのため、おそらく起動も速い
  • 標準の書き方 = C++ で書ける
  • 公式の最新をそのまま使える

短所

どう使うか?

こう考えました。

  • OpenCV のたくさんあるリファレンスなどを生かせるので、標準の書き方(C++)にしておきたい
  • いろいろ取り込んでアプリが肥大化するのはかっこよくない

短所については

  • ビルドの複雑さは慣れでカバー

というわけで、 3. staticlib を使ってDLLを作る が良いと考えました。

デバッグが面倒、という件も

  • 一応前回の記事でクリアできたと思っている
  • そもそもDLLにする主旨は、役割の分担を明確にし極力疎結合にすることです。データの受け渡しなど界面をしっかりと設計し、OpenCVで行う画像処理などは C++ 単体でテストしておいて、使えることを確認した後Unityで使うようにすべきでしょう。つまりデバッグは普通にC++で完結して行う。

という感じの進め方で良いと思っています。

(前回の記事)