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に教える必要があります。
コンパイルが終ってTest_.classができれば、java -jar ij.jarなりして ImageJを実行します。一番右のPluginsというメニューの中に Testという項目ができているでしょう。そうしたら、あとは画像を開いて その項目を選ぶだけです。 上の例では、画像の縦横を取得し、1つ1つのPixelを 読むという動作をします。画像は変更されず、見かけ上はなにも起きません。
次は、それぞれの画素に対して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;
}
}
おそらく実行すれば上のようなdialogが現れるでしょう。 Change imageにチェックをつけて実行すれば画像が変更され、 そうでなければ単に計測が行なわれます。
他にも色々な関数が存在するので、APIを見て試してみて下さい。
I think that, like species, languages will form evolutionary trees, with
dead-ends branching off all over. We can see this happening already. Cobol,
for all its sometime popularity, does not seem to have any intellectual
descendants. It is an evolutionary dead-end-- a Neanderthal language.
I predict a similar fate for Java. People sometimes send me mail saying, "How
can you say that Java won't turn out to be a successful language? It's already
a successful language." And I admit that it is, if you measure success by
shelf space taken up by books on it (particularly individual books on it), or
by the number of undergrads who believe they have to learn it to get a job.
When I say Java won't turn out to be a successful language, I mean something
more specific: that Java will turn out to be an evolutionary dead-end, like
Cobol.
This is just a guess. I may be wrong. My point here is not to dis Java, but to
raise the issue of evolutionary trees and get people asking, where on the tree
is language X? The reason to ask this question isn't just so that our ghosts
can say, in a hundred years, I told you so. It's because staying close to the
main branches is a useful heuristic for finding languages that will be good to
program in now.
-- Paul Graham
-- The Hundred-Year Language ( http://www.paulgraham.com/popular.html )
Hi Omer! Mazal Tov on Chen and yours marriage. It reminds me of a quote from
Charlotte Bronte's Jane Eyre:
"At this period she married, removed with her husband (a clergyman, an
excellent man, *almost worthy of such a wife*) to a distant county, and
consequently was lost to me."
Well, in your case I can say that both of you are almost worthy of each other.
Congrats again!
Shlomi Fish in: http://omerm.livejournal.com/36505.html?thread=43673#t43673
-- Shlomi Fish
-- Shlomi Fish's Aphorisms Collection ( http://www.shlomifish.org/humour.html )