生物屋さんのためのゼロからのプログラミング

―忘れないための覚書 (たま~に更新)―

EclipseでImageJのPlugin作成 -数値から画像を作る-

今回は、数値から画像データを作る。

但し、僕がざっくり調べた感じでは、何もない状態からでは数値から画像データを作れなかったので、
ここでは、既存の画像ファイルの数値を入れ替える方法で、数値から画像データを作ることにした。

コードは下記。

import java.awt.BorderLayout;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import ij.IJ;
import ij.ImagePlus;
import ij.plugin.PlugIn;
import ij.process.ImageProcessor;

public class Make_Image implements PlugIn, ActionListener {

	ImagePlus imp;

	//数値から画像を作る
	public void makeImage() {
		ImagePlus imp0 = IJ.openImage("開く画像のディレクトリとファイル名");
		int h = imp0.getHeight();
		int w = imp0.getWidth();
		imp0.show();

		//数値から画像を作るためのキャンバス
		imp = imp0.duplicate();
		ImageProcessor ip = imp.getProcessor();

		float count = 0;

		for (int i = 0; i < w; i++) {
			for (int j = 0; j < h; j++) {
				ip.putPixelValue(i, j, count);
				if (count > 65535) count = 0;
				count++;
			}
		}

		imp.show();
		IJ.run(imp, "Enhance Contrast", "saturated=0.35");
	}

	//画像を名前を付けて保存する
	public void saveImage () {
		String saveName = addName ();
		IJ.saveAs(imp, "Tiff", saveName);
	}


	//保存する場所と名前を取得する
	String addName () {
		FileDialog fd = new FileDialog (new Frame(), "Add Name", FileDialog.SAVE);
		fd.setVisible(true);
		String fullpath = fd.getDirectory() + fd.getFile();
		fd.dispose();
		return fullpath;
	}

	//コントローラーの作成
	public void run (String arg) {
		JFrame frame = new JFrame ("Make");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setBounds (100, 100, 120, 120);
		JButton makeButton = new JButton ("Make");
		JButton saveButton = new JButton ("Save");
		makeButton.addActionListener(this);
		saveButton.addActionListener(this);
		makeButton.setActionCommand("Make");
		saveButton.setActionCommand("Save");
		makeButton.setBounds(15, 20, 90, 30);
		saveButton.setBounds(15, 50, 90, 30);

		JPanel pane = new JPanel ();
		pane.add(makeButton);
		pane.add(saveButton);
		pane.setLayout(null);
		frame.getContentPane().add(pane, BorderLayout.CENTER);
		frame.setVisible(true);
	}

	//ボタンを押した時の反応d
	@Override
	public void actionPerformed(ActionEvent e) {
		String cmd = e.getActionCommand();
		if (cmd.equals("Make")) {
			makeImage();
		} else if (cmd.equals("Save")) {
			saveImage();
		}
	}
}

ここではテストとして、下記の部分でグラデーションを作っている。

for (int i = 0; i < w; i++) {
	for (int j = 0; j < h; j++) {
		ip.putPixelValue(i, j, count);
		if (count > 65535) count = 0;
		count++;
	}
}

このプログラムを実行すると、
f:id:Aki-Miya:20180209074002p:plain
のコントローラーが立ち上がり、Makeボタンを押すと、
f:id:Aki-Miya:20180209074043p:plain
数値から画像を作るためのキャンバスとなる画像が開き (ここでは、ImageJにあるClown画像の16bit グレーイメージを使用)、
f:id:Aki-Miya:20180209074215p:plain
同時に、上の様に数値から作られた画像ができる。Saveボタンを押すと、この作成した画像を名前を付けて保存できるようにした。

JavaでJFileChooserで画像を開き、名前を付けて画像を保存する。

以前の記事画像を“名前を付けて保存する”。 - 生物屋さんのためのゼロからのプログラミングを少し変えて、同じ名前で拡張子の異なる画像を保存するコードを書いた。

コードは下記。

import java.awt.BorderLayout;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class SaveWithoutExtension extends JFrame implements ActionListener {

	BufferedImage img;
	MyPanel mypane;
	int h, w; //画像のサイズ

	public void openFile () {
		JFileChooser fc = new JFileChooser();
		int select = fc.showOpenDialog(this);

		//ファイルを読み込む
		if (select == JFileChooser.APPROVE_OPTION) {
			try {
			File openFile = fc.getSelectedFile();
			img = ImageIO.read(openFile);
			}catch (IOException ex) {
				System.out.println("Miss");
			}
			h = img.getHeight();
			w = img.getWidth();
		}

		//画像をJFrameに貼る
		JFrame imgFrame = new JFrame ("Image Test");
		imgFrame.setBounds(300, 300, w, h);
		mypane = new MyPanel (w, h);
		imgFrame.getContentPane().add(mypane, BorderLayout.CENTER);
		imgFrame.setVisible(true);
	}

	//画像を貼る用のツール
	public class MyPanel extends JPanel {
		public MyPanel (int width, int height) {
			setSize (width, height);
		}

		public void paintComponent (Graphics g) {
			g.drawImage(img, 0, 0, this);
		}
	}

	//画像を保存する
	public void SaveImage () {

     //名前を取り出す
		String name = writeFile();
 
     //名前を付けて異なる拡張子で保存
		try {
			FileOutputStream fo0 = new FileOutputStream (name + ".png");
			ImageIO.write(img, "png", fo0);
			FileOutputStream fo1 = new FileOutputStream (name + ".tiff");
			ImageIO.write(img, "tiff", fo1);
			FileOutputStream fo2 = new FileOutputStream (name + ".jpg");
			ImageIO.write(img, "jpg", fo2);
		} catch (IOException ex) {
			System.out.println("Miss");
		}
	}

	//出力画像の名前書き
	String writeFile () {
		FileDialog fd = new FileDialog (new Frame (), "保存", FileDialog.SAVE);
		fd.setVisible(true);
		String fullpath = fd.getDirectory() + fd.getFile();
		fd.dispose();
		return fullpath;
	}

	public void actionPerformed (ActionEvent e) {
		String cmd = e.getActionCommand();

		if (cmd.equals("open")) {
			openFile ();
		} else if (cmd.equals ("save")) {
			SaveImage();
		}
	}

	SaveWithoutExtension (String title) {
		setTitle(title);
		setBounds (10, 10, 200, 100);
		setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);

		JButton button = new JButton ("Open");
		JButton button1 = new JButton ("Save");
		button.addActionListener (this);
		button1.addActionListener (this);
		button.setActionCommand("open");
		button1.setActionCommand("save");
		button.setBounds(40, 10, 100, 30);
		button1.setBounds (40, 50, 100, 30);
		JPanel pane = new JPanel ();
		pane.setLayout(null);
		pane.add(button);
		pane.add(button1);
		getContentPane().add(pane, BorderLayout.CENTER);
	}

	public static void main(String[] args) {
		SaveWithoutExtension frame = new SaveWithoutExtension("Image Save");
		frame.setVisible (true);
	}
}

キーとなるのは、

	//画像を保存する
	public void SaveImage () {

		String name = writeFile();
		try {
			FileOutputStream fo0 = new FileOutputStream (name + ".png");
			ImageIO.write(img, "png", fo0);
			FileOutputStream fo1 = new FileOutputStream (name + ".tiff");
			ImageIO.write(img, "tiff", fo1);
			FileOutputStream fo2 = new FileOutputStream (name + ".jpg");
			ImageIO.write(img, "jpg", fo2);
		} catch (IOException ex) {
			System.out.println("Miss");
		}
	}

	//出力画像の名前書き
	String writeFile () {
		FileDialog fd = new FileDialog (new Frame (), "保存", FileDialog.SAVE);
		fd.setVisible(true);
		String fullpath = fd.getDirectory() + fd.getFile();
		fd.dispose();
		return fullpath;
	}

名前を繰り返し使うために、

 String name = writeFile();

この部分で、入力された名前を取り出し、

  FileOutputStream fo0 = new FileOutputStream (name + ".png");
  ImageIO.write(img, "png", fo0);
  FileOutputStream fo1 = new FileOutputStream (name + ".tiff");
  ImageIO.write(img, "tiff", fo1);
  FileOutputStream fo2 = new FileOutputStream (name + ".jpg");
  ImageIO.write(img, "jpg", fo2);

この部分で、同じ名前だが拡張子の異なる画像を保存できるようにした。


このコードを実行すると、
f:id:Aki-Miya:20180127174159p:plainとJFrameが立ち上がり、Openボタンを押して開く画像を選択する。(今回は最近よく使っているImageJのClownの画像を使用した)そして、Saveボタンを押すと、次のような保存ダイアログが立ち上がる。
f:id:Aki-Miya:20180127174455p:plain
名前を付けて画像を保存すると、
f:id:Aki-Miya:20180127174650p:plain このように、予定通り、名前が同じでも拡張子の異なるファイル(ここではpngtiff、jpg)が保存できた。

tiffファイルをJavaで扱えるようにするには、以前書いたJavaでtiff画像を開く - 生物屋さんのためのゼロからのプログラミングを参照。

EclipseでImageJのPlugin作成 -ROI付き画像を名前をつけて保存する (Save images with ROI) -

今回は、ROIを置いた位置が分かるように、ROI付き画像に名前をつけて保存する方法を書いた。(ROIの位置確認用)
ImagePlus上のROIをBufferedImage上に移してBufferedImageを保存するという、かなりトリッキーなことをしたが、自分の目的に適っているので良しとした。

ソースコードは下記。

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import ij.IJ;
import ij.ImagePlus;
import ij.gui.ImageCanvas;
import ij.gui.OvalRoi;
import ij.io.OpenDialog;
import ij.plugin.PlugIn;
import ij.plugin.frame.RoiManager;
import ij.process.ImageProcessor;

public class ROI_Save implements PlugIn, MouseListener, MouseMotionListener, ActionListener {

	BufferedImage bim;
	JFrame imgFrame;
	MyPanel mypane; //BufferedImageを貼り付ける用のJPanel
	ImagePlus imp;
	ImageCanvas ic;
	ImageProcessor ip;
	Graphics2D g2;
	RoiManager rm;
	int x, y, h, w;
	int counter = 1;  //ROIの個数をカウントする用
	BasicStroke bs;

	//画像を開く
	public void openFile () {
		OpenDialog od = new OpenDialog("Select");
		String directory = od.getDirectory();
		String name = od.getFileName();
		String path = directory + name;
		imp = IJ.openImage(path);
		imp.show();
		h = imp.getHeight();
		w = imp.getWidth();
        ic = imp.getCanvas();  //ImageCanvasにImageを渡す
        ic.addMouseListener(this);
        ic.addMouseMotionListener(this);

        //ROIを表示できる様にRoiManagerを立ち上げる
        rm = new RoiManager();
        rm.runCommand(imp, "Show All");
        rm.runCommand(imp, "Show All with labels");

        //ImagePlusをBufferedImageに渡す
        bim = imp.getBufferedImage();

        //BufferedImageの画像を添付する用のJFrameの作成
        imgFrame = new JFrame ("Pic Test");
		imgFrame.setBounds(300, 300, w, h);
		imgFrame.setVisible(true);
		mypane = new MyPanel(w, h);
		imgFrame.getContentPane().add(mypane, BorderLayout.CENTER);
	}

	//BufferedImageの方にROIを置く
	public void drawRoi () {
		g2.draw(new Ellipse2D.Double(x-10, y-10, 20, 20));

		//ROIに番号をつける
		g2.drawString(String.valueOf(counter), x-3, y+3);
	}

	//出力画像の名前書き
	String writeFile () {
		FileDialog fd = new FileDialog (new Frame (), "保存", FileDialog.SAVE);
		fd.setVisible(true);
		String fullpath = fd.getDirectory() + fd.getFile();
		fd.dispose();
		return fullpath;
	}

	//保存ダイアログを使用して保存
	public void saveFile () {
		try {
			FileOutputStream fo = new FileOutputStream (this.writeFile());
			ImageIO.write(bim, "png", fo);
		} catch (IOException ex) {
			System.out.println("Miss");
		}
	}

	public class MyPanel extends JPanel {
		public MyPanel (int width, int height) {
			setSize (width, height);
		}

		public void paintComponent (Graphics g) {
			g.drawImage(bim, 0, 0, this);
			g2 = (Graphics2D)g;
			g2 = (Graphics2D) mypane.getGraphics();
			g2 = bim.createGraphics();
			bs = new BasicStroke(1.0f); //線の太さを決める
			g2.setPaint(Color.red);
			g2.setStroke(bs);
		}
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		String cmd = e.getActionCommand();
		if (cmd.equals("Open")) {
			openFile();
		} else if (cmd.equals("Save")) {
			saveFile();
		}
	}

	public void run (String arg) {
		JFrame frame = new JFrame ("Controller");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setBounds(10, 10, 200, 100);
		frame.setVisible(true);

		JButton openButton = new JButton ("Open");
		JButton saveButton = new JButton ("Save");
		openButton.addActionListener(this);
		saveButton.addActionListener(this);
		openButton.setActionCommand("Open");
		saveButton.setActionCommand("Save");
		openButton.setBounds(40, 10, 90, 30);
		saveButton.setBounds(40, 50, 90, 30);

		JPanel pane = new JPanel();
		pane.setLayout(null);
		pane.add(openButton);
		pane.add(saveButton);
		frame.getContentPane().add(pane, BorderLayout.CENTER);
	}

	@Override
	public void mouseClicked(MouseEvent e) {

		//ImagePlus上でマウスがクリックされた場所の座標の取得
		x = ic.offScreenX(e.getX());
		y = ic.offScreenY(e.getY());

		//クリックされた場所を中心とした円を描き、RoiManagerに加える
		imp.setRoi(new OvalRoi(x-10, y-10, 20, 20));
		rm.addRoi(imp.getRoi());

		//BufferedImageにROIをつける
		drawRoi ();
		counter++;
	}

	@Override
	public void mousePressed(MouseEvent e) {
	}

	@Override
	public void mouseReleased(MouseEvent e) {
	}

	@Override
	public void mouseEntered(MouseEvent e) {
	}

	@Override
	public void mouseExited(MouseEvent e) {
	}

	@Override
	public void mouseDragged(MouseEvent e) {
	}

	@Override
	public void mouseMoved(MouseEvent e) {
	}

}

これを実行すると、
f:id:Aki-Miya:20180116083113p:plainのウインドウが立ち上がり、
"Open"ボタンを押すと、ダイアログが現れ、画像ファイルを選択できる。ここでは、またImageJにある"Clown"の画像を選択した。
f:id:Aki-Miya:20180116083341p:plain
画像を選択すると、上のように同じ画像が2つ現れる。1つはImagePlus、もう1つがBufferedImage(Pic Testのウインドウのもの)。また、ROIの位置を画像に表示させたままにするために、RoiManagerも立ち上がるようにした。

ImagePlus上に、下のように適当にROIを置き、(注:この段階ではBufferedImageの方には何故かROIは付かない。原因不明)
f:id:Aki-Miya:20180116083807p:plain

"Controller"ウインドウの"Save"ボタンを押すと、下のように保存用のダイアログが立ち上がり、BufferedImageの画像を保存できる (注:拡張子もつけないとダメ)。
f:id:Aki-Miya:20180116083653p:plain

保存した画像が下。
f:id:Aki-Miya:20180116084011p:plain
これで、とりあえずROI付きの画像を保存でき、解析したDataのどこにROIを置いたのかを後で確認できるようになった。


いくつかコードを見ていく。
本当はROIを置いた状態のImagePlusをそのまま保存したかったのだが、色々調べても分からなかったため、以前の記事ウインドウサイズを変えても、描画が消えない方法 - 生物屋さんのためのゼロからのプログラミングでGraphics2Dで描画した画像を保存する方法を書いたので、今回はそれを利用することにした。

  //ImagePlusをBufferedImageに渡す
        bim = imp.getBufferedImage();

そのため、上の部分でImagePlusをBufferedImageに渡して、BufferedImage上にROIを転写することにした。
下記の部分で、BufferedImage上にGraphics2Dを使ってROIを描けるようにした。

public class MyPanel extends JPanel {
		public MyPanel (int width, int height) {
			setSize (width, height);
		}

		public void paintComponent (Graphics g) {
			g.drawImage(bim, 0, 0, this);
			g2 = (Graphics2D)g;
			g2 = (Graphics2D) mypane.getGraphics();
			g2 = bim.createGraphics();
			bs = new BasicStroke(1.0f); //線の太さを決める
			g2.setPaint(Color.red);
			g2.setStroke(bs);
		}
	}

そして、ImageCanvas上のマウスをクリックした場所と同じBufferedImage上の場所にROIを置くのが下記。(ついでに、ImageCanvas上と同様にラベルをつけるようにもした)

//BufferedImageの方にROIを
	public void drawRoi () {
		g2.draw(new Ellipse2D.Double(x-10, y-10, 20, 20));

		//ROIに番号をつける
		g2.drawString(String.valueOf(counter), x-3, y+3);
	}

この

   g2.draw(new Ellipse2D.Double(x-10, y-10, 20, 20));

の使い方は、ImagePlus上にROIを置く下記の使い方

   imp.setRoi(new OvalRoi(x-10, y-10, 20, 20));

と同じである。

EclipseでImageJのPlugin作成 -マウスでクリックした場所にOval ROIを描き、Excelファイルにデータを書き出す。-

ここでは、前回の記事
EclipseでImageJのPlugin作成 -マウスでクリックした場所にOval ROIを描く- - 生物屋さんのためのゼロからのプログラミング
を発展させて、stack画像にOval ROIを描いて、その測定値(ここではMeanのみ)をエクセルに書き出すプラグインにした。

ソースコードは下記。

import java.awt.BorderLayout;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.FileOutputStream;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import ij.IJ;
import ij.ImagePlus;
import ij.gui.ImageCanvas;
import ij.gui.OvalRoi;
import ij.io.OpenDialog;
import ij.measure.ResultsTable;
import ij.plugin.PlugIn;
import ij.plugin.frame.RoiManager;

public class ROI_Maker implements PlugIn, MouseListener, MouseMotionListener, ActionListener{

	ImagePlus imp;
	ImageCanvas ic;
	RoiManager rm;

	int rRoi;  //描くROIの大きさ
	int counter;  //ROIの個数をカウント
	int number; //Stack画像の枚数

	float [][] data = null;

	JTextField rVal; //描くROIの大きさを入力する用

	//ファイルをダイアログを使って開く
	public void openFile () {
		OpenDialog od = new OpenDialog("Select");
		String directory = od.getDirectory();
		String name = od.getFileName();
		String path = directory + name;
		imp = IJ.openImage(path);
		imp.show();
        ic = imp.getCanvas();  //ImageCanvasにImageを渡す
        number = imp.getNSlices(); //Stack画像の枚数の獲得
	}


	//Roiを置けるようにする。
	public void activeROI () {
		ic.addMouseListener(this);
		ic.addMouseMotionListener(this);

		//Roi Managerを立ち上げる
		rm = new RoiManager();
		rm.runCommand(imp, "Show All");
		rm.runCommand(imp, "Show All with labels");

		rRoi = Integer.parseInt(rVal.getText());
		counter = 0;
	}

	//Measure
	public void measureRoi () {

		//Dataを入れる入れ物を作る。
		data = new float [counter][number];

		//Dataを取り出す
		for (int i = 0; i < counter; i++) {
			rm.select(i);                      //測定するROIを選択
			ResultsTable rt = rm.multiMeasure(imp);

			for (int j = 0; j < number; j++) {
				data[i][j] = rt.getValue(1, j);
			}
		}

		//Dataをエクセルに書き出す。
		SaveData(counter, number);

	}


	   //出力ファイルの名前書き (ファイルパスの作成)
    String writefile() {
        FileDialog fd = new FileDialog(new Frame(), "保存 (末尾に 「.xlsx」を付けて下さい)", FileDialog.SAVE);
        fd.setVisible(true);
        String fullpath = fd.getDirectory() + fd.getFile();
        fd.dispose();
        return fullpath;
    }


    //Dataのエクセルへの保存
    public void SaveData (int ColSize, int RowSize) {
        try {
            FileOutputStream fo = new FileOutputStream(this.writefile());  
            XSSFWorkbook bookR = new XSSFWorkbook();
            XSSFSheet sheetR = bookR.createSheet("Data");
            XSSFRow rowR = sheetR.createRow((short)0);
            XSSFCell cellR;

            //エクセル上でのデータ出力用の行とセルの作成
            for (int i = 0; i < RowSize; i++) {
                rowR = sheetR.createRow((short)i);
                for (int j = 0; j < ColSize; j++) {
                    rowR.createCell((short)j);
                }
            }

            //数値をエクセルへの書き込み
            for (int i = 0; i < ColSize; i++) {
                for (int j = 0; j < RowSize; j++) {
                    rowR = sheetR.getRow(j);
                    cellR = rowR.getCell(i);
                    cellR.setCellValue(data[i][j]);
                }
            }
            bookR.write(fo);
            fo.close();

        } catch (Exception e) {
            System.out.println("保存に失敗しました");
        }
    }


	//コントローラーの作成
	public void run (String arg) {
		JFrame frame = new JFrame ("Controller");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setBounds(10, 10, 200, 100);
		frame.setVisible(true);

		JButton openButton = new JButton ("Open");
		JButton roiButton = new JButton ("ROI");
		JButton measureButton = new JButton("Measure");
		JLabel rLabel = new JLabel ("Roi size = ");
		rVal = new JTextField("30");
		openButton.addActionListener(this);
		roiButton.addActionListener(this);
		measureButton.addActionListener(this);
		openButton.setActionCommand("Open");
		roiButton.setActionCommand("Roi");
		measureButton.setActionCommand("Measure");
		openButton.setBounds(40, 10, 90, 30);
		roiButton.setBounds(40, 50, 90, 30);
		rLabel.setBounds(40, 90, 90, 30);
		rVal.setBounds(105, 90, 40, 30);
		measureButton.setBounds(40, 130, 90, 30);

		JPanel pane = new JPanel();
		pane.setLayout(null);
		pane.add(openButton);
		pane.add(roiButton);
		pane.add(measureButton);
		pane.add(rLabel);
		pane.add(rVal);
		frame.getContentPane().add(pane, BorderLayout.CENTER);
	}

	//ボタンが押された時の動作
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO 自動生成されたメソッド・スタブ
		String cmd = e.getActionCommand();
		if(cmd.equals("Open")) {
			openFile();
		} else if (cmd.equals("Roi")) {
			activeROI();
		} else if (cmd.equals("Measure")) {
			measureRoi();
		}
	}

    //クリックした場所にOvalRoiを描く
	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO 自動生成されたメソッド・スタブ
		int x = ic.offScreenX(e.getX());
		int y = ic.offScreenY(e.getY());
		imp.setRoi(new OvalRoi(x-rRoi/2, y-rRoi/2, rRoi, rRoi));
		rm.addRoi(imp.getRoi());
		rm.select(counter);

		//ROIの名称変更
		rm.runCommand("Rename", String.valueOf(counter+1));
		counter++;
	}

	//クリックした場所にROIを描く
	@Override
	public void mousePressed(MouseEvent e) {
		// TODO 自動生成されたメソッド・スタブ
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO 自動生成されたメソッド・スタブ
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO 自動生成されたメソッド・スタブ
	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO 自動生成されたメソッド・スタブ
	}



	@Override
	public void mouseDragged(MouseEvent e) {
		// TODO 自動生成されたメソッド・スタブ
	}

	@Override
	public void mouseMoved(MouseEvent e) {
		// TODO 自動生成されたメソッド・スタブ
	}
}

このプラグインを実行してみると、(実行方法は前回の記事を参照:
EclipseでImageJのPlugin作成 -マウスでクリックした場所にOval ROIを描く- - 生物屋さんのためのゼロからのプログラミング
f:id:Aki-Miya:20180110153021p:plain
上のようなウインドウが立ち上がる。前回の記事同様に、「Open」ボタンで目的の画像を開き、「ROI」ボタンで画像上にOval ROIを描ける。実際にROIを置いたのが下。
f:id:Aki-Miya:20180110153343p:plain
ここで使用したのは、三浦耕太先生著のImageJではじめる生物画像解析 | 学研メディカル秀潤社の第5章−1 (p197)のサポートサイト5章1節 公開プラグインを用いた 画像解析: LPXプラグイン集 - ImageJではじめる生物画像解析にあるデモ用の100スライスからなるstack画像。


次に、「Measure」ボタンを押すと、次のようなダイアログが立ち上がり、取得したDataをExcelファイルに名前を付けて保存できる。
f:id:Aki-Miya:20180110153502p:plain

Excelファイルへの出力結果が下記。
f:id:Aki-Miya:20180110153606p:plain



エクセルに書き出すためには、

poi-3.17.jar
poi.examples-3.17.jar
poi.excelant-3.17.jar
poi-ooxml-3.17.jar
poi-ooxml-schemas-3.17.jar
poi-scratchpad-3.17.jar
xmlbeans-2.6.0.jar

これらのjarファイルを
Apache POI - Download Release ArtifactsのBinary distributionの「poi-bin-3.17-20170915.zip (28.65 MB, signature (.asc))」からダウンロードし、ビルドパスを行う必要がある。
ビルドパスの作成は、下記のように行う。

プラグインを作成しているJavaプロジェクトを右クリック
   -> ビルドパス -> 外部アーカイブの追加  -> Jarファイルを選択

また、エラーが出てうまくExcelファイルを作れない場合は、

commons-collections4-4.1.jar

このjarファイルを入れればうまくいくかも。これは下記からダウンロードできる。
Collections – Download Apache Commons Collections

これらのjarファイルはプラグインを作成するJavaプロジェクトだけでなく、ImageJのソースコードを導入した"IJ"プロジェクトにもビルドパスする必要がある
(注:"IJ"プロジェクトについてはEclipseでImageJのPlugin作成 -下準備編 ver.2- - 生物屋さんのためのゼロからのプログラミングを参照)



今回は、stack画像を使っているため、Dataの取得には下記のように、

      //Dataを取り出す
             for (int i = 0; i < counter; i++) {
		rm.select(i);
		ResultsTable rt = rm.multiMeasure(imp);

		for (int j = 0; j < number; j++) {
			data[i][j] = rt.getValue(1, j);
		}
	     }

Multi Measureを使った。

Analyze -> Tools ->  ROI Manager... -> More 

このMulti Measureは、上記のようにROI Managerの”More”の中に入っている機能である。
取得したDataの中から、今回は”Mean”のみを取り出したかったため、

		data[i][j] = rt.getValue(1, j);

この「rt.getValue(1, j)」で「1」にしている。


取得したDataは、以前の記事Apache POIを使って、エクセルにデータを書き出す。 - 生物屋さんのためのゼロからのプログラミングで紹介した方法でエクセルファイルに書き出せるようにした。


これで、とりあえず、Stack画像からのData取得がかなり楽になった。

EclipseでImageJのPlugin作成 -マウスでクリックした場所にOval ROIを描く-

ここでは、ダイアログを使って画像を開き、画像のマウスをクリックした場所にOval ROIを描くプラグイン: ROI_Maker を作った。

ソースコードは下記。

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

import ij.IJ;
import ij.ImagePlus;
import ij.gui.ImageCanvas;
import ij.gui.OvalRoi;
import ij.io.OpenDialog;
import ij.plugin.PlugIn;
import ij.plugin.frame.RoiManager;

public class ROI_Maker implements PlugIn, MouseListener, MouseMotionListener, ActionListener{

	ImagePlus imp;
	ImageCanvas ic;
	RoiManager rm;

	int rRoi;  //描くROIの大きさ
	int counter;  //ROIの個数をカウント
	JTextField rVal; //描くROIの大きさを入力する用

	//ファイルをダイアログを使って開く
	public void openFile () {
		OpenDialog od = new OpenDialog("Select");
		String directory = od.getDirectory();
		String name = od.getFileName();
		String path = directory + name;
		imp = IJ.openImage(path);
		imp.show();
        ic = imp.getCanvas();  //ImageCanvasにImageを渡す
	}

	//Roiを置けるようにする。
	public void activeROI () {
		ic.addMouseListener(this);
		ic.addMouseMotionListener(this);

		//Roi Managerを立ち上げる
		rm = new RoiManager();
		rm.runCommand(imp, "Show All");
		rm.runCommand(imp, "Show All with labels");

		rRoi = Integer.parseInt(rVal.getText());
		counter = 0;
	}

	//コントローラーの作成
	public void run (String arg) {
		JFrame frame = new JFrame ("Controller");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setBounds(10, 10, 200, 100);
		frame.setVisible(true);

		JButton openButton = new JButton ("Open");
		JButton roiButton = new JButton ("ROI");
		JLabel rLabel = new JLabel ("Roi size = ");
		rVal = new JTextField("30");
		openButton.addActionListener(this);
		roiButton.addActionListener(this);
		openButton.setActionCommand("Open");
		roiButton.setActionCommand("Roi");
		openButton.setBounds(40, 10, 90, 30);
		roiButton.setBounds(40, 50, 90, 30);
		rLabel.setBounds(40, 90, 90, 30);
		rVal.setBounds(105, 90, 40, 30);

		JPanel pane = new JPanel();
		pane.setLayout(null);
		pane.add(openButton);
		pane.add(roiButton);
		pane.add(rLabel);
		pane.add(rVal);
		frame.getContentPane().add(pane, BorderLayout.CENTER);
	}

	//ボタンが押された時の動作
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO 自動生成されたメソッド・スタブ
		String cmd = e.getActionCommand();
		if(cmd.equals("Open")) {
			openFile();
		} else if (cmd.equals("Roi")) {
			activeROI();
		}
	}

    //クリックした場所にOvalRoiを描く
	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO 自動生成されたメソッド・スタブ
		int x = ic.offScreenX(e.getX());
		int y = ic.offScreenY(e.getY());
		imp.setRoi(new OvalRoi(x-rRoi/2, y-rRoi/2, rRoi, rRoi));
		rm.addRoi(imp.getRoi());

		//ROIの名称変更
		rm.select(counter);
		rm.runCommand("Rename", String.valueOf(counter+1));
		counter++;
	}

	//クリックした場所にROIを描く
	@Override
	public void mousePressed(MouseEvent e) {
		// TODO 自動生成されたメソッド・スタブ
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO 自動生成されたメソッド・スタブ
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO 自動生成されたメソッド・スタブ
	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO 自動生成されたメソッド・スタブ
	}



	@Override
	public void mouseDragged(MouseEvent e) {
		// TODO 自動生成されたメソッド・スタブ
	}

	@Override
	public void mouseMoved(MouseEvent e) {
		// TODO 自動生成されたメソッド・スタブ
	}
}

これを実行すると、
f:id:Aki-Miya:20180105105052p:plain
このように、Pluginに「ROI Maker」が追加される。

この「ROI Maker」をクリックすると、
f:id:Aki-Miya:20180105105603p:plain
このようなGUIが立ち上がる。
Openボタンをクリックすると、ダイアログが立ち上がり、画像を選択できる。
そして、ROIボタンをクリックすると、「Roi Manager」が立ち上がり、ROIを描けるようになる。

描くROIの大きさは、「ROI size = 」の横のJTextFieldに入力できる。(ここでは初期値を30とした)
(注:このソースコードではROIボタンを押すと、JTextFieldの値が読み込まれるので、ROIの大きさを変える場合はROIボタンを押す前に書き換える。)

そして、実際に画像にROIを描いたのが下。(ImageはFijiに入っている”Clown (14K)”を使用)
f:id:Aki-Miya:20180105111348p:plain
f:id:Aki-Miya:20180105111406p:plain
予定通り、Roi ManagerにROIがaddされている。


ImageJのPluginのソースコードを書くには、Fijiの「Records...」を使用して、コードの使い方を見るのが楽。
Fijiの
[Plugins -> Macros -> Records...] で 「Recorder」を立ち上げる。
「Record:」の横のボックスから「Java」を選択。
あとは実際にやりたい作業を行い、そのlogを参考にしてコードを描く。(丸々コピーしてもダメ)


個々のコードを見ていく。

public class ROI_Maker implements PlugIn, MouseListener, MouseMotionListener, ActionListener{

マウスの動きを見るように「MouseListener」「MouseMotionListener」を、ボタンを押した時に仕事をするように「ActionListener」を実装した。
ここでは「PlugIn」を実装しているが、「PlugInFilter」や「PlugInFrame」との使い分け方を僕はまだ理解していない。

//ファイルをダイアログを使って開く
	public void openFile () {
		OpenDialog od = new OpenDialog("Select");
		String directory = od.getDirectory();
		String name = od.getFileName();
		String path = directory + name;
		imp = IJ.openImage(path);
		imp.show();
        ic = imp.getCanvas();  //ImageCanvasにImageを渡す
	}

もっと楽な方法がありそうだが、とりあえずstack画像もこのコードで開けた。

	//Roiを置けるようにする。
	public void activeROI () {
		ic.addMouseListener(this);
		ic.addMouseMotionListener(this);

		//Roi Managerを立ち上げる
		rm = new RoiManager();
		rm.runCommand(imp, "Show All");
		rm.runCommand(imp, "Show All with labels");

		rRoi = Integer.parseInt(rVal.getText());
		counter = 0;
	}

ここで、Roi Managerを立ち上げている。置いたROIを表示したままにし、さらにラベルを付けるために、

	rm.runCommand(imp, "Show All");
	rm.runCommand(imp, "Show All with labels");

とした。

   rRoi = Integer.parseInt(rVal.getText());

この部分で、描くROIの大きさを取得している。

    counter = 0;

これは、ただ単にROIに番号を振る用。

  //クリックした場所にOvalRoiを描く
	public void mouseClicked(MouseEvent e) {
		// TODO 自動生成されたメソッド・スタブ
		int x = ic.offScreenX(e.getX());
		int y = ic.offScreenY(e.getY());
		imp.setRoi(new OvalRoi(x-rRoi/2, y-rRoi/2, rRoi, rRoi));
		rm.addRoi(imp.getRoi());

		//ROIの名称変更
		rm.select(counter);
		rm.runCommand("Rename", String.valueOf(counter+1));
		counter++;
	}

マウスの位置座標を得るには、

	int x = e.getX();
	int y = e.getY();

でも得られる。しかし、画像が拡大・縮小した場合、欲しい画像上の座標ではなく、拡大・縮小された画像での座標を取得することになる。そのため、ここでは下記の

	int x = ic.offScreenX(e.getX());
	int y = ic.offScreenY(e.getY());

を使用した。

imp.setRoi(new OvalRoi(”x座標”, ”y座標”, ”int a(横幅)”, ”int b(縦幅)”));

は、(x, y)座標から”int a”の横幅、”int b”の縦幅を持つ正方形 (長方形) に内接する円 (楕円) を描くメソッド。
そのため、下記のようにして

   imp.setRoi(new OvalRoi(x-rRoi/2, y-rRoi/2, rRoi, rRoi));

クリックした場所に、半径 rRoi/2のOval Roiを描けるようにした。

	rm.addRoi(imp.getRoi());

ここで、Roi Managerに上記で描いたROIを登録している。

      //ROIの名称変更
	rm.select(counter); 
	rm.runCommand("Rename", String.valueOf(counter+1));
	counter++;

ここで、名称を変更するROIをRoi Managerから選び、

	rm.runCommand("Rename", String.valueOf(counter+1));

で、intである”counter”を”String”に変換し、ROIに通し番号を付けられるようにした。


このPluginを走らせるためには、前の記事
EclipseでImageJのPlugin作成 -下準備編 ver.2- - 生物屋さんのためのゼロからのプログラミングで「TESTPlugin_」を作成した時と同様に、「build.xml」を作成する。基本的には、「TESTPlugin_」を新しいPlugin名に変更するだけでいい。一度デバッグしてしまえば、2回目以降の実行は「実行構成...」から出来る。

但し、「実行構成...」をクリックして現れる下記のウインドウで、
f:id:Aki-Miya:20180105122153p:plain
メインタブのプロジェクト名が「IJ」で、メイン・クラスが「ij.ImageJ」になっているかの確認と、ソースタブ内で実行するプロジェクトが選ばれているかの確認を忘れずに。

EclipseでImageJのPlugin作成 -下準備編 ver.2-

前回書いた「EclipseでImageJのPlugin作成 -下準備編-」では、うまくいかない部分があったので、
他の方法でアプローチすることにした。

今回用いたのは、下記の3つのサイトの合わせ技。
The ImageJ Eclipse Howto [ImageJ Documentation Wiki]
Re - ImageJで学ぶ!: 第41回 ImageJのソースコード分解(Eclipseを用いたImageJソースコードのコンパイル)で学ぶ!
Re - ImageJで学ぶ!: 第42回 ImageJのソースコード分解(Eclipseを用いたImageJのプラグイン実行方法)で学ぶ!


下準備として、下記のImageJのサイトからImageJの最新のソースコードをダウンロードする。
ImageJ
zipファイルを展開すると、sourceフォルダーが現れるので、適当なディレクトリに保存。


次に、Eclipseを立ち上げ、Java プロジェクトを作成する。
f:id:Aki-Miya:20171230135832p:plain

Java プロジェクトを選び、”次へ” をクリック。
プロジェクト名: "IJ" (適当につける)を入力、そして、下の様にチェックを入れ、”次へ” をクリック。
f:id:Aki-Miya:20171230140200p:plain

”ソース” タブを選んで、下の ”詳細” 枠内の ”追加ソースのリンク” をクリックし、
上記で保存しておいたImageJの ”source” フォルダを指定し、”次へ” をクリック。
f:id:Aki-Miya:20171230140341p:plain

f:id:Aki-Miya:20171230140351p:plain

 
・組み込みパターンの右の ”追加” をクリックして、
 ” IJ_Props.txt ”
 ” ij/ ”
 を記入する。

・除外パターンの右の ”追加” をクリックして、
 ” images/ ”
 ” macros/ ”
 ” plugins/ ”
 を記入し、”完了” をクリック 
f:id:Aki-Miya:20171230140522p:plain

f:id:Aki-Miya:20171230140538p:plain


次に、Eclipseを立ち上げて、Java プロジェクトを新規作成。
f:id:Aki-Miya:20171230140748p:plain
 
Java プロジェクトを選び、”次へ” をクリック
プロジェクト名: "TESTPlugin_" (適当につける。但し、”_”を何処かに必ず入れる)を入力、下の様にチェックを入れ、”次へ” をクリック。 
f:id:Aki-Miya:20171230140832p:plain

 
”プロジェクト” タブを選んで、 右の ”追加” をクリックし、
上記で作成した ”IJ” プロジェクトを追加し、”完了” をクリック。 
f:id:Aki-Miya:20171230141015p:plain
これで、Pluginを作る環境が整った。


では、実際にPluginを作成する。
上記で作成した、TESTPlugin_プロジェクトに下記の新規クラス (TESTPlugin_java) を作成する。
f:id:Aki-Miya:20171230141140p:plain

f:id:Aki-Miya:20171230142023p:plain

import ij.IJ;
import ij.plugin.PlugIn;

public class TESTPlugin_ implements PlugIn{ 
	public void run (String arg) {
		IJ.error("Hello World");
	}
}

これはただ”Hello World”と表記されたウインドウを出すだけのplugin。

次に、TESTPlugin_プロジェクト内にビルド.xmlというファイルを下記のように作る。
f:id:Aki-Miya:20171230142045p:plain

f:id:Aki-Miya:20171230142125p:plain 
作成したファイルに下記をコピペ。(今回は特に何も変えなくてもいい)

<project name="TESTPlugin_" default="" basedir=".">
    <description>
        TESTPlugin_ build file
    </description>
  <property name="src" location="src" />
  <property name="build" location="bin" />
  <property name="dist"  location="dist" />
 
	 <property name="pluginsDir"  location="$basedir/../../IJ/plugins/" />
 
  <property name="user.name" value="Aki" />
<target name="main" depends="compress" description="Main target">
	<echo>
		Building the .jar file.
	</echo>
</target>
 <target name="compress" depends="" description="generate the distribution">
 	<jar jarfile="TESTPlugin_.jar">
 		<fileset dir="." includes="plugins.config" />
		<fileset dir="${build}" includes="**/*.*" />
 		<manifest>
 		 	 	      <attribute name="Built-By" value="${user.name}"/>
 		</manifest>
 	</jar>
    <copy file="TESTPlugin_.jar" toDir="${pluginsDir}" />
  </target>
</project>


次に、 
”パッケージエクスプローラー” 内のTESTPlugin_プロジェクトを右クリックし、”プロパティ” をクリックすると下のようなウインドウが開くので、”ビルダー” を選択。右の”新規” をクリック。
f:id:Aki-Miya:20171230142234p:plain

”Ant_builder” を選択。
f:id:Aki-Miya:20171230142247p:plain

”メイン” タブで、”Browse Workspace” をクリックし、
”TESTPlugin_プロジェクト” から先ほど作成した”build.xml” を選択。
f:id:Aki-Miya:20171230142313p:plain

”ターゲット” タブで、”「クリーン」の後:” と ”自動ビルド” の ”ターゲットの設定” をクリックし、
f:id:Aki-Miya:20171230142342p:plain

そこに現れる ”main” と ”compress” を選択し、適用、OKを押す。
f:id:Aki-Miya:20171230142401p:plain

これにより、”「クリーン」の後:” と ”自動ビルド” の ウインドウに ”main” と ”compress” が現れる。
f:id:Aki-Miya:20171230142419p:plain


Eclipseの ”実行” を選択し、”デバッグの構成” をクリック。
f:id:Aki-Miya:20171230142543p:plain

新規 ”Java アプリケーション” を作成。
f:id:Aki-Miya:20171230142601p:plain

f:id:Aki-Miya:20171230142844p:plain

プロジェクト名に ”IJ” を選択し、メインクラスに ”ImageJ” を選択する。
f:id:Aki-Miya:20171230142933p:plain

”ソース” タブを選択し、”ソース・ルックアップ・パス” の右の ”追加” をクリックし、”Java プロジェクト” を選ぶ。
f:id:Aki-Miya:20171230143028p:plain

TESTPlugin_プロジェクトを選択し、”デバッグ” をクリック。
f:id:Aki-Miya:20171230143114p:plain
 

すると、
f:id:Aki-Miya:20171229140443j:plain
上のように、ImageJのPlugin内に作成した ”TESTPlugin_” が表示される。

これをクリックすると、
f:id:Aki-Miya:20171229140556j:plain
のように、”Hello Word” が表示できた。

これで、EclipseからImageJのPluginが作成できることを確かめられた。

EclipseでImageJのPlugin作成 -下準備編-

ImageJを活用した解析用ツールを開発することにした。
EclipseでImageJのいじれるようにするまでに少し苦労したので、備忘録を残す。(今回はMacを使用)
参考にしたのは、三浦耕太先生著の「ImageJではじめる生物画像解析」
ImageJではじめる生物画像解析 | 学研メディカル秀潤社の第5章−2 (p209-p212)

(注:これでうまくいかない場合は、この記事の次の記事
EclipseでImageJのPlugin作成 -下準備編 ver.2- - 生物屋さんのためのゼロからのプログラミング
を参照)


手順(1) Eclipseのダウンロード
EclipsePleiadeshttp://mergedoc.osdn.jp/からFull versionをダウンロードすれば簡単。しかもEclipseが日本語表記になる。

Macの場合は、ダウンロード終了後にフォルダーが現れるので、そのフォルダー内のEclipseのアイコンを同じくフォルダー内にあるApplicationのショートカットフォルダーにドラッグして入れば完了。


手順(2) ImageJのソースコードのコピー
GitHubのサイトhttps://github.com/dscho/minimal-ij1-pluginの”clone or download”からzipファイルをダウンロードし、
PCのDocumentsにminimal-ij1-pluginを移す。


手順(3) Eclipseにインポート
Eclipseを開いて、
”ファイル”→”インポート”→”Maven”→”既存Maveプロジェクト”
参照で上記で移したminimal-ij1-pluginを選択、現れるpom.xmlをチェックする。


Eclipseのパッケージ・エクスプローラーにインポートされたプロジェクトが現れるので、それを右クリック。
リファクタリング”→”Mavenアーティファクトの名前変更”

グループ ID: 任意の名前
アーティファクトID:作製するpluginの名称(どこかに”_”を必ず入れる)
バージョン: 作製中のものはSNAPSHOTと入れるらしい。
その下の『ワークスペースEclipseプロジェクトの名前変更』にチェックを入れる。

これで、EclipseからImageJを動かせるはず。


うまくいっていれば、
上記で名前を変えたプロジェクト”→”src/main/java”→”デフォルト・パッケージ”にある”Process_Pixels.java”を”Javaアプリケーション”で実行してみると、ImageJが立ち上がって、”Clown”の画像が開くはず。(その前に”Process pixels”という入力画面が現れるが)