だけどこれ、よく見ると汚いよね。特に電線のあたり。
それまで、画像のスケーリングやアフィン変換は Processing に任せていましたが、どうも内部で単純に画素を間引いているらしく、いわゆる高周波成分を含んだ画像に対して処理を施すと仕上がりが残念な事になってしまうのです。
そこで、画像を加工してもジャギーが目立たなくなるように、このたびプログラムを修正してみました。
まずは、新システムで生成したセロテープぺったん画像を以下に示します。
手ごろな写真がなかったので、Windows のサンプルピクチャフォルダに入っていた画像で試してみました。
うん。なんかセロテープの位置がほんの少しおかしいのはご愛嬌として、不自然なエッジやジャギーが低減されたおかげで、画像品質の劣化が劇的に改善された気がします(ただ、一番下の木の画像は、細部が少しぼやけてしまった気もします)。
タネを明かすと、Processing の画像クラスである PImage を、一旦 Java の BufferedImage に変換して、Java の世界で高品質な拡大縮小メソッドを適用し、その結果をふたたび Processing で扱えるように PImage に戻すという流れを採りました。
実装例を示しましょう。
まず、PImage から BufferedImage に変換するプログラムの例はこんな感じです。
BufferedImage PImage2BImage(PImage pImg) { BufferedImage bImg = new BufferedImage(pImg.width, pImg.height, BufferedImage.TYPE_INT_ARGB); for(int y = 0; y < bImg.getHeight(); y++) { for(int x = 0; x < bImg.getWidth(); x++) { bImg.setRGB(x, y, pImg.pixels[y * pImg.width + x]); } } return bImg; }
次に、BufferedImage オブジェクトのサイズ変更の処理は以下の通り。
PImage BImage2PImage(BufferedImage bImg) { PImage pImg = createImage(bImg.getWidth(), bImg.getHeight(), ARGB); for(int y = 0; y < pImg.height; y++) { for(int x = 0; x < pImg.width; x++) { pImg.pixels[y * pImg.width + x] = bImg.getRGB(x, y); } } return pImg; }
この結果を、以下のメソッドでふたたび PImage オブジェクトに変換します。
PImage BImage2PImage(BufferedImage bImg) { PImage pImg = createImage(bImg.getWidth(), bImg.getHeight(), ARGB); for(int y = 0; y < pImg.height; y++) { for(int x = 0; x < pImg.width; x++) { pImg.pixels[y * pImg.width + x] = bImg.getRGB(x, y); } } return pImg; }
これで、ジャギーの目立たないリサイズが実現できました。
回転も同様に処理できますが、拡大縮小に比べてソースが少々ややこしいので省略します。
そんなこんなで、今日のまとめ(というか、ちょっと言いたい事)。
Processing の API が画像処理の実装を極端に簡単化した背景には、リアルタイム性を重視したかったという意図があるように思えます。
ですが、Web アイコンやサムネイル等の加工・編集等の処理の自動化という(リアルタイム性を重視しない)用途においても、Processing は活躍できると考えています。
そんなわけで、そういう事を考えている人が、ぼく以外にいらっしゃるかも知れないなと思い、ちょっと邪道なテクニックを使って Processing のレンダリング品質向上に関する試みを行いました。まる。
【2011年7月17日追記】
試しに、今まで撮ったトイカメラの画像を、新しいプログラムで改めて加工してみました。
ほんのちょっとだけ、仕上がりの品質が向上しました。
0 件のコメント:
コメントを投稿
ひとことどうぞφ(・ω・,,)