金子邦彦研究室プログラミングJava のプログラム例Java での画像フィルタの例

Java での画像フィルタの例

このページでは,画像ファイルの読み出しと書き込みや,画像処理を行う Java プログラムの見本を示す. ImageMagick と JMagick を使って簡単に作ることができる.

関連する外部ページ
http://kyle-in-jp.blogspot.com/search/label/JMagick : JMagick を使った画像処理プログラムの見本が載ったすばらしい Web ページ

必要となるソフトウェア

サンプルプログラム

要点

実行手順は, 「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();
        }

    }

}