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

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

Javaで画像上にdrawOvalを用いてROI (Circle)を書く

今回は円形のROIの書き方を2種類書く。

Javaでの円の描画には、通常下記のコードを用いる。

  public abstract void drawOval(int x, int y, int width, int height)

このツールでは下の図のように始点からwidthの幅とheightの高さを持つ四角に内接する円を描く。
f:id:Aki-Miya:20150228185205p:plain
こうした円を描くコードは下記のようになる。

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 CircleTest extends JFrame implements ActionListener {

	BufferedImage img;
	DataBuffer buf;
	MyPanel1 mypane1;
	int x0; //マウスをクリックした点のx座標
	int xEnd;  //マウスを離した点のx座標
	int y0; //マウスをクリックした点のy座標
	int yEnd; //マウスを離した点のy座標
	int h;
	int w;

	//画像を開く
	public void OpenImage () {
		try {
			File openFile = new File("C:\\Users\\aki-miya\\Desktop\\picTest.jpg");
			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 MouseCheck1());
		mypane1.addMouseMotionListener(new MouseCheck1());
	}

	//普通の円形ROI用のマウスの動きをモニター
	class MouseCheck1 extends MouseInputAdapter {
		public void mousePressed (MouseEvent eo) {
			x0 = eo.getX();
			y0 =eo.getY();
		}

		public void mouseReleased(MouseEvent eo) {
			Graphics go = mypane1.getGraphics();
			xEnd = eo.getX();
			yEnd = eo.getY();
			go.setColor(Color.BLUE);
			go.drawOval(x0, y0, xEnd - x0, yEnd - y0);
		}
	}

	//画像を張り付ける用のツール
	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);
		}
	}

	//ボタンが押された時のイベント
	public void actionPerformed (ActionEvent e) {
		String cmd = e.getActionCommand();
		if (cmd.equals("open")) {
			OpenImage();
		}
	}

	CircleTest() {
		JButton button = new JButton ("Open");
		button.addActionListener(this);
		button.setActionCommand("open");
		button.setBounds(36, 10, 90, 30);
		JPanel pane = new JPanel();
		pane.setLayout(null);
		pane.add(button);
		getContentPane().add(pane, BorderLayout.CENTER);
	}

	public static void main(String[] args) {
		CircleTest frame = new CircleTest ();
		frame.setTitle("Test");
		frame.setBounds(10, 10, 180, 90);
		frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}

しかし、このツールでは思ったような円が描けないので、次のようにマウスをクリックした点からマウスを離した点を結ぶ円を描くことにした。
f:id:Aki-Miya:20150228185449p:plain
この円を描くコードは次のようにした。

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 CircleTest2 extends JFrame implements ActionListener {

	BufferedImage img;
	DataBuffer buf;
	MyPanel1 mypane1;
	int x0; //マウスをクリックした点のx座標
	int xEnd;  //マウスを離した点のx座標
	int y0; //マウスをクリックした点のy座標
	int yEnd; //マウスを離した点のy座標
	int h;
	int w;

	//画像を開く
	public void OpenImage () {
		try {
			File openFile = new File("C:\\Users\\aki-miya\\Desktop\\picTest.jpg");
			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();
			double r = 0.5*Math.sqrt((xEnd - x0)*(xEnd - x0) + (yEnd - y0) * (yEnd - y0));
			double x = (x0 + xEnd)/2;
			double y = (y0 + yEnd)/2;
			gn.setColor(Color.RED);
			gn.drawOval((int)(x - r), (int)(y-r), (int)(2*r), (int)(2*r));
		}
	}

	//画像を張り付ける用のツール
	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);
		}
	}

	//ボタンが押された時のイベント
	public void actionPerformed (ActionEvent e) {
		String cmd = e.getActionCommand();
		if (cmd.equals("open")) {
			OpenImage();
		}
	}

	CircleTest2() {
		JButton button = new JButton ("Open");
		button.addActionListener(this);
		button.setActionCommand("open");
		button.setBounds(36, 10, 90, 30);
		JPanel pane = new JPanel();
		pane.setLayout(null);
		pane.add(button);
		getContentPane().add(pane, BorderLayout.CENTER);
	}

	public static void main(String[] args) {
		CircleTest2 frame = new CircleTest2 ();
		frame.setTitle("Test");
		frame.setBounds(10, 10, 180, 90);
		frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}

今回は簡単のために正円を描くようにした。(楕円については気が向いたら書こうと思う)
このコードでマウスの動きに合わせて円を描くために、下記のコードで

     public void mouseReleased(MouseEvent en) {
	Graphics gn = mypane1.getGraphics();
	xEnd = en.getX();
	yEnd = en.getY();
	double r = 0.5*Math.sqrt((xEnd - x0)*(xEnd - x0) + (yEnd - y0) * (yEnd - y0));
	double x = (x0 + xEnd)/2;
	double y = (y0 + yEnd)/2;
	gn.setColor(Color.RED);
	gn.drawOval((int)(x - r), (int)(y-r), (int)(2*r), (int)(2*r));
     }

クリックした点とマウスを離した点から円の中心を求め、そこから円の半径を求めている。