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

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

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内部のみの情報を取り出すことは出来た。
f:id:Aki-Miya:20150228211434p:plain