Javaで画像処理

 Javaは、java.awt.imageパッケージのImageFilterインターフェイスを実装することで、結構簡単に画像処理ができる。
 とりあえず、RGB補正の簡単なサンプルを書いてみる。

 ■ソースコード
 ソースコードは以下のとおり。
 RGBImageFilterを継承したRGBFilterクラスで処理を行っている。

package test;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.awt.image.ImageProducer;
import java.awt.image.RGBImageFilter;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileFilter;

public class TestFilter extends JFrame{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private ImageCanvas canvas;
	private JFileChooser dialog;
	private JSlider[] slider;

	public TestFilter(){
		super();
		super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		super.setTitle("ImageFilterTest");
		super.getContentPane().setLayout(new BorderLayout());
		canvas=new ImageCanvas();
		canvas.setBorder(BorderFactory.createLoweredBevelBorder());
		super.getContentPane().add(new JScrollPane(canvas),BorderLayout.CENTER);
		dialog=new JFileChooser();
		super.setJMenuBar(createMenuBar());
		super.setSize(600,600);
		JPanel p0=new JPanel(new GridLayout(4,1));
		slider=new JSlider[4];
		String[] nn=new String[]{"Alpha","Red","Green","Blue"};
		final JLabel[] ll=new JLabel[4];
		for(int i=0;i<slider.length;i++){
			JPanel p=new JPanel();
			BoxLayout bl=new BoxLayout(p,BoxLayout.X_AXIS);
			p.setLayout(bl);
			JLabel pn=new JLabel(nn[i]);
			pn.setPreferredSize(new Dimension(40,16));
			p.add(pn);
			slider[i]=new JSlider();
			slider[i].setMinimum(0);
			slider[i].setMaximum(100);
			slider[i].setValue(100);
			slider[i].setMajorTickSpacing(10);
			slider[i].setMinorTickSpacing(5);
			slider[i].setPaintTicks(true);
			slider[i].setPaintTrack(true);
			p.add(slider[i]);
			ll[i]=new JLabel("100");
			ll[i].setPreferredSize(new Dimension(30,16));
			p.add(ll[i]);
			final int id=i;
			slider[i].addChangeListener(new ChangeListener(){
				@Override
				public void stateChanged(ChangeEvent arg0) {
					JSlider sl=(JSlider)arg0.getSource();
					ll[id].setText(Integer.toString(sl.getValue()));
					updateFilter();
				}
			});
			p0.add(p);
		}
		FileFilter filter=new FileFilter(){
			@Override
			public boolean accept(File arg0) {
				String ext=arg0.getName().toLowerCase();
				return (ext.endsWith(".png")||ext.endsWith(".jpg"));
			}
			@Override
			public String getDescription() {
				return "*.png,*.jpg";
			}
			
		};
		dialog.setFileFilter(filter);
		super.getContentPane().add(p0,BorderLayout.SOUTH);
	}

	private JMenuBar createMenuBar(){
		JMenuBar bar=new JMenuBar();
		JMenu menu=new JMenu("File");
		bar.add(menu);
		JMenuItem open=new JMenuItem("Open");
		open.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {
				File f=getFile(JFileChooser.OPEN_DIALOG);
				if(f==null)return;
				try{
					Image im=ImageIO.read(f);
					canvas.setBaseImage(im);
				}catch(IOException e){
					JOptionPane.showMessageDialog(
				 	 canvas,e.getMessage(),"Info",
				 	  JOptionPane.WARNING_MESSAGE);
				}
			}
		});
		menu.add(open);
		JMenuItem save=new JMenuItem("Save");
		save.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {
				File f=getFile(JFileChooser.SAVE_DIALOG);
				if(f==null)return;
				try{
					ImageIO.write(canvas.getImage(), "png", f);
				}catch(IOException e){
					JOptionPane.showMessageDialog(
				 	 canvas,e.getMessage(),"Info",
				 	  JOptionPane.WARNING_MESSAGE);
				}
			}
		});
		menu.add(save);
		JMenuItem exit=new JMenuItem("Exit");
		menu.addSeparator();
		menu.add(exit);
		return bar;
	}

	File getFile(int type){
		if(type==JFileChooser.OPEN_DIALOG){
			dialog.setDialogTitle("Open");
			dialog.setDialogType(JFileChooser.OPEN_DIALOG);
			int flg=dialog.showOpenDialog(this);
			if(flg==JFileChooser.APPROVE_OPTION){
				return dialog.getSelectedFile();
			}else{
				return null;
			}
		}else{
			dialog.setDialogTitle("Save");
			dialog.setDialogType(JFileChooser.SAVE_DIALOG);
			int flg=dialog.showSaveDialog(this);
			if(flg==JFileChooser.APPROVE_OPTION){
				return dialog.getSelectedFile();
			}else{
				return null;
			}
		}
	}

	void updateFilter(){
		if(canvas.getImage()==null)return;
		double t=(double)slider[0].getValue()/100.0;
		double r=(double)slider[1].getValue()/100.0;
		double g=(double)slider[2].getValue()/100.0;
		double b=(double)slider[3].getValue()/100.0;
		RGBFilter fil=new RGBFilter(t,r,g,b);
		canvas.setImage(applicateFilter(canvas.getBaseImage(),fil,this));
	}
	
	private Image applicateFilter(Image image,ImageFilter fil,Component com){
		ImageProducer ip=image.getSource();
		ImageProducer ip2=new FilteredImageSource(ip,fil);
		return com.createImage(ip2);
	};
	
	private class RGBFilter extends RGBImageFilter {
		private double trans,red,green,blue;
		public RGBFilter(double t,double r,double g,double b){
			super();
			trans=t;
			red=r;
			green=g;
			blue=b;
			super.canFilterIndexColorModel=true;
		}

		public int filterRGB(int x, int y, int rgb) {
			int t=(int)((double)(rgb>>24&0xff)*trans);
			int r=(int)((double)(rgb>>16&0xff)*red);
			int g=(int)((double)(rgb>>8&0xff)*green);
			int b=(int)((double)(rgb&0xff)*blue);
			int ret=(t<<24)+(r<<16)+(g<<8)+b;
			return ret;
		}

	}
	
	private class ImageCanvas extends JComponent{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		private Image image;
		private Image baseImage;
		private int width,height;

		BufferedImage getImage(){
			BufferedImage bi=new BufferedImage(width,height,
				 BufferedImage.TYPE_INT_ARGB);
			Graphics g=bi.createGraphics();
			paintComponent(g);
			return bi;
		}
		
		Image getBaseImage(){
			return baseImage;
		}
		
		void setBaseImage(Image img){
			baseImage=img;
			image=baseImage;
			repaint();
		}
		
		void setImage(Image img){
			image=img;
			repaint();
		}
		
		@Override
		protected void paintComponent(Graphics g) {
			if(image!=null){
				int w=image.getWidth(this);
				int h=image.getHeight(this);
				if(w!=width||h!=height){
					width=w;
					height=h;
					this.setPreferredSize(new Dimension(width,height));
				}
				g.drawImage(image, 0, 0,this);
			}
		}
	}
	
	public static void main(String[] args) {
		TestFilter doit=new TestFilter();
		doit.setVisible(true);
	}
}

 ■実行結果
 とりあえず、こんな感じ。左が処理前で、右が処理後の画像。


 ■参考資料
 C#用ですが、大分前に買ったこの本を参考にしました。

ディジタル画像処理の基礎と応用―基本概念から顔画像認識まで

ディジタル画像処理の基礎と応用―基本概念から顔画像認識まで