2010年9月14日火曜日

Pythonを使ってAndroid端末を5分でリモートカメラにする方法

このブログ記事をはてなブックマークに追加

Android端末をリモートカメラにしてしまう方法「Spycam」という記事経由でTurn your Android Phone Into a Remote Spy Camera with Ruby in 15 Minutesを知った。SL4AのJRubyを使ってAndroid端末を15分で遠隔操作のスパイカメラにしてしまえるらしい。これは面白い。そこで、Rubyが15分ならPythonを使って5分でリモートカメラにしてしまおうと思い立った。

まず、Pythonでは標準モジュールのSimpleHTTPServerやwsgiref.simple_serverを使って簡単にWebサーバを構築することができる。そしてSL4Aを使えばAndroid端末をそのままサーバとして起動させることができる。これを組み合わせればできたも同然だ。

それで書いたのが以下のコードだ。10行そこそこでAndroid端末をWebサーバに仕立て上げ、Webブラウザ経由で写真を撮ることができる。こんなちっこい端末がWebサーバになるなんて世の中進歩したものだ。

remote_camera.py

import android from wsgiref.simple_server import make_server droid=android.Android() pic='/sdcard/snapshot.jpg' def camera(env,res): if env['PATH_INFO']=='/': droid.cameraCapturePicture(pic) res('200 OK',[('Content-type','image/jpeg')]) return [file(pic).read()] httpd=make_server('',9998,camera) httpd.serve_forever()

使い方は次の通り。まず、SL4Aを起動し、メニューボタンから"View"を選ぶとダイアログが出てくるので"Interpreters"を選択する。


再度、メニューボタンから今度は"Start Server"、"Public"を選択する。これでAndroid端末がサーバとして機能する。


次に、Android画面上部のインジケータ部分を開き、"SL4A Service"をタップする。そうするとScript Monitorが立ち上がるので、Serverのアドレスを確認する。それから先ほど作成したPythonスクリプト(remote_camera.py)を起動する。


サーバのアドレスの最後にソースコードで指定したポート(上記のコードでは9998)を加えたURLをWebブラウザに入力する。例えばサーバのアドレスが your.address.net だとすれば、 http://your.address.net:9998/ がWebブラウザに入力するURLとなる。これで遠隔操作による撮影が可能になった。ページをリロードすればその度に写真が撮影され表示される。試しに最近購入した書籍などを撮影。


これを使って次のような遊びをしてみた。Android端末を見つかりにくいところに隠し、あとでWebブラウザから写真を撮る。その画像とかすかに聞こえるシャッター音を頼りに隠したAndroid端末を探すというゲームだ。子供たち相手にやってみたが皆大喜びだった。もっと広い場所でやれば本当に楽しそうだ。必要なものはAndroid端末とWebブラウザの使えるデバイスだけだ。デバイスもPCではなくAndroid端末のようなスマートフォンで良いのだから手軽だ。

これは使い方の一例だが、Android端末とSL4Aを使えば可能性が本当に広がってくる。

続きを読む...

2010年9月13日月曜日

Android端末で青空プログラミング! SL4Aの導入からアプリケーションの作成・公開まで

このブログ記事をはてなブックマークに追加

以前、Android上でPython、Lua、JavaScriptなどを実行するスクリプティング環境ASE (Android Script Environment)について記事にした。現在ASEはSL4A (Scripting Layer for Android)に変更され、機能がさらに進化している。APIの充実やインターフェイスの改良、スクリプト環境は独立になり、HTMLインタプリタ導入やAndroidパッケージ(APK)の作成などもできるようになった。そこで改めてSL4Aのインストール方法、使い方、Pythonによるアプリケーションの作成、QRコードによるソースコードの公開方法などを紹介する。

導入

まず、SL4Aの公式サイトで最新版のSL4Aをダウンロードする。現時点ではsl4a-r2.apkだが、頻繁に更新されるので注意すること。さらに必要なスクリプト環境をダウンロードする。BeanShell, JRuby, Lua, Perl, Python, Rhino (JavaScript)などがあるが、ここではPythonを選んだ。現時点での最新版はpython_for_android_r1.apkになる。SL4Aとスクリプト環境は独立しているのでそれぞれをインストールする。

これらのAndroidパッケージは公式のものではないので、ダウンロード後インストールするためには、Android端末の設定で「アプリケーション」の「提供元不明のアプリ」にチェックを入れておく必要がある。


これでSL4AでPythonを使用するための準備は整った。

スクリプトの作成

SL4Aをインストールすると左のようなアイコンが出てくるのでそれをタップして起動する。Pythonスクリプトファイルの作成するには、メニューボタンから"Add"を選択し(スクリーンショット左側)、表示されるダイアログから"Python"を選ぶ(スクリーショット左から2番目)。そうすると、Pythonスクリプトの雛形を伴った編集画面になるので(スクリーンショット中央)、それを更新して作成する(スクリーンショット右から2番目)。ファイル名は自由に付けることができ、作成したスクリプトファイルは"Save & Run"ですぐに起動できる(スクリーンショット右側)。編集画面時のメニューボタンから"API Browser"を選択するとAPI一覧が表示される。これはコードを書く上で非常に役に立つ。


さて、ここで実際にアプリを作ってみる。しばらく前にPythonワンライナーで数独ソルバを作成したのでそれをAndroidアプリとして作り替えてみた。ワンライナーではプログラム中に問題を埋め込んでいたが、Androidではそれダイアログから入力するように変えた。入力時に電話のテンキーにすれば素早く片手で入力できるようになるが、HT-03Aではなぜか全角文字になってしまったのでそれをASCII文字に変換するテーブルも追加した。さらに、ワンライナーのようなコンソールへの出力ではバックグラウンドでの動作ができないので、ダイアログで表示させるように変更した。作成したのが以下のスクリプトだ。

sudoku_solver.py

# -*- coding: utf-8 -*- import sys,android droid=android.Android() L=[] def S(D): if 0 in D: L.append(D.index(0)) A=D[L[-1]//9*9:L[-1]//9*9+9] B=D[L[-1]%9:81:9] C=[d for n in(0,1,2)for d in D[L[-1]//27*27+L[-1]%9//3*3+n*9:L[-1]//27*27+L[-1]%9//3*3+n*9+3]] for i in set(range(1,10))-set(A+B+C): D[L[-1]]=i S(D) D[L.pop()]=0 else: M=''.join(['%d'%d+('\n' if i%9==8 else ' ')for i,d in enumerate(D)]).rstrip() droid.dialogCreateAlert(u'解答',M) droid.dialogShow() sys.exit() T={ord(u'\n'):None,ord(u' '):None,ord(u'*'):u'0',ord(u'*'):u'0',ord(u'.'):u'0',ord(u'.'):u'0'} for i in range(10): T[ord(u'0')+i]=u'%d'%i P=droid.dialogGetInput(u'数独ソルバ',u'問題を入力してください:').result.strip().translate(T) S(map(int,P))

sudoku_solver.pyを起動するにはファイル一覧からsudoku_solver.pyをタップする。すると以下のような5つのアイコン(左から順に、コンソール上での起動、バックグラウンドでの起動、編集、ファイル名の変更、削除)が現れるのでそのうち左の2つのアイコンのどちらかを選ぶことで起動できる。今回はバックグラウンドで起動した。


起動後、以下のようなダイアログが出てくるので問題となる数独を入力する。空白部分は * もしくは . とする。


以下が入力が完了した状態。ここでOKボタンを押すと解析が開始される。


解析が完了すると以下のような解答が表示される。


スクリプトの共有

これでスクリプトによるAndroidアプリを作成することができた。作成したアプリを別の人にも使ってもらうために公開したい場合はどうすればよいのだろうか。ソースコードをそのまま公開することもできるが、それだと一々Android端末にコピーしなくてはならず、場合によっては打ち込み直すはめになり、面倒だ。そこで、QRコードを使ったスクリプトの共有がある。4,296文字という制限があるが、今回のような短いコードでは十分だ。

QRコードを作成するためにQR Code Generatorを利用する。ここのサイトで"Contents"を"Text"とし、"Text content"に、先頭行をファイル名(上述のスクリプトの場合 sudoku_solver.py )としたスクリプトのソースコードを入れる。"Barcode size"は"L"とする。これで"Generate"ボタンを押せばQRコードが生成される。

次にQRコードからソースファイルに戻す方法だが、Android端末でSL4Aを起動し、メニューボタンから"Add"を選ぶ。表示されるリストから"Scan Barcode"でQRコードを読み込むだけだ。ただし、Android 1.6以前ではバーコードスキャナーが入っていないので、Android MarketからZXingのQRコードスキャナー(無料)をインストールしておくこと。


これで簡単にコードを共有することができた。因みにこの記事の先頭に表示しているQRコードは今回作成した数独ソルバのソースコードになっている。

***

まだドラフト段階だがAndroidパッケージ(APK)の作成も可能だし、前回ではPCからadbによるコマンドラインでの操作を取り上げたが、いずれもPCとAndroid端末を繋いでの操作になり青空プログラミングという今回の趣旨から外れてしまうし、一回で説明するには記事が長くなってしまうので今回は割愛することにした。それらについては別の機会に書くかもしれない。

続きを読む...

2010年9月7日火曜日

アルゴリズムの素晴らしさに気付かせてくれたのはエラトステネスの篩だった

このブログ記事をはてなブックマークに追加

Haskellによるエラトステネスの篩(sieve of Eratosthenes)の美しい実装を見て、初めてアルゴリズムの素晴らしさに気付かせてくれたのがエラトステネスの篩だったことを思い出した。たしか中学生の頃だ。そこで、当時を懐かしみながら簡単な実装を書き留めておくことにした。とりあえず、Haskell, C++, Pythonの実装を以下に示す。コードは比較的短いが、実行効率を優先させているわけではない。

Haskell

これはHaskellのサンプルコードでよく出てくる無限リストと遅延評価による実装だが、とても分かりやすいし、美しいコードだと思う。

primes = sieve [2..] sieve (p:xs) = p : sieve [x | x <- xs, x `mod` p /= 0]

以下のように関数takeを使って必要な分だけ素数を取り出すことができる。ただし、実行効率はあまり良くない。

take 10 primes [2,3,5,7,11,13,17,19,23,29]

C++

次にC++を使って実装してみた。ここではC++0xを使っている。そのほうが簡潔で分かりやすく書けるし、これからはC++0xがより使われ、普及して欲しいという意味もある。因みにgccではバージョン4.5以降、Intelコンパイラではバージョン11.0以降、Visual C++では2010(16.0)以降でコンパイルできる。

std::vector<int> primes; for (int i = 3; i < 100; i += 2) primes.push_back(i); auto end = primes.end(); for (auto x = primes.begin(); *x * *x <= *(end-1); ++x) end = std::remove_if(x + 1, end, [&x](int p){ return p % *x == 0; }); primes.erase(end, primes.end()); for (auto p = primes.begin(); p != primes.end(); ++p) std::cout << *p << " "; std::cout << std::endl;

上記のコードでは3から100までの素数を表示する。ノートPC (Core 2 Duo T9800 2.93 GHz / Visual Studio 2010)を使って1000万までの素数を生成してファイルに書き出すのにかかった時間は約2秒だった。

そういえば以前にC++のテンプレートで素数を求めたことがあったな。エラトステネスの篩ではなかったけど。

Python

最後にPythonによる実装を示す。効率はあまり良くないかも。

primes = range(3, 100, 2) for i in range(len(primes)): if primes[i]**2 > primes[-1]: break primes[i+1:] = filter(lambda p: p % primes[i] != 0, primes[i+1:]) print primes

これをそのままワンライナーに。

python -c "import sys;globals().__setitem__('P',range(3,100,2));[P.__setslice__(i+1,len(P),filter(lambda p:p%P[i]!=0,P[i+1:]))for i in range(len(P))if i<len(P)and P[i]**2<=P[-1]];[sys.stdout.write('%d '%p)for p in P]"

上記のコードではそれぞれ、赤字の数値が求める素数の上限値となっている。

続きを読む...