2013年4月22日月曜日

テストも簡単!Intel XDKで書いたアプリをAndroidでテストする


前回エミュレータ上では、AndroidでもiPhoneでも動いたthree.jsのサンプルですが、今回は実際に実機でテストしてみます。

XDKのエミュレータの右上にある「App Tester」をクリックします。

作成したProjectがクラウドに転送されます。

転送完了。
右矢印をクリックすると手順の説明が出てきます。

ここからはappMobiのAndroidアプリ「app•lab」をインストールし、Android側で作業します。

アプリを起動し、「enter the lab」から先へ進みます。

「log in now」からブラウザを起動します。
どうやらはじめから画面の右上に表示されている「MY APPS」からでも同じく飛べるようです。

XDKに登録した際のIDとPWを入力してログインします。

先ほど転送したProjectを選択します。

「App Tester」を選択します。
「Test Local」からでも起動出来ますが、その差は良く分かりません。

「Launch」から起動します。

はい、見事動きません。

html5の互換性の問題なのか何なのか。。。

他のサンプルアプリを飛ばしてみたところ普通に動いたので、AndroidのChromeブラウザとthree.jsの問題かもしれません。

たしかにthree.jsで書いたアプリがAndroidで動いているサンプルってあまり見ないんですよね。

そもそもこのXDKのエミュレータは、ブラウザによる対応状況の差異まで考慮されていないのかもしれません。画面サイズによる差異を見る程度の話で、HTML5の互換性を100%と過程しているのだとするとあまり意味無いですね。

何にせよ、3Dで物理演算までの道のりはまだまだ長いです。。


Read More...

2013年4月21日日曜日

ブラウザで3D!Intel XDKでthree.jsを動かしてみる


では今回はIntel XDKを使って、three.jsのサンプルを動かしてみます。

この辺からthree.jsのサンプルなど含めて一式ダウンロードします。

「examples」フォルダに様々なサンプルが入っているので、Chromeで表示させながら、簡単そうなのを選んでみます。

今回選んだのは、立方体がドラッグするとクルクル回るだけの簡単なサンプル「canvas_geometry_cube.html」です。

今回、XDKの画面で新しく利用するのは、画面左側にある「Reload app」ボタンとエミュレータの右上にある「Show/Hide Debug Console」ボタンです。


前回触ったXDKのエディタ画面で、index.htmlに必要そうなところをコピペしていき、エミュレーションモードに戻ります。

「Show/Hide Debug Console」ボタンでコンソールを開き、「Reload app」ボタンで更新します。

。。。。

動きません。

コンソールを見てみましょう。


なにやら404(Not Found)が出ていますね。
それもそのはず、three.jsのライブラリをコピーするのを忘れていました。

ファイルをコピーし、パスも整えて再度リロードしてみます。


ちゃんと動きました。
マウスでドラッグするとクルクル回ります。

ちなみにリロードボタンの下に「Rotate」ボタンがあって、切り替えられます。


さらに画面右側に「DEVICE EMULATION」という欄があり、デバイスも切り替えられます。


XDKもなかなかお手軽ですが、three.jsもかなりお手軽ですね。
そのうち3Dで物理演算ぐらいまではやってみたいと思います。

Read More...

ブラウザで開発!初めてのIntel XDK


もともとappMobiが開発していたHTML5開発ツールで、Intelがスタッフごと買収して「Intel XDK」としてリリースしました。
ぱっと見た感じ便利そうだったので、軽く触ってみることにします。


まず立ち上げるとdemoアプリのHello Worldが表示されます。
新しくアプリを作成するには、左上のファイル名の左側にある「START NEW」から新規作成します。


「Project Name」を適当に決めて、今回はウィザードなどは使わずにゼロから作るので「Create your own from scratch.」を選択します。


ちなみに、Project IDは「ID.ProjectName」という規則なのですが、これID変更出来ないんでしょうか??登録に利用したメアドの@前がそのまま表示されます。
なんとなく気持ち悪いので画像は編集しつつ次へ進みます。

「Use a blank project.」を選択します。


画面に「Application Created Successfully!」と表示されて、まっさらなプロジェクトが表示されます。
以下で見えているのはエミュレーションモードで、エディタモードへ遷移するには左上にある先ほどの「START NEW」ボタンの左側「EDITOR」ボタンをクリックします。


開いた画面の左側メニューで編集したいファイルを選択すると画面右側にソースが表示されます。


生成されたindex.htmlのソースを見ると、ブランクというわりには、以下のような何やらテンプレ的なものが並んでいます。
<script type="text/javascript" charset="utf-8" src="_appMobi/appmobi_local_bootstrap.js"></script> 
<script type="text/javascript" charset="utf-8" src="http://localhost:58888/_appMobi/xhr.js"></script> 
<script type="text/javascript">
/* This function runs once the page is loaded, but appMobi is not yet active */
var init = function(){

};
window.addEventListener("load",init,false);  

/* This code prevents users from dragging the page */
var preventDefaultScroll = function(event) {
    event.preventDefault();
    window.scroll(0,0);
    return false;
};
document.addEventListener('touchmove', preventDefaultScroll, false);

/* This code is used to run as soon as appMobi activates */
var onDeviceReady=function(){
    //Size the display to 768px by 1024px
    AppMobi.display.useViewport(768,1024);
 
 //hide splash screen
 AppMobi.device.hideSplashScreen(); 
};
document.addEventListener("appMobi.device.ready",onDeviceReady,false);    
</script>

ちなみに上記を削除してリロードしてみると、以下のように怒られます。


コピペを指示されたコードは以下。
<!-- the line below is required for access to the appMobi JS library -->
<script type="text/javascript" charset="utf-8" src="http://localhost:58888/_appMobi/appmobi.js"></script>

<script type="text/javascript" language="javascript">
        // This event handler is fired once the AppMobi libraries are ready
        function onDeviceReady() {
            //use AppMobi viewport to handle device resolution differences if you want
            //AppMobi.display.useViewport(768,1024);

            //hide splash screen now that our app is ready to run
            AppMobi.device.hideSplashScreen();
        }

        //initial event handler to detect when appMobi is ready to roll
        document.addEventListener("appMobi.device.ready",onDeviceReady,false);
</script>

もともと入っていたコードと内容が違う理由は謎です。

エディタを触った感じ、「Ctrl+C」「Ctrl+Z」「Ctrl+S」などのコマンドもそのまま使えて、特に不便は感じませんでした。

ちなみに保存するとこんなポップアップが出てきます。


後は何か書いてみるだけということで、次回は実際に何か作ってみます。


今回はここまでです。

なぜ中途半端なところで終わっているかというと、調子に乗って「three.js」と「Physijs」で物理演算のサンプルを動かそうと試み、そして動かず時間だけが過ぎていき、無かったことにしたからです。。


Read More...

2013年4月14日日曜日

Chrome拡張で朝鮮半島に平和を!Browser ActionからScriptを実行する


 前回はツールバーのアイコンクリックでポップアップを表示させましたが、今回はアイコンクリックで直接スクリプトを実行します。

 拡張のアイコンをクリックすると、innerHTMLを書き換えるスクリプトを仕込みます。


 前回と違う点は「permissions」の設定と、「background」の設定です。

 「permissions」については必要なものを配列で指定します。
 今回はchrome.tabsを利用するために「tabs」を指定するのと、どのサイトでも動くように「http://*/*」(httpから始まるすべてのサイト)を指定。

 「background」については、スクリプトを登録しておくとChrome起動時に呼ばれます。
 関数を定義しておいたり、リスナーを登録しておいたりなどに利用します。

 「browser_action」の「default_popup」は、今回は使わないので削除します。

{
 "name": "南北統一",
 "version": "1.0",
 "manifest_version": 2,

 "description": "朝鮮半島を平和にします。",

 //必要なパーミッションを指定する
 "permissions": [
  "tabs", "http://*/*"
 ],

 //バックグラウンドで動く処理
 "background": {
  //スクリプトファイルを登録
  "scripts": ["background.js"]
 },

 "browser_action": {
  "default_icon": "icon.png",
  "default_title": "統一"
 }
}


 続いてスクリプトファイルを作成します。

 「chrome.browserAction.onClicked」はツールバーのアイコンがクリックされた際に呼ばれるイベントで、その「addListener」でリスナーを登録しておきます。

 「chrome.tabs.executeScript」でタブ内でスクリプトを実行します。
 第1引数はスクリプトを実行するtabIdで、現在のタブの場合はnullを指定します。
 第2引数は実行するスクリプトの詳細情報オブジェクトで、codeプロパティの場合は「:」の後ろに実行するスクリプトを文字列で指定します。

 長々と実行内容を文字列変数に格納しておいてから、executeScriptに渡していますが、もっとうまいやり方がありそうです。
 事前に関数を定義しておいてその関数を文字列で渡せば良いかと思ったのですが、やってみたら動きませんでした。

 まぁ、ここは動けば良いということで。

unification = "";
unification += 
 "document.body.innerHTML = " +
 "document.body.innerHTML.replace(/北朝鮮/g,'朝鮮');" +
 "document.body.innerHTML = " +
 "document.body.innerHTML.replace(/韓国/g,'朝鮮');";

chrome.browserAction.onClicked.addListener(function() {
 chrome.tabs.executeScript(null, {code: unification});
});

 ちなみにタグやスクリプトも無慈悲に置換されますので、「a」⇒「h1」なんてことも出来ます。


 さて、作成した拡張をChromeに登録して実行してみましょう。

 これが、

こうなる。

うーん。。

半島の統一には成功したのですが、内戦が激化しましたね。


Read More...

2013年4月13日土曜日

意外に簡単に作れる!Google Chrome ExtensionsでHello World


普通に使っているものの、書いたことの無かったGoogle Chrome Extensions(拡張機能)。ちょこっと調べてみたところ、HTMLとJavaScriptが分かれば相当お手軽に作れるということが分かりやってみました。

いくつか種類があるのですが、その中でも「Browser Action」という、ツールバーのアイコンをクリックすると動くやつが手軽そうです。

それでは、ツールバーのアイコンをクリックすると、「Hello World!」と表示するだけの簡単なものを作ってみましょう。

1.アイコンを用意する

ツールバーに表示するために19×19(px)の画像を用意します。

拡張機能一覧で表示するためのアイコンは48×48(px)の画像で、無くても動くので今回は用意しません。


2.マニフェストファイルを作成する

「manifest.json」という名前で以下のように作成します。

{
 //拡張機能の名前
 "name": "Hello World!",
 //拡張機能のバージョン
 "version": "1.0",
 //決まりごとで今は2に設定
 "manifest_version": 2,

 //拡張機能一覧に表示される説明
 "description": "Hollo Extensions!",

 "browser_action": {
  //先ほど用意したアイコン
  "default_icon": "icon.png",
  //アイコンにマウスオーバーした際に表示される文字
  "default_title": "Hello World!",
  //Hello Worldを表示するHTMLファイル
  "default_popup": "hello.html"
 }
}


3.Hello Worldを表示するHTMLを作成する

styleにmin-widthを設定しないと、変なところで改行されるので「body」に設定します。

<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charaset="utf-8">
</head>
<body style="min-width:200px">
<h1>Hello World!</h1>
</body>
</html>


4.Chromeに登録する

もうあとはChromeに登録するだけです。
アイコンとマニフェストファイルとHTMLを一つのフォルダに放り込み、以下手順で登録します。

メニューから「ツール」の「拡張機能(E)」を開きます。


「デベロッパーモード」にチェックを入れ、「パッケージ化されていない拡張機能を読み込む」から該当のフォルダを選択します。


すぐ下の部分に表示されたら登録成功です。
ちなみに、拡張機能を修正したりした場合は、ここの「リロード(Ctrl+R)」をクリックすると変更が反映されます。


5.実行する

うまくいきました。

しかし、Hello Worldなんて今も使うんですかね??


Read More...

2013年3月31日日曜日

永遠のいたちごっこ!?Youtubeの動画ファイルURLを特定する

Youtubeの動画ファイルをダウンロードしたい。動画をダウンロードさせたくない。
ユーザの思いとYoutubeの中の人の思いは、いつの日も交わることのない平行線です。

ユーザ側はYoutubeサイトを解析して動画ファイルの実体のありかを見つけ出し、Youtube側はサイトの仕組みを定期的に変更しています。

2月頃に解析してファイルのURLを特定出来たのですが、久しぶりに見てみるとまた仕組みが変更になっていました。

さて、いたちごっこの始まりです。


DOMやSAXなどを使って、<script>タグの中から以下が含まれる部分を探し出します。
※ちなみに2月に見たときとはこの変数名が変わっていました。

var ytplayer = ytplayer


これはソース上に一箇所しか表示されないので、すぐ特定出来ます。
該当の場所は以下のような感じで始まります。

<script>var ytplayer = ytplayer || {};ytplayer.config = {"url": "https:


この「ytplayer.config」の中には、以下のように様々な値がJSON形式で入っています。

  • url
  • url_v9as2
  • attrs
  • params
  • url_v8
  • args
  • html5
  • assets
  • min_version
  • sts

必要なのは「args」で、またこの中に100個近い値が入っていて、その内以下二つの値を利用します。

  • url_encoded_fmt_stream_map
  • title

「url_encoded_fmt_stream_map」の中には画質の数だけカンマ区切りでURLエンコードされたデータが入っています。

url=http://r9---sn-ogueynes.c.youtube.com/videoplayback?upn=IAD3bFZV614&mv=m&source=youtube&expire=1364660261&sparams=algorithm%2Cburst%2Ccp%2Cfactor%2Cid%2Cip%2Cipbits%2Citag%2Csource%2Cupn%2Cexpire&algorithm=throttle-factor&cp=U0hVSVZRTl9LS0NONV9OS1JDOkQxNGtBcURXM0pG&id=215b73e77a669a55&sver=3&ms=au&burst=40&mt=1364634922&fexp=919112%2C910071%2C914073%2C916626%2C901449%2C932000%2C906383%2C902000%2C919512%2C929903%2C931202%2C900821%2C900823%2C931203%2C931401%2C908529%2C930807%2C919373%2C930803%2C906836%2C920201%2C929602%2C930101%2C930603%2C900824%2C910223&newshard=yes&factor=1.25&key=yt1&ip=114.185.103.241&itag=17&ipbits=8\u0026type=video/3gpp; codecs="mp4v.20.3, mp4a.40.2"\u0026sig=72F456D7BB44FD11E2FEEFF93BB7E299458D267B.B502EFA76F6358C09848C82085C4EEA0551AC8BA\u0026fallback_host=tc.v8.cache2.c.youtube.com\u0026quality=small\u0026itag=17


データ一つ一つを見ていくと、キーと値が「=」で対になった以下の値が、「\u0026」(&をアスキーコードの16進数であらわしたもの)で区切られています。

  • url
  • type
  • sig
  • fallback_host
  • quality
  • itag

「\u0026」で分割してキーと値に分けた後、「url」の値をデコードして「?」より前と後ろで分割します。

前はコレ。

http://r9---sn-ogueynes.c.youtube.com/videoplayback?


後ろには、キーと値が「=」で対になった以下の値が、「&」で区切られています。
これは全部使いますので、「&」で分割してキーと値に分けます。

  • upn
  • mv
  • source
  • expire
  • sparams
  • algorithm
  • cp
  • id
  • sver
  • ms
  • burst
  • mt
  • fexp
  • newshard
  • factor
  • key
  • ip
  • itag
  • ipbits

これに「args」に入っていた「title」を加えます。
「title」はダウンロードした際のファイル名になるので、値はそのままでも個別に指定しても良いです。

「url_encoded_fmt_stream_map」の中にあった「sig」をキーを「signature」に変更して加えます。

キーでソートします。

あとは出来上がったキーと値の組み合わせを、以下のように「url」前半部分につなげてアクセスするだけでダウンロード出来ます。

http://URL?キー=値&キー=値&キー=値&キー=値



いたちごっこは終わらない。。

Read More...

2012年4月24日火曜日

エッジを検出する その3 - OpenCV for Android


続いてCannyフィルタです。

ガウシアンフィルタとSobelフィルタを組み合わせてエッジを検出します。
まず、ガウシアンフィルタでぼけた画像を作り、その画像にSobelフィルタをかけることでエッジを検出します。
実際には処理はそれだけではなく、色々とやっているようです。

Cannyフィルタを利用するには、Imgproc.Canny()メソッドを利用します。

Imgproc.Canny(Mat image, Mat edges, double threshold1,
double threshold2, int apertureSize, boolean L2gradient)

Mat src          処理したい元画像のMat
Mat edges        変換後Mat
double threshold1   第1閾値
double threshold2   第2閾値
int apertureSize    Sobelのアパーチャサイズ
boolean L2gradient  L2ノルム利用有無


threshold1、threshold2については、値が小さいほうがエッジ同士を接続するために用いられ、大きいほうが強いエッジの初期検出に用いられます。
順番を変えても結果は同じです。

apertureSizeについては、デフォルトが3で、3、5、7が選択出来ます。

L2gradientについては、画像勾配の強度を求めるために、精度の高いL2ノルムを利用するか、高速なL1ノルムを利用するかを設定します。
デフォルトではL1ノルム(false)です。


それでは、実際にやってみましょう。

元画像です。


Imgproc.Canny(mat, dstMat, 50, 200);


Imgproc.Canny(mat, dstMat, 100, 200);


Imgproc.Canny(mat, dstMat, 100, 300);


Imgproc.Canny(mat, dstMat, 50, 200, 5);


Imgproc.Canny(mat, dstMat, 50, 200, 7);


Imgproc.Canny(mat, dstMat, 100, 200, 3, false);


Imgproc.Canny(mat, dstMat, 100, 200, 3, true);


ちなみに平滑化⇒Sobelで同じような結果になるんでしょうか?
Imgproc.GaussianBlur(mat, mat, new Size(3, 3), 0, 0);
Imgproc.Sobel(mat, dstMat, mat.type(), 1, 1, 5);


そう単純では無いようですねw


Read More...