BrokenCamera for Android (Version 6)
なんか Android マーケットでマイナーバージョンの上げ方がよく分からなくて、メジャーバージョンがどんどん上がっていってる。色々機能追加したのでよかったら使ってみてください。
画質が良くなった/写真の保存場所が変わった
前はブロックノイズが立ってて結構汚い写真が撮れてしまっていたんだけど、改善してだいぶきれいになったと思う。あと画質を良くするのに必要だったので、仕方なく写真の保存場所を /sdcard/BrokenCamera/ に変更しました。
フィルタを選べるようになった/プラグインを 3 つ追加した
メニューキーを押すとこんな感じでフィルタを選べるようになった。
MonkeyGlitch っていうのが前から使えたデフォルトの glitch で、そのほかに適当な感じのやつを 3 つ追加しておいた。
- Abstraction (勝手に巨大な図形で塗りつぶす)
- BlockNoise (わざと画質を落とす)
- SwapHeightAndWidth (JPEG SOF ヘッダの縦横幅を交換する)
次期予定
そろそろ飽きてきた感もあるんだけど、とりあえず yuiseki さんと hkhumanoid さんに報告をもらったバグはまだ調査中です。
個別プラグインだと Kudanize とか HSyncGlitch とか移植したり、勝手に意味分からないキャプション入れるのとか Databending using Audacity « Antonio Roberts みたいのとか作ってみたい。
あと UI が分かりづらいってよく言われるので、今の業務用っぽさもいい気はしてるんだけど、ひまあったらもう少し分かりやすくしたいです。
BrokenCamera を修正して簡単にいろんな壊れ方を試せるようにした
画像を壊すアルゴリズムの部分だけ別ファイルに分けて、ファイルを追加すれば自動でオプションメニューに表示されるように修正した。
追加方法
Breaker クラスを継承した自分のクラスを記述する (以下はこれを Java で実装したもの)。
package cc.omora.android.brokencamera.breakers; import cc.omora.android.brokencamera.Breaker; public class SwapHeightAndWidth extends Breaker { public void breakData(byte[] data, int level) { for(int i = 0; i < data.length; i++) { if((data[i] & 0xFF) == 0xFF && ((data[i+1] & 0xFF) == 0xC0 || (data[i+1] & 0xFF) == 0xC2)) { byte[] bytes = {data[i+5], data[i+6], data[i+7], data[i+8]}; data[i+5] = bytes[2]; data[i+6] = bytes[3]; data[i+7] = bytes[0]; data[i+8] = bytes[1]; } } } }
上記のファイルを追加するだけで、自動的にメニューに表示されて選択可能になる (リフレクションで breakers パッケージ配下のクラス一覧を取得している)。
ビットマップのデータをいじりたい場合はこんな感じで書く。
package cc.omora.android.brokencamera.breakers; import cc.omora.android.brokencamera.Breaker; import android.graphics.Bitmap; public class SwapHeightAndWidth extends Breaker { public void breakData(Bitmap bitmap, int level) { // operate on bitmap data } }
その他
エンドユーザ的には次のバージョンから SwapHeightAndWidth が使えるようになる(はず)。あとおもしろいアルゴリズム知ってる人いたらぜひなんか追加して pull request してください。
参考
- アプリケーションパッケージ(.apk)中のクラスを列挙する - Kazzzの日記
- Twitter / @fuba: glitch camera、アルゴリズムじぶんで書けたらおもしろそう (iPhone の glitch camera への言及)
glitch yesterday
glitch と呼んでいいのかよく分からないけど、Android でカメラアプリを作っていて見つけた画像の壊し方。JPEG の SOF セグメントに保存されている縦横幅の情報を正しくない値に書き換えている (サンプルは縦横を交換)。誰かもうやってそうな感じする。JPEG のバイナリをいじるのは gist:484718 を参考にした。
ぶっ壊れた写真しか撮れないカメラ (BrokenCamera for Android)
- https://market.android.com/details?id=cc.omora.android.brokencamera
- https://github.com/tily/java-android-broken-camera
Usage: - Touch screen to take picture - Volume keys to control glitch level Maybe works on: - HTC Desire HD - HTC Desire Z Note: - It's still beta version. Please report bugs!
とりあえず Android で何か作ってみたいなと思って作ってみたやつ。Glitch のアルゴリズム自体は猿でもできる横のグリッチで 5 行ぐらいしか書いていない。
縦書きビューアの音量キー上下押すとページをめくれるのがいいなと思ってて、真似して音量キーの動作を上書きして画像の壊れる度合いを調整できるようにしてる。
プラガブルにして色々なアルゴリズムを試せるようにしたりしたい、リフレクションを使って特定ディレクトリ配下にソースファイルを置けばそのままメニューに表示されて選択できるような実装にしたい。
あとすでに中国の人に「貧しい人々。とにかく、何もDHDオープン」とか言われてるので、自分の端末以外でちゃんと動く自信全然ない。使ってみて動かなかったりしたらバグレポートもらえるとすごく助かります。
Links:
1 枚の Java ソースファイルだけで Android アプリを管理できるようにする rur コマンド
Android アプリもグリモンみたいにファイル 1 枚で gist とかで管理できたらいいなと思って、Java ファイル 1 枚からパッケージ作成したり端末にインストールしたりできるコマンドを作ってみた。
本格的に作るなら Processing みたいな Java をラップするような感じになるんだろうけど、実験として思いついたのをとりあえず作った感じです。
実装もぜんぜんたいしたことしてなくて、~/.rur 配下にプロジェクト毎にディレクトリを切って、android,adb,ant コマンドを実行しているだけ。
使い方
rur コマンドに実行権限がありパスが通っているディレクトリに置かれているのが前提。
rur init コマンドで Android アプリ用のソースファイルを生成する。
$ rur init MyActivity.java
MyActivity.java ができる。
$ cat MyActivity.java package com.example.myactivity; import android.app.Activity; import android.os.Bundle; public class MyActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } }
あとは好きなように編集して rur start すれば、コンパイル・端末インストール・アプリ起動までやってくれる。
$ rur start MyActivity.java
その他のコマンド
その他のサブコマンドとして debug, install, clean が使えて、該当する ant のタスクを実行してくれる。
$ rur debug MyActivity.java $ rur install MyActivity.java $ rur clean MyActivity.java
制限事項とか
複数ソースファイルにまたがったアプリとかには使えないし、res 配下のレイアウト定義や文言定義用の XML ファイルも使えない (手動で ~/.rur 配下をいじれば使えるけど)。
それと致命的な欠点として AndroidManifest.xml を考慮していなかったのでカメラを使ったりネットに接続したりといった権限を付与できないのに今気付いた。-u CAMERA とか -u INTERNET とかつければ AndroidManifest.xml をうまく書き換えてくれるようにしたい。
あと個人的に追加した UI 部品の import 文を書くのがめんどくさいので、android.jar を読み込んで足りない import 文を自動生成するのとか便利かなと思っている。
Ruby で Double-Array を実装して Common-Prefix Search を試してみる
Double-Array (ダブル配列) は トライ木を実装するためのアルゴリズムの 1 つで、他の実装よりも高速に TRIE から文字列を検索できるらしい。ChaSen や MeCab で、形態素解析を行うために必要な Common-Prefix Search (共通接頭辞探索) を行うために使われている。これを理解のために Ruby で実装してみた。
基本的な動作確認
ここに書いてある bird, bison, cat の 3 単語で構築した Double-Array の例。
コード:
require 'trie/double_array' da = Trie::DoubleArray.new da.build(%w|bird bison cat|) 0.upto(da.base.length) do |i| next unless da.base[i] puts "node[#{i}]\tbase:#{da.base[i]}\tcheck:#{da.check[i]}" end
出力結果:
node[1] base:1 check:0 node[36] base:0 check:101 node[37] base:-1 check:111 node[38] base:-2 check:117 node[98] base:1 check:100 node[99] base:1 check:1 node[100] base:1 check:1 node[101] base:1 check:115 node[106] base:1 check:99 node[111] base:2 check:112 node[112] base:1 check:116 node[115] base:1 check:106 node[116] base:1 check:106 node[117] base:3 check:98
「文字コードとして ASCII を利用した場合」の図と照合してもだいたい合っている (末端ノードの base の値が異なるのは Darts に倣って元単語配列のインデクス番号をマイナスの値にしたものを格納しているため)。
Common-Prefix Search
小さな辞書を作って Common-Prefix Search を試してみる。
コード:
require 'trie/double_array' # 適当に作った CSV の辞書 (「表層,意味」の形式) dic = <<EOD あめ,雨(名詞) あめりか,アメリカ(名詞) か,か(助詞、疑問) か,蚊(名詞) かに,蟹(名詞) さ,差(名詞) じ,じ(助詞、意志打ち消し) じ,字(名詞) そで,袖(名詞) で,で(接続詞) でも,デモ(名詞) に,二(数詞) に,に(接続詞) ぬらさ,濡らさ(動詞、未然形) ふ,麩(名詞) ふる,降る(動詞、終止形) ふる,降る(動詞、連体形) め,目(名詞) め,芽(名詞) も,も(接続詞) り,利(名詞) りか,理科(名詞) EOD # 単語の表層がユニークなものを配列としてまとめる words, features = [], [] prev, tmp = '', [] dic.each_with_index do |line, i| word, feature = line.chomp.split(',') if i == 0 || word == prev tmp << feature else words << prev features << tmp tmp = [feature] end prev = word end words << prev features << tmp # Double-Array の構築 da = Trie::DoubleArray.new da.build(words) # Common-Prefix Search key = 'ふるあめりかにそでもぬらさじ' while key != '' res = da.common_prefix_search(key) puts "- #{key}" if res && res.size > 0 res.each do |i, len| w, f = words[i][0,len], features[i] puts " - #{w} [#{f.join('/')}]" end else puts " - [no match]" end key = key.split(//u)[1..-1].join end
出力結果:
- ふるあめりかにそでもぬらさじ - ふ [麩(名詞)] - ふる [降る(動詞、終止形)/降る(動詞、連体形)] - るあめりかにそでもぬらさじ - [no match] - あめりかにそでもぬらさじ - あめ [雨(名詞)] - あめりか [アメリカ(名詞)] - めりかにそでもぬらさじ - め [目(名詞)/芽(名詞)] - りかにそでもぬらさじ - り [利(名詞)] - りか [理科(名詞)] - かにそでもぬらさじ - か [か(助詞、疑問)/蚊(名詞)] - かに [蟹(名詞)] - にそでもぬらさじ - に [二(数詞)/に(接続詞)] - そでもぬらさじ - そで [袖(名詞)] - でもぬらさじ - で [で(接続詞)] - でも [デモ(名詞)] - もぬらさじ - も [も(接続詞)] - ぬらさじ - ぬらさ [濡らさ(動詞、未然形)] - らさじ - [no match] - さじ - さ [差(名詞)] - じ - じ [じ(助詞、意志打ち消し)/字(名詞)]
うまく動いているっぽい。
実装の特徴
TODO
後記
アルゴリズムとか計算機科学の素養がなくて Double-Array 自体を理解するのにやたら時間がかかった。ちゃんとしたもの作れているか自信ないので、ソースや文章になんか間違ってるところあったら教えてもらえると嬉しいです。