它的核心思想就是让图像暗的地方变亮,亮的地方变暗。问题是,如果图像原本的亮暗程度就非常符合人眼的观察结果,那么直方图均衡化之后的图像就变的很糟。所以该方法要依据图像数据的特点而定。
图像整体变亮,暗处的细节得到了突出:
import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.*; public class chongcaiyang extends Frame{ Image im, tmp; int iw, ih; int[] pixels; boolean flag_load = false; //构造方法 public chongcaiyang(){ super("chongcaiyang"); Panel pdown; Button load, run, save, quit; addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } }); pdown = new Panel(); pdown.setBackground(Color.lightGray); //定义按钮 load = new Button("装载图像"); run = new Button("重采样"); save = new Button("保存"); quit = new Button("退出"); this.add(pdown, BorderLayout.SOUTH); //添加按钮 此处的顺序为案板上的左->右的顺序 pdown.add(load); pdown.add(run); pdown.add(save); pdown.add(quit); //按钮的动作程序 装载图像 load.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ try { jLoad_ActionPerformed(e); } catch (IOException e1) { e1.printStackTrace(); } } }); //按钮的动作程序 重采样 run.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ try { jRun_ActionPerformed(e); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } }); //按钮的动作程序 保存 save.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ try { jSave_ActionPerformed(e); } catch (IOException e1) { e1.printStackTrace(); } } }); //按钮的动作程序 退出 quit.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ jQuit_ActionPerformed(e); } }); } //按钮动作的实现 加载图像 public void jLoad_ActionPerformed(ActionEvent e) throws IOException{ File inputFile = new File("d:\\java\\sc\\lena_grey.jpg"); BufferedImage input = ImageIO.read(inputFile); tmp = input; flag_load = true; repaint(); } //按钮动作的实现 重采样 public void jRun_ActionPerformed(ActionEvent e) throws IOException{ if(flag_load){ File inputFile = new File("d:\\java\\sc\\lena_grey.jpg"); BufferedImage input = ImageIO.read(inputFile); iw = input.getWidth(this); ih = input.getHeight(this); //设定N值 int N = iw; String s = JOptionPane.showInputDialog(null,"请输入N值(512/256/128/64/32/16/8)"); if(s!= null&& !s.equals("")){ N = Integer.parseInt(s); } //检查输入是否正确 if((N>512)|(N<8)){ N = 512; JOptionPane.showMessageDialog(null, "输入不正确,请重新输入!"); } //图像重采样 BufferedImage grayImage = new BufferedImage(iw, ih, BufferedImage.TYPE_BYTE_GRAY); //kao!三个循环就就能搞定,不就是重采样吗? for(int i=0; i<ih-1; i++){ for(int j=0; j<iw-1; j=j+(ih/N)){ for(int k=0; k<(ih/N); k++){ int rgb = input.getRGB(i, j); int grey = (int) (0.3*((rgb&0xff0000)>>16)+0.59*((rgb&0xff00)>>8)+0.11*((rgb&0xff))); rgb = 255<<24|grey<<16|grey<<8|grey; grayImage.setRGB(i, j+k, rgb); } } } //产生图像 tmp = grayImage; flag_load = true; repaint(); }else{ JOptionPane.showMessageDialog(null, "先点击“装载图像”,3Q!","提示:", JOptionPane.WARNING_MESSAGE); } } //按钮动作的实现保存 public void jSave_ActionPerformed(ActionEvent e) throws IOException{ if(flag_load){ BufferedImage bi = new BufferedImage(tmp.getWidth(null),tmp.getHeight(null), BufferedImage.TYPE_INT_RGB); Graphics g = bi.getGraphics(); g.drawImage(tmp,0, 0,null); g.dispose(); File save_path=new File("d:\\java\\sc\\save_t01.jpg"); ImageIO.write(bi, "JPG", save_path); }else{ JOptionPane.showMessageDialog(null, "先点击“装载图像”,3Q!","提示:", JOptionPane.WARNING_MESSAGE); } } //按钮动作的实现 退出 public void jQuit_ActionPerformed(ActionEvent e){ System.exit(0); } //绘图函数 public void paint(Graphics g){ //if(flag_Load){ g.drawImage(tmp,50,50,this); //}else{} } public static void main(String[] args) { chongcaiyang ti = new chongcaiyang(); ti.setSize(1000,860); ti.setVisible(true); } }
import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.*; public class hist extends Frame{ Image im, tmp; int iw, ih; int[] pixels; boolean flag_load = false; boolean flag_grey = false; //hist的构造方法 public hist(){ this.setTitle("直方图均衡化"); Panel pdown; Button load, grey, hist, run, save, quit; //添加窗口监听事件 addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } } ); pdown = new Panel(); pdown.setBackground(Color.LIGHT_GRAY); //按钮名称 load = new Button("装载图像"); grey = new Button("灰度图像"); hist = new Button("直方图"); run = new Button("均衡化"); save = new Button("保存"); quit = new Button("退出"); this.add(pdown, BorderLayout.SOUTH); //增加按钮 pdown.add(load); pdown.add(grey); pdown.add(hist); pdown.add(run); pdown.add(save); pdown.add(quit); //按钮的动作程序 装载图像 load.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ try { jLoad_ActionPerformed(e); } catch (IOException e1) { e1.printStackTrace(); } } }); //按钮的动作程序 灰度化 grey.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ try { jGrey_ActionPerformed(e); } catch (IOException e1) { e1.printStackTrace(); } } }); //按钮的动作程序 直方图 hist.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ jHist_ActionPerformed(e); } }); //按钮的动作程序 直方图均衡化 run.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ jRun_ActionPerformed(e); } }); //按钮的动作程序 保存 save.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ try { jSave_ActionPerformed(e); } catch (IOException e1) { e1.printStackTrace(); } } }); //按钮的动作程序 退出 quit.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ jQuit_ActionPerformed(e); } }); } //按钮动作的实现 加载图像 public void jLoad_ActionPerformed(ActionEvent e) throws IOException{ File inputFile = new File("d:\\java\\sc\\source.jpg"); BufferedImage input = ImageIO.read(inputFile); im = input; tmp = input; flag_load = true; repaint(); } //按钮动作的实现 灰度化 public void jGrey_ActionPerformed(ActionEvent e) throws IOException{ if(flag_load){ File inputFile = new File("d:\\java\\sc\\source.jpg"); BufferedImage input = ImageIO.read(inputFile); iw = input.getWidth(this); ih = input.getHeight(this); pixels = new int[iw*ih]; BufferedImage grayImage = new BufferedImage(iw, ih, BufferedImage.TYPE_BYTE_GRAY); for(int i=0; i<iw; i++){ for(int j=0; j<ih; j++){ int rgb = input.getRGB(i, j); int grey = (int) (0.3*((rgb&0xff0000 )>>16)+0.59*((rgb&0xff00 )>>8)+0.11*((rgb&0xff))); rgb = 255<<24|grey<<16|grey<<8|grey; grayImage.setRGB(i, j, rgb); } } tmp = grayImage; try{ PixelGrabber pg = new PixelGrabber(tmp,0,0,iw,ih,pixels,0,iw); pg.grabPixels(); }catch(InterruptedException e3){ e3.printStackTrace(); } flag_grey = true; repaint(); } else{ JOptionPane.showMessageDialog(null, "先点击“装载图像”,3Q!","提示:", JOptionPane.WARNING_MESSAGE); } } //按钮动作的实现 直方图显示 调用histshow这个类进行操作 public void jHist_ActionPerformed(ActionEvent e){ histshow h = new histshow(); h.getData(pixels, iw, ih); h.setSize(480,350); h.setVisible(true); } //按钮动作的实现 直方图均衡化 public void jRun_ActionPerformed(ActionEvent e){ if(flag_load&&flag_grey){ try{ PixelGrabber pg = new PixelGrabber(tmp,0,0,iw,ih,pixels,0,iw); pg.grabPixels(); }catch(InterruptedException e3){ e3.printStackTrace(); } BufferedImage greyImage = new BufferedImage(iw, ih, BufferedImage.TYPE_BYTE_GRAY); //获取图像的直方图 int[] histogram = new int[256]; for(int i=0; i<ih-1; i++){ for(int j=0; j<iw-1; j++){ int grey = pixels[i*iw+j]&0xff; histogram[grey]++; } } //直方图均衡化 double a = (double)255/(iw*ih); double[] c = new double [256]; c[0] = (a*histogram[0]); for(int i=1; i<256; i++){ c[i] = c[i-1]+(int)(a*histogram[i]); } for(int i=0; i<ih; i++){ for(int j=0; j<iw; j++){ int grey = pixels[i*iw+j]&0x0000ff; int hist = (int)(c[grey]); pixels[i*iw+j] = 255<<24|hist<<16|hist<<8|hist; greyImage.setRGB(j, i, pixels[i*iw+j]); } } tmp = greyImage; flag_load = true; repaint(); }else{ JOptionPane.showMessageDialog(null, "先点击“装载图像”,3Q!","提示:", JOptionPane.WARNING_MESSAGE); } } //按钮动作的实现保存 public void jSave_ActionPerformed(ActionEvent e) throws IOException{ if(flag_load){ BufferedImage bi = new BufferedImage(tmp.getWidth(null),tmp.getHeight(null), BufferedImage.TYPE_INT_RGB); Graphics g = bi.getGraphics(); g.drawImage(tmp,0, 0,null); g.dispose(); File save_path=new File("d:\\java\\sc\\save_t01.jpg"); ImageIO.write(bi, "JPG", save_path); }else{ JOptionPane.showMessageDialog(null, "先点击“装载图像”,3Q!","提示:", JOptionPane.WARNING_MESSAGE); } } //按钮动作的实现 退出 public void jQuit_ActionPerformed(ActionEvent e){ System.exit(0); } //绘图函数 public void paint(Graphics g){ //if(flag_Load){ g.drawImage(tmp,50,50,this); //}else{} } public static void main(String[] args) { hist ti = new hist(); ti.setSize(900,860); ti.setVisible(true); } }
import java.awt.*; import java.awt.event.*; import java.awt.Window; public class histshow extends Frame{ int data[]; int histogram[] = new int[256]; public histshow(){ this.setTitle("图像的灰度直方图"); Panel pdown; Button quit; pdown = new Panel(); quit = new Button("关闭窗口"); this.add(pdown, BorderLayout.SOUTH); pdown.add(quit); quit.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ jQuit_ActionPerformed(e); } }); // 添加窗口监听事件 addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ histshow.this.dispose(); } }); } public void jQuit_ActionPerformed(ActionEvent e){ this.setVisible(false); } public void getData(int[] data, int iw, int ih){ this.data = data; for (int i = 0; i < iw * ih; i++){ int grey = data[i] & 0xff; histogram[grey]++; } // 找出最大的数,进行标准化. int temp = histogram[0]; for (int i = 0; i < 256; i++){ if (temp <= histogram[i]){ temp = histogram[i]; //System.out.println(temp); } } for (int i = 0; i < 256; i++){ histogram[i] = histogram[i] * 200 / temp; //System.out.println(temp); } } //画出直方图 public void paint(Graphics g){ // 画出水平和垂直的轴 g.drawLine(100, 250, 356, 250); g.drawLine(100, 50, 100, 250); // 画出横轴坐标 g.drawString("0", 98, 263); g.drawString("50", 145, 263); g.drawString("100", 193, 263); g.drawString("150", 243, 263); g.drawString("200", 293, 263); g.drawString("250", 343, 263); // 画出纵轴坐标 g.drawString("0.5", 83, 145); g.drawString("1", 90, 60); // 画出图像的直方图 for (int i = 0; i < 256; i++){ g.drawLine(100 + i, 250, 100 + i, 250 - histogram[i]); } g.drawString("该图像的灰度直方图如上所示.", 160, 280); } }