Javaで画像上にdrawOvalを用いてROI (Circle)を書き、切り出す。
今回は、前回描いた円形ROIの内部を切り取るコードを書いた。
(かなり強引なやり方であるが、ROI内の輝度値を取り出したかったため、良しとした。)
まずは、ソースコードを書きに記す。
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.awt.image.DataBuffer; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.event.MouseInputAdapter; public class CircleCut extends JFrame implements ActionListener { BufferedImage img; BufferedImage cutImg; BufferedImage cirImg; DataBuffer buf; DataBuffer cutBuf; DataBuffer cirBuf; MyPanel1 mypane1; MyPanel2 mypane2; int x0; //マウスをクリックした点のx座標 int xEnd; //マウスを離した点のx座標 int y0; //マウスをクリックした点のy座標 int yEnd; //マウスを離した点のy座標 int h; int w; int cih; int ciw; double r; double x; double y; //画像を開く public void OpenImage () { try { File openFile = new File("開きたい画像"); img = ImageIO.read(openFile); h = img.getHeight(); w = img.getWidth(); buf = img.getRaster().getDataBuffer(); } catch (IOException ex) { System.out.println("miss"); } //画像をフレームに貼る JFrame imgFrame = new JFrame ("Open Image"); imgFrame.setBounds (300, 100, w, h); imgFrame.setVisible(true); mypane1 = new MyPanel1 (w, h); imgFrame.getContentPane().add(mypane1, BorderLayout.CENTER); mypane1.addMouseListener(new MouseCheck2()); mypane1.addMouseMotionListener(new MouseCheck2()); } //円形ROI用のマウスの動きをモニター class MouseCheck2 extends MouseInputAdapter { public void mousePressed (MouseEvent en) { x0 = en.getX(); y0 =en.getY(); } public void mouseReleased(MouseEvent en) { Graphics gn = mypane1.getGraphics(); xEnd = en.getX(); yEnd = en.getY(); r = 0.5*Math.sqrt((xEnd - x0)*(xEnd - x0) + (yEnd - y0) * (yEnd - y0)); x = (x0 + xEnd)/2; y = (y0 + yEnd)/2; gn.setColor(Color.RED); gn.drawOval((int)(x - r), (int)(y-r), (int)(2*r), (int)(2*r)); } } //ROIのCut public void roiCut () { cutImg = new BufferedImage(xEnd - x0, yEnd - y0, img.getType()); cutImg = img.getSubimage((int)(x - r), (int)(y-r),(int)(2*r), (int)(2*r)); cutBuf = cutImg.getRaster().getDataBuffer(); try { String dstFilePath = "データの一時保存先"; File dstFile = new File(dstFilePath); ImageIO.write(cutImg, "png", dstFile); } catch (IOException ex) { System.out.println("Miss"); } } //円の外側のイメージの削除 public void modiImage () { try { File cirFile = new File("上記データの一時保存先"); cirImg = ImageIO.read(cirFile); cih = cirImg.getHeight(); ciw = cirImg.getWidth(); cirBuf = cirImg.getRaster().getDataBuffer(); } catch (IOException exc) { System.out.println("miss"); } for (int i = 0; i < cih*ciw; i++) { if (Math.sqrt((i%ciw - ciw/2)*(i%ciw - ciw/2) + (i/ciw - cih/2)*(i/ciw - cih/2)) > r) { cirBuf.setElem(i, 0); } } try { String dstFilePath = "作成した画像の保存先"; File dstFile = new File(dstFilePath); ImageIO.write(cirImg, "png", dstFile); } catch (IOException ex) { System.out.println("Miss"); } JFrame cutFrame = new JFrame ("CutImage"); cutFrame.setSize((int)(2*r), (int)(2*r)); cutFrame.setLocationRelativeTo(null); cutFrame.setVisible(true); mypane2 = new MyPanel2 ((int)(2*r), (int)(2*r)); cutFrame.getContentPane().add(mypane2, BorderLayout.CENTER); } //画像を張り付ける用のツール public class MyPanel1 extends JPanel { public MyPanel1 (int width, int height) { setSize(width, height); } public void paintComponent (Graphics g) { g.drawImage(img, 0, 0, this); } } //ROI画像を張り付ける用のツール public class MyPanel2 extends JPanel { public MyPanel2 (int width, int height) { setSize(width, height); } public void paintComponent (Graphics g) { g.drawImage(cirImg, 0, 0, this); } } public void actionPerformed (ActionEvent e) { String cmd = e.getActionCommand(); if (cmd.equals("open")) { OpenImage(); } else if (cmd.equals("roi")) { roiCut(); modiImage(); } } CircleCut() { JButton button = new JButton ("Open"); JButton roiB = new JButton ("ROI"); button.addActionListener (this); roiB.addActionListener(this); button.setActionCommand("open"); roiB.setActionCommand("roi"); button.setBounds(36, 10, 90, 30); roiB.setBounds(36, 50, 90, 30); JPanel pane = new JPanel(); pane.setLayout(null); pane.add(button); pane.add(roiB); getContentPane().add(pane, BorderLayout.CENTER); } public static void main(String[] args) { CircleCut frame = new CircleCut(); frame.setTitle("Test"); frame.setBounds(10, 10, 180, 130); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }
円形ROIの内部を切り取るために、まず円形ROIを囲む正方形を下記のコードで切り取り、
//ROIのCut public void roiCut () { cutImg = new BufferedImage(xEnd - x0, yEnd - y0, img.getType()); cutImg = img.getSubimage((int)(x - r), (int)(y-r),(int)(2*r), (int)(2*r)); cutBuf = cutImg.getRaster().getDataBuffer();
その後、下記のコードで円形ROIの外部の部分の輝度値を"0"とした。
for (int i = 0; i < cih*ciw; i++) { if (Math.sqrt((i%ciw - ciw/2)*(i%ciw - ciw/2) + (i/ciw - cih/2)*(i/ciw - cih/2)) > r) { cirBuf.setElem(i, 0); } }
かなり無理なコードであるが、下記の実行結果のようにROI内部のみの情報を取り出すことは出来た。