Java での画像フィルタの例
このページでは,画像ファイルの読み出しと書き込みや,画像処理を行う Java プログラムの見本を示す. ImageMagick と JMagick を使って簡単に作ることができる.
【関連する外部ページ】
http://kyle-in-jp.blogspot.com/search/label/JMagick : JMagick を使った画像処理プログラムの見本が載ったすばらしい Web ページ
必要となるソフトウェア
- Eclipse のWebページの記述に従って,Eclipse のインストールが終わっていること.
- 「Java から ImageMagick の機能を使う(JMagick を使用)」のWebページの記述に従って,JMagick のインストール等が終わっていること.
サンプルプログラム
要点
- Eclipse でのパッケージ名は次のようにしている.
- パッケージ名: hoge.hoge.com
- メインとなるクラス名: HelloWorld
- JMagick を使った画像ファイルの読み込み(簡単です).
次のように書く.FILENAME がファイル名.width, height に縦横のサイズが入ります.
image = new MagickImage( new ImageInfo( FILENAME ) ); int width = (int)image.getDimension().getWidth(); int height = (int)image.getDimension().getHeight();
- 読み込んだ画像ファイルの画素値を,Java 配列にコピー(簡単です).
次のように書く.
byte bytes[] = new byte[ width * height * 4 ]; // red, green, blue, alpha image.dispatchImage(0, 0, width, height, "RGBA", bytes);
- Java 配列を、画像ファイルに書き込む
次のように書く.「image.setFileName("c:\\R\\sample.png");」でファイル名を変えます(元のファイルを上書きしたくないので).
image.constituteImage(width, height, "RGBA", filter( width, height, bytes ) ); image.setFileName("c:\\R\\sample.png"); image.writeImage(new ImageInfo());
実行手順は, 「Java から ImageMagick の機能を使う(JMagick を使用)」 のWebページを見てください.
package hoge.hoge.com; import magick.ImageInfo; import magick.MagickException; import magick.MagickImage; public class HelloWorld { final private static String FILENAME = "C:\\R\\hoge.jpg"; // 縦横 2M だけ大きいサイズの真っ黒の画像の中心に,画像 bytes を貼り付け // 各画素は4バイト(1バイトが4つ分)であること. private static double[] imagepaste( final int width, final int height, byte bytes[], final int M ) { double data[] = new double[ (width + (2 * M)) * (height * (2 * M)) * 4 ]; // red, green, blue, alpha for( int i=0; i<height; i++ ) { for( int j=0; j<width; j++ ) { final int from = (i* width * 4) + (j*4); final int to = ((width+(2*M))*M*4) + (i*(width+(2*M))*4) + (M*4) + (j*4); data[ to ] = bytes[ from ]; // red data[ to + 1 ] = bytes[ from + 1 ]; // green data[ to + 2 ] = bytes[ from + 2 ]; // blue data[ to + 3 ] = bytes[ from + 3 ]; // alpha } // 左右の余白を黒でうめる for( int j=0; j<M; j++) { final int to = ((width+(2*M))*M*4) + (i*(width+(2*M))*4) + (j*4); data[ to ] = 0; // red data[ to + 1 ] = 0; // green data[ to + 2 ] = 0; // blue data[ to + 3 ] = 0; // alpha } for( int j=0; j<M; j++) { final int to = ((width+(2*M))*M*4) + (i*(width+(2*M))*4) + (M*4) + (width*4) + (j*4); data[ to ] = 0; // red data[ to + 1 ] = 0; // green data[ to + 2 ] = 0; // blue data[ to + 3 ] = 0; // alpha } } // 上を黒で埋める for( int i=0; i<M; i++ ) { for( int j=0; j<(width+(2*M)); j++ ) { final int to = (i*(width+(2*M))*4) + (j*4); data[ to ] = 0; // red data[ to + 1 ] = 0; // green data[ to + 2 ] = 0; // blue data[ to + 3 ] = 0; // alpha } } // 下を黒で埋める for( int i=0; i<M; i++ ) { for( int j=0; j<(width+(2*M)); j++ ) { final int to = ((width+(2*M))*(M+height)*4) + (i*(width+(2*M))*4) + (j*4); data[ to ] = 0; // red data[ to + 1 ] = 0; // green data[ to + 2 ] = 0; // blue data[ to + 3 ] = 0; // alpha } } return data; } // 画像の隅、縦横 2M 画素を切り抜く // 各画素は4バイト(1バイトが4つ分)であること.imagepaste の逆操作 private static byte[] imageclip( final int width, final int height, double data[], final int M ) { byte bytes[] = new byte[ width * height * 4 ]; // red, green, blue, alpha for( int i=0; i<height; i++ ) { for( int j=0; j<width; j++ ) { final int from = ((width+(2*M))*M*4) + (i*(width+(2*M))*4) + (M*4) + (j*4); final int to = (i * width * 4) + (j*4); bytes[ to ] = (byte) data[ from ]; // red bytes[ to + 1 ] = (byte) data[ from + 1 ]; // green bytes[ to + 2 ] = (byte) data[ from + 2 ]; // blue bytes[ to + 3 ] = (byte) data[ from + 3 ]; // alpha } } return bytes; } private static byte[] filter( int width, int height, byte bytes[] ) { // 余白つきの画像を生成 final int M = 1; double data[] = imagepaste( width, height, bytes, /* margin */ M ); // フィルタ本体 byte data2[] = new byte[ (width + 2) * (height * 2) * 4 ]; // red, green, blue, alpha for( int i=0; i<height; i++ ) { for( int j=0; j<width; j++ ) { final int at = ((width+(2*M))*M*4) + (i*(width+(2*M))*4) + (M*4) + (j*4); // 余白の分だけずれる final int atP = at - ((width+(2*M))*4); final int atN = at + ((width+(2*M))*4); final double red = (double) ( data[ atP - 4 ] + data[ atP ] + data[ atP + 4 ] + data[ at - 4 ] + data[ at ] + data[ at + 4 ] + data[ atN - 4 ] + data[ atN ] + data[ atN + 4 ] ) / 9; final double green = (double) ( data[ atP - 3 ] + data[ atP + 1 ] + data[ atP + 5 ] + data[ at - 3 ] + data[ at + 1 ] + data[ at + 5 ] + data[ atN - 3 ] + data[ atN + 1 ] + data[ atN + 5 ] ) / 9; final double blue = (double) ( data[ atP - 2 ] + data[ atP + 2 ] + data[ atP + 6 ] + data[ at - 2 ] + data[ at + 2 ] + data[ at + 6 ] + data[ atN - 2 ] + data[ atN + 2 ] + data[ atN + 6 ] ) / 9; final double alpha = (double) ( data[ atP - 1 ] + data[ atP + 3 ] + data[ atP + 7 ] + data[ at - 1 ] + data[ at + 3 ] + data[ at + 7 ] + data[ atN - 1 ] + data[ atN + 3 ] + data[ atN + 7 ] ) / 9; final int to = (i* width *4) + (j*4); data2[ to ] = (byte) red; data2[ to + 1 ] = (byte) green; data2[ to + 2 ] = (byte) blue; data2[ to + 3 ] = (byte) alpha; } } return data2; } public static void main(String[] args) { MagickImage image; try { // 画像ファイル読み込み image = new MagickImage( new ImageInfo( FILENAME ) ); int width = (int)image.getDimension().getWidth(); int height = (int)image.getDimension().getHeight(); // 画像データを,配列にコピー byte bytes[] = new byte[ width * height * 4 ]; // red, green, blue, alpha image.dispatchImage(0, 0, width, height, "RGBA", bytes); // フィルタ(filter)の実行結果を書き戻す image.constituteImage(width, height, "RGBA", filter( width, height, bytes ) ); image.setFileName("c:\\R\\sample.png"); image.writeImage(new ImageInfo()); } catch (MagickException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } } }