[ Main Page ]

ImageJのPlug-inを作る

ImageJでPlug-inを作る時の参考になれば幸いです。

はじめの一歩

画像処理Plug-inは、Interface ij.plugin.filter.PlugInFilterの 実装として作ります。ここではまず、Test_というPlug-inを 作ってみます。この場合、少なくとも実装する必要があるのは、 void run(ImageProcessor ip)と int setup(java.lang.String arg, ImagePlus imp)です。 setup()は、Plug-in Filterが処理できる画像の種類を 返す初期関数、run()は、実際の処理関数です。 詳しくは、API referenceを参照して下さい。 Plug-inの名前には_が含まれている必要があるようです。

import ij.*;
import ij.process.*;
import ij.gui.*;
import ij.plugin.filter.*;

public class Test_ implements PlugInFilter
{
    public int setup(String arg, ImagePlus img)
    {
        if (IJ.versionLessThan("1.28e"))
            return DONE;
        else
	    // どの種類の画像も扱えるし、マルチページtiff
	    // なども扱えることを言う。
            return DOES_ALL+DOES_STACKS;
    }

    public void run(ImageProcessor ip)
    {
        // 幅を取得
        int width = ip.getWidth();
        // 高さを取得
        int height = ip.getHeight();
        
        int[] p1 = new int[3];
        
        // load
        for (int y=1; y<height; y++)
            {
                for (int x=0; x<width; x++)
                    {
		        // (x,y)のPixelデータを取得。
			// int[] は、RGBである。

			// !!!! 注意 !!!!
			// 以降の例題ではほとんどこのgetPixelを使っていますが、
			// これはプログラムを見やすくするためです。
			// 画像の画素数だけ呼び出すので、
			// 実用的ではありません。実際に使う場合は、
			// getPixelsなどを使って高速化してください。

                        p1 = ip.getPixel(x, y, p1);
                    }
            }
    }    
}

この内容をTest_.javaという名前で、 ImageJのディレクトリの中のpluginsというディレクトリに 保存してください。

コンパイルする時は、以下のようにして、ImageJのライブラリの 位置をjavacに教える必要があります。

teru@server:/tmp/ImageJ/plugins$ CLASSPATH=../ij.jar javac Test_.java

コンパイルが終ってTest_.classができれば、java -jar ij.jarなりして ImageJを実行します。一番右のPluginsというメニューの中に Testという項目ができているでしょう。そうしたら、あとは画像を開いて その項目を選ぶだけです。 上の例では、画像の縦横を取得し、1つ1つのPixelを 読むという動作をします。画像は変更されず、見かけ上はなにも起きません。

簡単なFilter

次は、それぞれの画素に対してFilterをかけてみましょう。ここでは、 それぞれの画素に対し、そこが明るさで200より小さければ 黒く、それ以外はそのままというものを作ってみます。今度は、Test2_.java という名前にして下さい。

import ij.*;
import ij.process.*;
import ij.gui.*;
import ij.plugin.filter.*;

public class Test2_ implements PlugInFilter
{
    // 明るさ Y = 0.299R+0.587G+0.114B
    // 色差 Cr = 0.500R-0.419G-0.081B
    // 色差 Cb = -0.169R-0.332G+0.500B

    // 画素から明るさを計算
    private double getY(int[] a)
    {
        if (a.length != 3)
            return 0;
        return 0.299*((double)a[0])+0.587*((double)a[1])+0.114*((double)a[2]);
    }

    public int setup(String arg, ImagePlus img)
    {
        if (IJ.versionLessThan("1.28e"))
            return DONE;
        else
	    // どの種類の画像も扱えるし、マルチページtiff
	    // なども扱えることを言う。
            return DOES_ALL+DOES_STACKS;
    }

    public void run(ImageProcessor ip)
    {
        // 幅を取得
        int width = ip.getWidth();
        // 高さを取得
        int height = ip.getHeight();
        
        int[] p1 = new int[3];
        int[] black = {0, 0, 0};

        // load
        for (int y=1; y<height; y++)
            {
                for (int x=0; x<width; x++)
                    {
		        // (x,y)のPixelデータを取得。
			// int[] は、RGBである。
                        p1 = ip.getPixel(x, y, p1);

			// 明るさが100より小さければ黒にしてしまう。
			if (getY(p1) < 100)
			    ip.putPixel(x, y, black);
                    }
            }
    }    
}

ここでは、putPixelという関数で出力しています。

簡単な計測と表の出力

今度は、画像に対し、計測を行なってその結果を表で出力 するものを考えてみましょう。

import ij.*;
import ij.process.*;
import ij.gui.*;
import ij.plugin.filter.*;

public class Test3_ implements PlugInFilter
{
    // 明るさ Y = 0.299R+0.587G+0.114B
    // 色差 Cr = 0.500R-0.419G-0.081B
    // 色差 Cb = -0.169R-0.332G+0.500B

    // 画素から明るさを計算
    private double getY(int[] a)
    {
        if (a.length != 3)
            return 0;
        return 0.299*((double)a[0])+0.587*((double)a[1])+0.114*((double)a[2]);
    }

    public int setup(String arg, ImagePlus img)
    {
        if (IJ.versionLessThan("1.28e"))
            return DONE;
        else
	    // どの種類の画像も扱えるし、マルチページtiff
	    // なども扱えることを言う。
            return DOES_ALL+DOES_STACKS;
    }

    public void run(ImageProcessor ip)
    {
        // 幅を取得
        int width = ip.getWidth();
        // 高さを取得
        int height = ip.getHeight();
        
        int[] p1 = new int[3];

        // 表のsetup
	// 例えば、一行に3つの事項を出力するなら、
	// 1 \t 2 \t 3と、3つのタイトルを\tで区切って書く。
        IJ.setColumnHeadings("x\t y\t bright");

        // load
        for (int y=1; y<height; y++)
            {
                for (int x=0; x<width; x++)
                    {
		        // (x,y)のPixelデータを取得。
			// int[] は、RGBである。
                        p1 = ip.getPixel(x, y, p1);

			// 明るさが500より小さければ、
                        // 場所と明るさを表に出力
			// 出力方法はさっきと同じように\tで区切る
			if (getY(p1) < 500)
			    IJ.write(x + "\t" + y + "\t" + getY(p1));
                    }
            }
    }    
}

実行前にユーザからなんらかの入力を受ける

先ほどの例でいえば、明るさがどの値より大きいのかを 実行毎に指定できるようにしてみましょう。これには GenericDialogを使用します。

import ij.*;
import ij.process.*;
import ij.gui.*;
import ij.plugin.filter.*;

public class Test4_ implements PlugInFilter
{
    // 明るさ Y = 0.299R+0.587G+0.114B
    // 色差 Cr = 0.500R-0.419G-0.081B
    // 色差 Cb = -0.169R-0.332G+0.500B

    // 画素から明るさを計算
    private double getY(int[] a)
    {
        if (a.length != 3)
            return 0;
        return 0.299*((double)a[0])+0.587*((double)a[1])+0.114*((double)a[2]);
    }

    public int setup(String arg, ImagePlus img)
    {
        if (IJ.versionLessThan("1.28e"))
            return DONE;
        else
	    // どの種類の画像も扱えるし、マルチページtiff
	    // なども扱えることを言う。
            return DOES_ALL+DOES_STACKS;
    }

    public void run(ImageProcessor ip)
    {
        // dialogの表示。キャンセルでそのまま戻る。
        if(getParam())
	    return ;
        
        // 幅を取得
        int width = ip.getWidth();
        // 高さを取得
        int height = ip.getHeight();
        
        int[] p1 = new int[3];
        int[] black = new int[3];
        black[0] = 0; black[1] = 0; black[2] = 0;

        // 表のsetup
	// 例えば、一行に3つの事項を出力するなら、
	// 1 \t 2 \t 3と、3つのタイトルを\tで区切って書く。
        IJ.setColumnHeadings("x\t y\t bright");

        // load
        for (int y=1; y<height; y++)
            {
                for (int x=0; x<width; x++)
                    {
		        // (x,y)のPixelデータを取得。
			// int[] は、RGBである。
                        p1 = ip.getPixel(x, y, p1);

			// 明るさが50より小さければ、
                        // 場所と明るさを表に出力
			// 出力方法はさっきと同じように\tで区切る
			if (getY(p1) < brightLimit)
			    IJ.write(x + "\t" + y + "\t" + getY(p1));

			// もし画像変更が許可されていれば
			// 条件に合わないところを黒で塗りつぶす
			else if (ifChange)
			    ip.putPixel(x, y, black);
                    }
            }
    }

    // staticにしておくと、次にPlug-inを実行した時も
    // 以前の入力結果が保存されている。
    static int brightLimit = 50;

    // static でなければ実行毎に初期化されます。
    private boolean ifChange = false;

    // ここでユーザからParameterを取得。
    // 実行前にdialogが出ます。
    private boolean getParam()
    {
        GenericDialog gd = new GenericDialog("Enter Parameters.",
                                             IJ.getInstance());
        gd.addNumericField("", brightLimit, 0);
	gd.addCheckbox("change image", ifChange);
	// 同じようにして他のParameterも取得できます。        

	// dialog表示
        gd.showDialog();
        
	// dialogでキャンセルボタンが押された時
	// (ちょっと汚い処理の仕方です。Javaらしくするなら例外を使うのかな。)
        if (gd.wasCanceled()) 
	    {
                return true;
            }
        
	// ここで取得結果を代入。詳しくはAPI docを参照して下さい。
        brightLimit = (int) gd.getNextNumber();
	ifChange = (boolean) gd.getNextBoolean();
	// 他のParameterもここで取得可能です。

	return false;
    }
}

GD Screen Shot

おそらく実行すれば上のようなdialogが現れるでしょう。 Change imageにチェックをつけて実行すれば画像が変更され、 そうでなければ単に計測が行なわれます。

他にも色々な関数が存在するので、APIを見て試してみて下さい。

Stray XSLT code causes more deaths than road accidents.

    -- Shlomi Fish
    -- XSLT Facts by Shlomi Fish and Friends ( http://www.shlomifish.org/humour/bits/facts/XSLT/ )

Chandler: She's amazing! She makes the women that I dream about look like
short, fat, bald men!

Monica: Well, go over to her! She's not with anyone.

Chandler: Oh yeah, and what would my opening line be? 'Excuse me.
Blarrglarrghh.'

Rachel: Oh, c'mon. She's a person, you can do it!

Chandler: Oh please, could she be more out of my league? Ross, back me up
here.

Ross: He could never get a woman like that in a million years.

Chandler: Thank you, buddy.

Phoebe: Oh, oh, but y'know, you always see those really beautiful women with
those really nothing guys. You could be one of those guys!

    -- David Crane & Marta Kauffman
    -- "Friends" (T.V. Show) ( http://en.wikipedia.org/wiki/Friends )


Powered by UNIX fortune(6)
[ Main Page ]