Javaで画像処理(その5)
前回の続き。境界抽出フィルタと細線化フィルタを追加する。
■ソースコード
AbstractImageFilterを継承した、BorderTraceFilterクラスとThinningFilterクラスを実装する。
・BorderTraceFilter.java
package test; import java.awt.Color; public class BorderTraceFilter extends AbstractImageFilter { private int width; private int height; private int back; public BorderTraceFilter(Color back){ this.back=(back.getRGB()<<8); } public void setDimensions(int w,int h){ super.setDimensions(w,h); width=w; height=h; consumer.setDimensions(width,height); } protected void filterImage() { int[][] p=createBinary(); int[][] b=new int[p.length][p[0].length]; b=border_trace(p,b); int[] px=new int[width]; int backcolor=(back>>8); for(int y=0;y<height;y++){ for(int x=0;x<width;x++){ if(b[x][y]==0){ px[x]=(255<<24)+backcolor; }else{ px[x]=getPixelValue(x,y); } } consumer.setPixels(0,y,width,1,colorModel,px,0,width); } } private int[][] border_trace(int[][] p,int[][] b){ int code=0; for(int y=1;y<height-1;y++){ for(int x=1;x<width-1;x++){ if(p[x][y]==1&&b[x][y]==0){ if(p[x-1][y]==0){ code=0; trace(x,y,code,p,b); }else if(p[x+1][y]==0){ code=4; trace(x,y,code,p,b); } } } } return b; } private void trace(int x,int y,int code,int[][] p,int[][] b){ if(!check(x,y,p))return; int xs=x; int ys=y; int x1=x; int x2=0; int y1=y; int y2=0; while(x2!=xs||y2!=ys){ switch(code){ case 0: x2=x1; y2=y1+1; if(y2<height&&p[x2][y2]==1){ code=6; }else{ code=2; } break; case 2: x2=x1+1; y2=y1; if(x2<width&&p[x2][y2]==1){ code=0; }else{ code=4; } break; case 4: x2=x1; y2=y1-1; if(y2>=0&&p[x2][y2]==1){ code=2; }else{ code=6; } break; case 6: x2=x1-1; y2=y1; if(x2>=0&&p[x2][y2]==1){ code=4; }else{ code=0; } break; } if(x2>=0&&x2<width&&y2>=0&&y2<height){ if(p[x2][y2]==1){ b[x2][y2]=1; x1=x2; y1=y2; } } } } private int[][] createBinary(){ int[][] ret=new int[width][height]; int p; for(int y=0;y<height;y++){ for(int x=0;x<width;x++){ p=(getPixelValue(x,y)<<8); if(p==back){ ret[x][y]=0; }else{ ret[x][y]=1; } } } return ret; } private boolean check(int x,int y,int[][] p){ if(p[x-1][y]==0&&p[x+1][y]==0&&p[x][y-1]==0&&p[x][y+1]==0){ return false; }else{ return true; } } }
・ThinningFilter.java
package test; import java.awt.Color; public class ThinningFilter extends AbstractImageFilter { private int width; private int height; private int back; public ThinningFilter(Color back){ this.back=(back.getRGB()<<8); } public void setDimensions(int w,int h){ super.setDimensions(w,h); width=w; height=h; consumer.setDimensions(width,height); } protected void filterImage() { thnning(); } private void thnning(){ int[][] main=createBinary(); int[][] sub=createBinary(); int[] aa=new int[9]; int[] bb=new int[9]; int rev=1; int num=0; while(rev!=0){ rev=0; num++; for(int y=1;y<height-1;y++){ for(int x=1;x<width-1;x++){ if(main[x][y]==0)continue; aa[0]=main[x+1][y]; bb[0]=sub[x+1][y]; aa[1]=main[x+1][y-1]; bb[1]=sub[x+1][y-1]; aa[2]=main[x][y-1]; bb[2]=sub[x][y-1]; aa[3]=main[x-1][y-1]; bb[3]=sub[x-1][y-1]; aa[4]=main[x-1][y]; bb[4]=sub[x-1][y]; aa[5]=main[x-1][y+1]; bb[5]=sub[x-1][y+1]; aa[6]=main[x][y+1]; bb[6]=sub[x][y+1]; aa[7]=main[x+1][y+1]; bb[7]=sub[x+1][y+1]; int sum=0; for(int i=0;i<8;i++) sum +=aa[i]; if(sum==0)sub[x][y]=0; if(sum>=2&&sum<=5){ if(connect(aa)==1&&connect(bb)==1){ for(int j=1;j<5;j++){ if(bb[j]==0){ int c=aa[j]; aa[j]=0; if(connect(aa)!=1){ aa[j]=c; break; } aa[j]=c; } sub[x][y]=0; } } } if(sub[x][y]==0)rev++; } } for(int y=0;y<height;y++){ for(int x=0;x<width;x++){ main[x][y]=sub[x][y]; } } } int backcolor=(back>>8); for(int y=0;y<height;y++){ int[] p=new int[width]; for(int x=0;x<width;x++){ if(main[x][y]==0){ p[x]=(255<<24)+backcolor; }else{ p[x]=getPixelValue(x,y); } } consumer.setPixels(0,y,width,1,colorModel,p,0,width); } } private int connect(int[] val){ val[8]=val[0]; int num=0; for(int i=1;i<val.length;i++){ if(val[i]==1&&val[i-1]==0)num++; } return num; } private int[][] createBinary(){ int[][] ret=new int[width][height]; int p; for(int y=0;y<height;y++){ for(int x=0;x<width;x++){ p=(getPixelValue(x,y)<<8); if(p==back){ ret[x][y]=0; }else{ ret[x][y]=1; } } } return ret; } }
次いで、createMenuBarに以下のコードを付け加える。
JMenuItem tin=new JMenuItem("Thinning"); tin.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent arg0) { ThinningFilter fil=new ThinningFilter(Color.WHITE); canvas.setBaseImage(applicateFilter(canvas.getImage(),fil,canvas)); fil=null; } }); filter.add(tin); JMenuItem bor=new JMenuItem("BorderTrace"); bor.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent arg0) { BorderTraceFilter fil=new BorderTraceFilter(Color.WHITE); canvas.setBaseImage(applicateFilter(canvas.getImage(),fil,canvas)); fil=null; } }); filter.add(bor);
■実行結果
実行結果は、以下のとおり(元画像、細線化、境界抽出)。