「マンガテレビ」の作り方
DESCRIPTION
第41回HTML5とか勉強会で講演した「マンガテレビ」の作り方。WebSpeech APIとかheadtrackr.jsとかTRANSCRIPT
http://goo.gl/O2YkkJ
「マンガテレビ」の作り方
第 41 回 HTML5 とか勉強会2013.8.26 こまつけんさく
http://goo.gl/O2YkkJ
自己紹介こまつけんさく
NTT コミュニケーションズ 最新 Web 技術の研究開発
html5j スタッフ
Google Developers Expert (HTML5)
Microsoft Valuable Professional (IE)
http://goo.gl/O2YkkJ
「マンガテレビ」?
https://app.html5experts.jp/manga/
http://goo.gl/O2YkkJ
いわゆる「リスペクト」です
( ー `д ー ´) キリッ
http://goo.gl/O2YkkJ
開発のきっかけ
http://www.kakkoii.tv/events/20130726/index.html
http://goo.gl/O2YkkJ
HTML5 Experts Nighton 8/23@MTL
http://html5experts.jp/yusuke-naka/1698/
http://goo.gl/O2YkkJ
開発メンバー
http://goo.gl/O2YkkJ
What is 機能
http://goo.gl/O2YkkJ
マンガ化
http://goo.gl/O2YkkJ
音声コマンド、ふきだし、エフェクト
http://goo.gl/O2YkkJ
リアルタイムフィードバック
http://goo.gl/O2YkkJ
How to 実装マンガ化
WebSpeech APIHeadtrackr.js
http://goo.gl/O2YkkJ
マンガ化1. getUserMedia() でビデオ取得
2. CanvasPixelArray 取得
3. フィルター処理
http://goo.gl/O2YkkJ
マンガ化 (1/3) getUserMedia()
navigator.webkitGetUserMedia({video: true, audio: false}, function(stream){ var url = window.webkitURL.createObjectURL(stream); $v_[0].src = url; $v_[0].play();});
http://goo.gl/O2YkkJ
マンガ化 (2/3)CanvasPixelArray 取得
var imgData = ctx.getImageData(0, 0, 640, 480);
3
1 2
4
imgData = [ 255, 0, 0, 255, // 1 (R, G, B, α) 0, 255, 0, 255, // 2 (R, G, B, α) 0, 0, 255, 255, // 3 (R, G, B, α) 255, 255, 0, 255 // 4 (R, G, B, α)];
http://goo.gl/O2YkkJ
マンガ化 (3/3)フィルター処理
階調化とエッジ中抽出の組み合わせ
エッジ抽出
階調化(三階調)
合成
参考) http://www.slideshare.net/masayukimaekawa/java-script-14727253
http://goo.gl/O2YkkJ
Code
for(var y = 1; y < height-1; y++){ for(var x = 1; x < width-1; x++){ c = y * width + x; i = c << 2;
// 周辺ピクセル tmp = (c - width) << 2; a0 = (dotList[tmp] + dotList[tmp+1] + dotList[tmp + 2]) & FILTER; tmp = (c - 1) << 2; a1 = (dotList[tmp] + dotList[tmp+1] + dotList[tmp + 2]) & FILTER; tmp = (c + 1) << 2; a2 = (dotList[tmp] + dotList[tmp+1] + dotList[tmp + 2]) & FILTER; tmp = (c + width) << 2; a3 = (dotList[tmp] + dotList[tmp+1] + dotList[tmp + 2]) & FILTER; // グレー値 gray = (dotList[i] + dotList[i+1] + dotList[i + 2] );
if((a0 + a1 + a2+ a3) < ((gray & FILTER) << 2)) { // エッジ化 img_toon.data[i] = 0; img_toon.data[i+1] = 0; img_toon.data[i+2] = 0; } else { // 階調化 if( gray < DARK ) { gra = 0; } else if( gray > BLIGHT ) { gra = 255; } else { gra = 1; } // スクリーントーン if( gra == 1 ) { dx_ = (x & 0x03); dy_ = (y & 0x03) if( (!dx_ && !dy_) || (dx_ == 2) && (dy_ == 2)){ gra = 0; } else { gra = 255; } }; img_toon.data[i] = gra; img_toon.data[i+1] = gra; img_toon.data[i+2] = gra; } img_toon.data[i+3] = 0xff; //img.data[i + 3]; } }
30 万回のループ処理です。。。
http://goo.gl/O2YkkJ
WebSpeech API
var rec = new webkitSpeechRecognition();rec.start();
rec.onresult = function(event) { // event.results に認識結果が格納}
音声認識 API
W3C でドラフトにもなっていない。 Chrome のみ実装
認識は、 Google さんが頑張っています
http://goo.gl/O2YkkJ
意外に重要
https じゃないと、途中でも、これ出ちゃう・・・
http://goo.gl/O2YkkJ
Headtrackr.jsOepra の Audun さんが開発した顔検出ライブラリ
Face.js より高速で動く( MBP で 30fps ぐらい)
var htracker = new headtrackr.Tracker();htracker.init($("video")[0], $("canvas")[0]);htracker.start();
document.addEventListener("facetrackingEvent", function( ev ) { // ev.width : 幅 , ev.height : 高さ , ev.x : 中心 (x), ev.y : 中心 (y)});
http://goo.gl/O2YkkJ
ここまでの内容
http://html5experts.jp/komasshu/1649/
http://goo.gl/O2YkkJ
How to 向上 performance
http://goo.gl/O2YkkJ
高速化のポイント
for(var y = 1; y < height-1; y++){ for(var x = 1; x < width-1; x++){ c = y * width + x; i = c << 2;
// 周辺ピクセル tmp = (c - width) << 2; a0 = (dotList[tmp] + dotList[tmp+1] + dotList[tmp + 2]) & FILTER; tmp = (c - 1) << 2; a1 = (dotList[tmp] + dotList[tmp+1] + dotList[tmp + 2]) & FILTER; tmp = (c + 1) << 2; a2 = (dotList[tmp] + dotList[tmp+1] + dotList[tmp + 2]) & FILTER; tmp = (c + width) << 2; a3 = (dotList[tmp] + dotList[tmp+1] + dotList[tmp + 2]) & FILTER; // グレー値 gray = (dotList[i] + dotList[i+1] + dotList[i + 2] );
if((a0 + a1 + a2+ a3) < ((gray & FILTER) << 2)) { // エッジ化 img_toon.data[i] = 0; img_toon.data[i+1] = 0; img_toon.data[i+2] = 0; } else { // 階調化 if( gray < DARK ) { gra = 0; } else if( gray > BLIGHT ) { gra = 255; } else { gra = 1; } // スクリーントーン if( gra == 1 ) { dx_ = (x & 0x03); dy_ = (y & 0x03) if( (!dx_ && !dy_) || (dx_ == 2) && (dy_ == 2)){ gra = 0; } else { gra = 255; } }; img_toon.data[i] = gra; img_toon.data[i+1] = gra; img_toon.data[i+2] = gra; } img_toon.data[i+3] = 0xff; //img.data[i + 3]; } }
30 万回のループ処理です。。。
http://goo.gl/O2YkkJ
目標マンガ化フィルター処理を 60 fps @ MBP で !!
1 回あたりの処理は、大体 10msec 以下に抑える必要がある 1000 [msec] / 60 = ( 約 )16 msec
ループ 1 回あたりの処理は、 30 nano-sec 以下が目標 10 msec / 300,000
http://goo.gl/O2YkkJ
パフォーマンスチェック
http://goo.gl/O2YkkJ
結論関数呼び出しは減らそう
プロパティ参照は無くそう
演算処理はなるべく減らそう
ビットシフトは、若干早くなる (でも、なんか頭が良くなった気がする)
parseInt(“1”) < “1”|0 InternetExplorer を除く
http://goo.gl/O2YkkJ
パフォーマンスチューニングはエコ!!
http://goo.gl/O2YkkJ
Thank you!!@komasshu