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) { } }
これを実行すると、
のウインドウが立ち上がり、
"Open"ボタンを押すと、ダイアログが現れ、画像ファイルを選択できる。ここでは、またImageJにある"Clown"の画像を選択した。
画像を選択すると、上のように同じ画像が2つ現れる。1つはImagePlus、もう1つがBufferedImage(Pic Testのウインドウのもの)。また、ROIの位置を画像に表示させたままにするために、RoiManagerも立ち上がるようにした。
ImagePlus上に、下のように適当にROIを置き、(注:この段階ではBufferedImageの方には何故かROIは付かない。原因不明)
"Controller"ウインドウの"Save"ボタンを押すと、下のように保存用のダイアログが立ち上がり、BufferedImageの画像を保存できる (注:拡張子もつけないとダメ)。
保存した画像が下。
これで、とりあえず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));
と同じである。