BrokenCamera for Android (Version 6)

なんか Android マーケットでマイナーバージョンの上げ方がよく分からなくて、メジャーバージョンがどんどん上がっていってる。色々機能追加したのでよかったら使ってみてください。

画質が良くなった/写真の保存場所が変わった

前はブロックノイズが立ってて結構汚い写真が撮れてしまっていたんだけど、改善してだいぶきれいになったと思う。あと画質を良くするのに必要だったので、仕方なく写真の保存場所を /sdcard/BrokenCamera/ に変更しました。

フィルタを選べるようになった/プラグインを 3 つ追加した

メニューキーを押すとこんな感じでフィルタを選べるようになった。

http://farm6.static.flickr.com/5056/5460840416_df4db84ecd.jpg

MonkeyGlitch っていうのが前から使えたデフォルトの glitch で、そのほかに適当な感じのやつを 3 つ追加しておいた。

  • Abstraction (勝手に巨大な図形で塗りつぶす)

http://farm6.static.flickr.com/5211/5458451676_4d3287d451_o.jpg

http://farm6.static.flickr.com/5020/5456580736_bb629f6007_o.jpg

http://farm6.static.flickr.com/5258/5460207343_3ee7fc6405_o.jpg

次期予定

そろそろ飽きてきた感もあるんだけど、とりあえず yuiseki さんと hkhumanoid さんに報告をもらったバグはまだ調査中です。

個別プラグインだと Kudanize とか HSyncGlitch とか移植したり、勝手に意味分からないキャプション入れるのとか Databending using Audacity « Antonio Roberts みたいのとか作ってみたい。

あと UI が分かりづらいってよく言われるので、今の業務用っぽさもいい気はしてるんだけど、ひまあったらもう少し分かりやすくしたいです。

BrokenCamera を修正して簡単にいろんな壊れ方を試せるようにした

画像を壊すアルゴリズムの部分だけ別ファイルに分けて、ファイルを追加すれば自動でオプションメニューに表示されるように修正した。

追加方法

Breaker クラスを継承した自分のクラスを記述する (以下はこれJava で実装したもの)。

  • src/cc/omora/android/brokencamera/breakers/SwapHeightAndWidth.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 パッケージ配下のクラス一覧を取得している)。

http://farm6.static.flickr.com/5296/5444422016_dff9173153.jpg

ビットマップのデータをいじりたい場合はこんな感じで書く。

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 してください。

glitch yesterday

http://clipp.jp/assets/12/12a23b608f383a29ea990ed60a2cf2b6_500.jpg
http://farm6.static.flickr.com/5297/5400085458_0822d14497_o.jpg

glitch と呼んでいいのかよく分からないけど、Android でカメラアプリを作っていて見つけた画像の壊し方。JPEG の SOF セグメントに保存されている縦横幅の情報を正しくない値に書き換えている (サンプルは縦横を交換)。誰かもうやってそうな感じする。JPEG のバイナリをいじるのは gist:484718 を参考にした。

ぶっ壊れた写真しか撮れないカメラ (BrokenCamera for Android)

http://farm6.static.flickr.com/5174/5397850608_0d285023ab_s.jpg

http://farm6.static.flickr.com/5180/5415295213_41e0099990.jpg

http://farm6.static.flickr.com/5288/5378307020_f5281d5b2d.jpg

http://cdn.f.st-hatena.com/images/fotolife/m/motemen/20110129/20110129220228.jpg

http://farm6.static.flickr.com/5281/5370261826_b39d075609.jpg

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

http://farm6.static.flickr.com/5287/5376389274_0a7e26a7ce.jpg

その他のコマンド

その他のサブコマンドとして 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 から文字列を検索できるらしい。ChaSenMeCab で、形態素解析を行うために必要な 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]
- さじ
  - さ [差(名詞)]
- じ
  - じ [じ(助詞、意志打ち消し)/字(名詞)]

うまく動いているっぽい。

実装の特徴

  • TAIL 配列による効率化は行っていない
  • 終端文字は MeCab と同じく '\0' (NULL)
  • 深さ優先探索の実装に再帰を用いていない
  • マルチバイト文字も 1 バイトに区切って保存している

TODO

  • 備忘録として DoubleArray についての分かりやすい解説を書く
  • 大量データの辞書 (mecab-ipadic、はてなキーワードWikipedia) でパフォーマンス測定を行う
  • 深さ優先探索再帰を使ったバージョンを作ってパフォーマンス比較を行う
  • NArray を使って高速化する- TAIL 配列を使って高速化する
  • darts を参考にして子ノード一覧取得処理を fetch メソッドに分ける

後記

アルゴリズムとか計算機科学の素養がなくて Double-Array 自体を理解するのにやたら時間がかかった。ちゃんとしたもの作れているか自信ないので、ソースや文章になんか間違ってるところあったら教えてもらえると嬉しいです。