JAVAの最適化(4)
今日は90度回転のアルゴリズムについて考えてみます。
通常であれば、新しいイメージをnewして、そこに回転した画像を置いていきます。
public rotate90( ){ byte[] newbuf = new byte[ width * height ]; int sp = width * height - width; int spi = 0; int j = sp + spi; for( int i = 0 ; i <= width * height ; i++ ){ newbuf[ j ] = pixelbuf[ i ]; j -= width; if( j < 0 ){ spi++; j = sp + spi; } } int tmp = width; width = height; height = tmp; pixelbuf = newbuf; }
こんな感じでしょうか。
しかし、携帯において、画像1つ分のnewというのは、決して軽い処理ではありません。
なんとかして、newしないで画像を回転できないものかと考えてみました。
まず、2x3のイメージがあるとして、
0 1 2 3 4 5
このイメージを、
0 1 2 3 → 4 2 0 4 5 5 3 1
こうやって出来ればいいわけですね。
これが1次元配列になっているので、
0 → 4 1 → 2 2 → 0 3 → 5 4 → 3 5 → 1
こんな変換さえ出来ればいいと。
で、その式は、
j = width * (height - 1) - (i % height) * width + i / height;
となります。
で、それぞれiとjを交換してやれば出来上がりヽ(´ー`)ノ
違います(・∀・)
ちょっとシミュレートしてみると分かりますけど、
最初の状態 0 1 2 3 4 5 0番目と4番目を交換 4 1 2 3 0 5 1番目と2番目を交換 4 2 1 3 0 5 2番目と0番目を交換 1 2 4 3 0 5
2番目には0が入らなければならないのに、4が入ってしまいました。これは失敗です。
なぜこうなってしまったかというと、0と4は既に交換されているからです。
本当は0があったところには、4が入ってしまっているので、0と交換することが出来ないのです。
なんとかして、0を探し出して、2番目の値と交換してやる必要があります。
まず、0はどこにあるかというと、4番目にあります。
なぜ4番目にあるかというと、0番目と4番目を交換したからです。
どうやって4という数字を出したかというと、
j = width * (height - 1) - (i % height) * width + i / height;
この式のiに、0を代入した結果がそうなったからです。
つまり、既に交換されてしまっている番号の場合は、交換されてしまった先を上記の式で求めて、交換されていない番号と交換するのです。
交換されてしまっている番号とは、交換元より小さい数字のことです。
今回の場合は、2番目と0番目なので、交換元(2)より交換先(0)の方が小さいです。
なので、0からもう一度上記の式で計算して、4という数字を出して、2番目と4番目を交換することになります。
2番目と0番目を交換……出来ない 0番目から4番目を算出 2番目と4番目を交換 4 2 0 3 1 5 3番目と5番目を交換 4 2 0 5 1 3 4番目と3番目を交換……出来ない 3番目から5番目を算出 4番目と5番目を交換 4 2 0 5 3 1 5番目と1番目を交換……出来ない 1番目から2番目を算出 5番目と2番目を交換……出来ない 2番目から4番目を算出 5番目と4番目を交換……出来ない 4番目から3番目を算出 5番目と3番目を交換……出来ない 3番目から5番目を算出 5番目と5番目を交換 4 2 0 5 3 1
最後の1つは別に計算する必要はないですが、こうやって、自分以上の数字になるまで変換をして、自分以上の数字になれば交換をします。
これで90度回転を実装してみます。
public void rotate90( ){ int i,j; byte tmp; for( i = 0 ; i < width * height ; i++ ){ j = i; do{ j = width * (height - 1) - (j % height) * width + j / height; }while( j < i ); tmp = pixelbuf[ i ]; pixelbuf[ i ] = pixelbuf[ j ]; pixelbuf[ j ] = tmp; } i = width; width = height; height = i; }
出来上がりヽ(´ー`)ノ
これでnewせずに90度回転を実装できましたが、その代わり、最後の方はかなりの計算量になりそうです。
最後の方は、式を使って検索するのではなくて、自分の位置からシーケンシャルに探していった方が速いかもしれないですね。
とりあえずこれと同じようにして、270度回転も実装出来ます。
で、180度回転はflipX()とflipY()をすれば同じ結果が得られるので、そうすることにします。
こうして、90度ごとの回転アルゴリズムの実装が出来ましたとさ。ちゃんちゃん。
……ほんとにこのアルゴリズムで大丈夫なのかなぁ(;´Д`)