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の順でフィルタをかけたときの様子。