Javaで画像処理(その4)

 前回の続き。2値化フィルタ、収縮・拡張フィルタを追加する。

 ■ソースコード
 前回作成したAbstractImageFilterクラスを継承した、BinaryFilterクラスとExpansionFilterクラスを実装する。

 ・BinaryFilter.java

package test;

public class BinaryFilter extends AbstractImageFilter {
	private int width;
	private int height;
	private int thWidth;
	private int thSize;
	private int threshold;

	public BinaryFilter(){
		thWidth=10;
		thSize=20;
		threshold=0;
	}

	public BinaryFilter(int th){
		thWidth=10;
		thSize=20;
		threshold=th;
	}
	
	public BinaryFilter(int tw,int ts){
		thWidth=tw;
		thSize=ts;
	}
	
	protected void filterImage() {
		if(threshold==0){
			dynamic();
		}else{
			fix();
		}
	}

	public void setDimensions(int w,int h){
		super.setDimensions(w,h);
		width=w;
		height=h;
		consumer.setDimensions(width,height);
	}

	private void fix(){
		int gray=0;
		int[] p=new int[width];
		for(int y=0;y<height;y++){
			for(int x=0;x<width;x++){
				int[] val=getPixelRGBValue(x,y);
				if(val[1]>threshold){
					gray=255;
				}else{
					gray=0;
				}
				p[x]=(255<<24)+(gray<<16)+(gray<<8)+gray;
			}
			consumer.setPixels(0,y,width,1,colorModel,p,0,width);
		}
	}


	private void dynamic(){
		int y1,y2,x1,x2;
		int prev=255;
		int gray=0;
		int[] p=new int[width];
		for(int y=0;y<height;y++){
			if(y<thSize/2){
				y1=0;
				y2=y+thSize/2;
			}else if(height-1-y<thSize/2){
				y1=y-thSize/2;
				y2=height-1;
			}else{
				y1=y-thSize/2;
				y2=y+thSize/2;
			}
			int sizeY=y2-y1+1;
			for(int x=0;x<width;x++){
				if(x<thSize/2){
					x1=0;
					x2=x+thSize/2;
				}else if(width-1-x<thSize/2){
					x1=x-thSize/2;
					x2=width-1;
				}else{
					x1=x-thSize/2;
					x2=x+thSize/2;
				}
				int sizeX=x2-x1+1;
				int average=0;
				for(int i=y1;i<=y2;i++){
					for(int j=x1;j<=x2;j++){
						int[] rgb=getPixelRGBValue(j,i);
						average +=rgb[1];
					}
				}
				average /=(double)(sizeX*sizeY);
				int th;
				if(prev==255){
					th=(int)average-thWidth;
				}else{
					th=(int)average+thWidth;
				}
				int[] val=getPixelRGBValue(x,y);
				if(val[1]<th){
					gray=0;
				}else{
					gray=255;
				}
				p[x]=(255<<24)+(gray<<16)+(gray<<8)+gray;
			}
			consumer.setPixels(0,y,width,1,colorModel,p,0,width);
		}
	}
}

 ・ExpansionFilter.java

package test;

public class ExpansionFilter extends AbstractImageFilter {
	private int width;
	private int height;
	private Ope op;
	private final int OFF=(255<<24)+(255<<16)+(255<<8)+255;
	private final int ON=(255<<24)+(0<<16)+(0<<8)+0;

	private enum Ope{EXPANSION,CONTRACTION}
	
	public static final Ope OP_EXPANSION=Ope.EXPANSION;
	public static final Ope OP_CONTRACTION=Ope.CONTRACTION;

	public ExpansionFilter(Ope arg){
		op=arg;
	}

	public void setOperation(Ope arg){
		op=arg;
	}

	public void setDimensions(int w,int h){
		super.setDimensions(w,h);
		width=w;
		height=h;
		consumer.setDimensions(width,height);
	}
	
	protected void filterImage() {
		if(op==OP_EXPANSION){
			expantion();
		}else{
			contraction();
		}
	}

	private void expantion(){
		int[] p=new int[width];
		for(int y=0;y<height;y++){
			for(int x=0;x<width;x++){
				if(isExpansion(x,y)){
					p[x]=ON;
				}else{
					p[x]=OFF;
				}
			}
			consumer.setPixels(0,y,width,1,colorModel,p,0,width);
		}
	}

	private void contraction(){
		int[] p=new int[width];
		for(int y=0;y<height;y++){
			for(int x=0;x<width;x++){
				if(isContraction(x,y)){
					p[x]=OFF;
				}else{
					p[x]=ON;
				}
			}
			consumer.setPixels(0,y,width,1,colorModel,p,0,width);
		}
	}

	private boolean isExpansion(int x,int y){
		if(x>0&&y>0)if(getPixelRGBValue(x-1,y-1)[1]!=255)return true;
		if(y>0)if(getPixelRGBValue(x,y-1)[1]!=255)return true;
		if(x<width-1&&y>0)if(getPixelRGBValue(x+1,y-1)[1]!=255)return true;
		if(x>0)if(getPixelRGBValue(x-1,y)[1]!=255)return true;
		if(x<width-1)if(getPixelRGBValue(x+1,y)[1]!=255)return true;
		if(x>0&&y<height-1)if(getPixelRGBValue(x-1,y+1)[1]!=255)return true;
		if(y<height-1)if(getPixelRGBValue(x,y+1)[1]!=255)return true;
		if(x<width-1&&y<height-1)if(getPixelRGBValue(x+1,y+1)[1]!=255)return true;
		return false;
	}

	private boolean isContraction(int x,int y){
		if(x>0&&y>0)if(getPixelRGBValue(x-1,y-1)[1]!=0)return true;
		if(y>0)if(getPixelRGBValue(x,y-1)[1]!=0)return true;
		if(x<width-1&&y>0)if(getPixelRGBValue(x+1,y-1)[1]!=0)return true;
		if(x>0)if(getPixelRGBValue(x-1,y)[1]!=0)return true;
		if(x<width-1)if(getPixelRGBValue(x+1,y)[1]!=0)return true;
		if(x>0&&y<height-1)if(getPixelRGBValue(x-1,y+1)[1]!=0)return true;
		if(y<height-1)if(getPixelRGBValue(x,y+1)[1]!=0)return true;
		if(x<width-1&&y<height-1)if(getPixelRGBValue(x+1,y+1)[1]!=0)return true;
		return false;
	}

}

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

		JMenu bimenu=new JMenu("Binary");
		filter.add(bimenu);
		JMenuItem binary=new JMenuItem("Binary");
		binary.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {
				BinaryFilter fil=new BinaryFilter();
				canvas.setBaseImage(applicateFilter(canvas.getImage(),fil,canvas));
				fil=null;
			}
		});
		bimenu.add(binary);
		
		JMenuItem reduc=new JMenuItem("Contraction");
		reduc.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {
				ExpansionFilter fil=new ExpansionFilter(ExpansionFilter.OP_CONTRACTION);
				canvas.setBaseImage(applicateFilter(canvas.getImage(),fil,canvas));
				fil=null;
			}
		});
		bimenu.add(reduc);
		
		JMenuItem exp=new JMenuItem("Expansion");
		exp.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {
				ExpansionFilter fil=new ExpansionFilter(ExpansionFilter.OP_EXPANSION);
				canvas.setBaseImage(applicateFilter(canvas.getImage(),fil,canvas));
				fil=null;
			}
		});
		bimenu.add(exp);

 ■実行結果
 以下の画像は、元画像 -> Prewitt -> Gray -> Reverse -> Binary ->Expantion×2 -> Contractionの順でフィルタをかけたときの様子。