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

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

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取得がかなり楽になった。