Javaで画像処理(その6)

 今回は、線の起点・終点や交点等を探査する特徴点抽出をやってみる。

 ■ソースコード
 特徴点を保持するFeatureクラスと特徴点を探査するFeatureFinderクラスを書く。
 ・Feature.java

package test;

public class Feature {
	private int x;
	private int y;
	private int order;
	private int id;
	private boolean mark;
	public Feature(int a,int b,int c){
		x=a;
		y=b;
		order=c;
		id=0;
		mark=false;
	}

	public boolean isMark() {
		return mark;
	}

	public void setMark(boolean mark) {
		this.mark = mark;
	}

	int getOrder() {
		return order;
	}

	public int getX() {
		return x;
	}

	public int getY() {
		return y;
	}

	void setOrder(int i) {
		order = i;
	}

	void setX(int i) {
		x = i;
	}

	void setY(int i) {
		y = i;
	}

	public int getId() {
		return id;
	}

	public void setId(int i) {
		id = i;
	}

	public boolean equals(Object arg0) {
		if(arg0 instanceof Feature){
			Feature f=(Feature)arg0;
			return (x==f.x&&y==f.y);
		}else{
			return false;
		}
	}
}

 ・FeatureFinder.java

package test.filter;

import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class FeatureFinder {
	private BufferedImage image;
	private int width;
	private int height;
	private int[][] px;
	
	public FeatureFinder(BufferedImage im){
		image=im;
		width=image.getWidth();
		height=image.getHeight();
		px=new int[width][height];
		for(int x=0;x<width;x++){
			for(int y=0;y<height;y++){
				int n=image.getRGB(x,y);
				int val=(n>>16&0xff);
				if(val==255){
					px[x][y]=0;
				}else{
					px[x][y]=1;
				}
			}
		}
	}
	
	public List<Point2D> getFeature(){
		List<Feature> tmp=getFeature(width,height,px);
		List<Point2D> ret=new ArrayList<Point2D>();
		if(tmp.size()>0){
			Iterator<Feature> it=tmp.iterator();
			while(it.hasNext()){
				Feature f=(Feature)it.next();
				ret.add(new Point2D.Double(f.getX(),f.getY()));
			}
			
		}
		return ret;
	}

	private static final List<Feature> getFeature(int width,
					 int height,int[][] binary){
		List<Feature> list=new ArrayList<Feature>();
		for(int y=1;y<height-1;y++){
			for(int x=1;x<width-1;x++){
				if(binary[x][y]==1){
					int val=binary[x+1][y]+binary[x][y-1]+
					   binary[x-1][y]+binary[x][y+1];
					if(val==1||val==3||val==4){
						Feature f=new Feature(x,y,val);
						list.add(f);
					}
				}
			}
		}
		return list;
	}
	
}

次いで、createMenuBarに以下のコードを付け加える。

	JMenuItem feat=new JMenuItem("Feature");
	feat.addActionListener(new ActionListener(){
		@Override
		public void actionPerformed(ActionEvent arg0) {
			Runnable rr=new Runnable(){
				public void run(){
					BufferedImage bi=canvas.getImage();
					FeatureFinder ff=new FeatureFinder(bi);
					List<Point2D> feature=ff.getFeature();
					final VolatileImage vi=canvas.createVolatileImage(
						 bi.getWidth(), bi.getHeight());
					Graphics2D g2=(Graphics2D)vi.createGraphics();
					g2.drawImage(bi,0,0,canvas);
					g2.setColor(Color.RED);
					for(Point2D p :feature){
						Ellipse2D ep=new Ellipse2D.Double(
						   p.getX()-2,p.getY()-2,4d,4d);
						g2.draw(ep);
					}
					Runnable rx=new Runnable(){
						public void run(){
							canvas.setBaseImage(vi);
						}
					};
					SwingUtilities.invokeLater(rx);
				}
			};
			new Thread(rr).start();
		}
	});
	filter.add(feat);

 ■実行結果
 こんな感じ。(右から、元画像、細線化、特徴点抽出)
 ちなみに、細線化等の前処理が必要。
 一応、線の起点・終点・交点が検出されているのがわかる。