现在的位置: 首页 > 综合 > 正文

图像的采样与量化及灰度直方图

2012年06月24日 ⁄ 综合 ⁄ 共 10536字 ⁄ 字号 评论关闭

图像的采样

采样是把空域上或时域上连续的图像(模拟图像)转换成离散采样点(像素)集合(数字图像)的操作。

 采样越细,像素越小,越能精细地表现图像。不同采样间距的效果如下:

    
 

a.采样间隔16                                                                     b.采样间隔32                                                                     c.采样间隔64

图1

算法源代码1(java):

/**
	 * 对图像进行采样
	 * 
	 * @param pix
	 *            保存图片像素
	 * @param iw
	 *            二维像素矩阵的宽
	 * @param ih
	 *            二维像素矩阵的高
	 * @param grey
	 *            采样间距
	 * @return
	 */
	private static int[] sample(int[] pix, int iw, int ih, int grey) {
		// 对图像进行采样
		ColorModel cm = ColorModel.getRGBdefault();

		int d = (int) (256 / grey); // 采样间隔
		int dd = d * d;
		for (int i = 0; i < ih; i = i + d) {
			for (int j = 0; j < iw; j = j + d) {
				int r = 0, g = 0, b = 0;
				for (int k = 0; k < d; k++)
					for (int l = 0; l < d; l++) {
						r = r + cm.getRed(pix[(i + k) * iw + (j + l)]);
						g = g + cm.getGreen(pix[(i + k) * iw + (j + l)]);
						b = b + cm.getBlue(pix[(i + k) * iw + (j + l)]);
					}
				r = (int) (r / dd);
				g = (int) (g / dd);
				b = (int) (b / dd);
				for (int k = 0; k < d; k++)
					for (int l = 0; l < d; l++)
						// pix[(i+k)*iw+(j+l)] = 255<<24|r<<16|g<<8|b;
						pix[(i + k) * iw + (j + l)] = new Color(r, g, b)
								.getRGB();
			}
		}
		return pix;
	}

图像的量化

量化是把像素的灰度(浓淡)变换成离散的整数值的操作。最简单的量化是用黑(0)白(255)两个数值(即2级)来表示,成为二值图像。

量化越细致,灰度级数(浓淡层次)表现越丰富。计算机中一般用8bit(256级)来量化,这意味着像素的灰度(浓淡)是0—255之间的数值。化级数的效果图如下:

    
 

a.量化级数2                                                                    b.量化级数8                                                                 c.量化级数64

图2

算法源代码2(java): 

/**
	 * 对图像进行量化
	 * @param srcPath 原图像文件路径
	 * @param distPath 目标图像文件路径
	 * @param grey 量化的级数
	 */
	public static void quantize(String srcPath, String distPath, int grey) {
		OutputStream out = null;
		try {
			BufferedImage img = ImageIO.read(new File(srcPath));
			int imgType = img.getType();
			int w = img.getWidth();
			int h = img.getHeight();
			int pix[] = new int[w*h];
			img.getRGB(0, 0, w, h, pix, 0, w);
			int greyScope = 256/grey;
			int r,g,b,temp;
			r=b=g=temp=0;
			ColorModel cm=ColorModel.getRGBdefault();
			for(int i=0; i<w*h; i++) {
				r = cm.getRed(pix[i]);
				temp = r/greyScope;
				r = temp*greyScope;
				g = cm.getGreen(pix[i]);
				temp = g/greyScope;
				g = temp*greyScope;
				b = cm.getBlue(pix[i]);
				temp = b/greyScope;
				b = temp*greyScope;
				pix[i] = new Color(r, g, b).getRGB();
			}
			out = new FileOutputStream(distPath);
			BufferedImage imgOut = new BufferedImage(w, h, imgType); 
			imgOut.setRGB(0, 0, w, h, pix, 0, w);
			ImageIO.write(imgOut, "jpg", out);
			System.out.println("test");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				out.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

图像直方图

直方图的定义

灰度直方图(histogram)是灰度级分布的函数,它表示图象中具有每种灰度级的象素的个数,反映图象中每种灰度出现的频率。灰度直方图的横坐标是灰度级,纵坐标是该灰度级出现的频率,是图象的最基本的统计特征。

生成图像灰度直方图的一般步骤:

1、统计各个灰度值的像素个数;

2、根据统计表画出直方图

如下图

 

图3


图4

算法源代码3:见下面算法源代码4中的drawHistogram()方法

灰度直方图的性质

1、只反映该图像中不同灰度值出现的次数(或频率),而不能反映某一灰度值像素所在的位置;

2、任何一张图像能唯一地确定一个与它对应的直方图,而一个直方图可以有多个不同的图像;

3、如果一张图片被剪裁成多张图片,各个子图的直方图之和就是这个全图的直方图。

直方图的用途

直方图有很多的用途,比如阀值分割,图像增强,还常常用于医疗影像。

 

图像的阀值(二值)处理

阀值处理的定义


图像的阀值处理是将图像的像素灰度值在某个定值(设为t)以上的点赋值为白色(或黑色),在这个定值t以下的点赋值为黑色(或白色)的处理过程。用公式表示成:


由于图像的阀值处理得到的是只有两个灰度值的二值图像,所以也将阀值处理称作二值化处理,得到的图像叫二值图像。如下图

图像阀值处理的步骤

1、 画出图像的灰度直方图;

2、 根据图像的灰度直方图确定阀值t,如图5的阀值为65;

3、 将像素灰度值小于等于t的点赋值为白色(或黑色),大于t的点赋值为黑色(或白色);效果如图6:

图5

图6

算法源代码4(java):

package cn.edu.jxau.luoweifu;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.io.File;
import java.io.IOException;
import java.util.Date;

import javax.imageio.ImageIO;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;


/**
 * 设置头像
 * @author 罗伟富
 *
 */
public class Histogram extends JFrame implements ChangeListener, ActionListener{
	/**
	 * 头像界面的宽度
	 */
	public static final int WIDTH = 680;
	/**
	 * 头像界面的高度
	 */
	public static final int HEIGHT = 400;
	/**
	 * 显示图片版面的宽度
	 */
	public static final int PWIDTH = 350;
	/**
	 * 显示图片版面的高度
	 */
	public static final int PHEIGHT = 300;
	/**
	 * 直方图版面的宽度
	 */
	public static final int H_WIDTH = 350;
	/**
	 * 直方图片版面的高度
	 */
	public static final int H_HEIGHT = 300;
	/**
	 * 滑块的最大值
	 */
	public static final int JS_MAXIMUM = 100;
	
	public static final String FRAMTITLE = "图像的灰度直方图";
	private String imgSrc;
	Image img;
	JSlider jsliderH, jsliderV;	//水平和垂直滑块
	JPanel uP, picP, uplodP, histP;
	JButton openFile, histogram, threshold; 
	MyCanvas canvas;
	Canvas histCanvas;
	int imgW = PWIDTH, imgH = PHEIGHT;
	int xcentre = PWIDTH/2, ycentre = PHEIGHT/2;
	private int dx1 = xcentre-imgW/2, dy1 = ycentre-imgH/2, dx2 = xcentre + imgW/2, dy2 = ycentre + imgH/2;
	private int sx1 = 0, sy1 = 0, sx2, sy2;
	private float shx = 0, shy = 0;
	/**
	 * 构造函数
	 */
	public Histogram() {
		setTitle(FRAMTITLE);
		launchDialog();
	}
	
	/**
	 * 返回canvas
	 * @return
	 */
	public Canvas getCanvas() {
		return canvas;
	}
	/**
	 * 界面设计
	 */
	private void launchDialog() {
		//初始化图片对象
		imgSrc = "F:\\image processing\\baboom2_gray.jpg";
		img = Toolkit.getDefaultToolkit().getImage(imgSrc);
		//初始化组件
		canvas = new MyCanvas();
		jsliderH = new JSlider();
		jsliderH.setMaximum(JS_MAXIMUM);
		jsliderH.setValue(JS_MAXIMUM/2);
		jsliderH.setMinimum(1);
		jsliderH.setOrientation(JSlider.HORIZONTAL);
		jsliderH.addChangeListener(this);
		jsliderV = new JSlider();
		jsliderV.setMaximum(JS_MAXIMUM);
		jsliderV.setValue(JS_MAXIMUM/2);
		jsliderV.setMinimum(1);
		jsliderV.setOrientation(JSlider.VERTICAL);
		jsliderV.addChangeListener(this);
		picP = new JPanel();
		picP.setPreferredSize(new Dimension(PWIDTH, PHEIGHT));
		//picP.setBackground(Color.green);
		uP = new JPanel();
		uplodP = new JPanel();
		openFile = new JButton("打开图片");
		histogram = new JButton("显示直方图");
		threshold = new JButton("显示二值图像");
		openFile.addActionListener(this);
		histogram.addActionListener(this);	
		threshold.addActionListener(this);
		//添加组件
		picP.setLayout(new BorderLayout());
		picP.add(canvas, BorderLayout.CENTER);
		uP.setLayout(new BorderLayout());
		uP.add(picP, BorderLayout.CENTER);
		uP.add(jsliderH, BorderLayout.SOUTH);
		uP.add(jsliderV, BorderLayout.EAST);
		
		histCanvas = new Canvas();
		histP = new JPanel(new BorderLayout());
		histP.add(histCanvas);
		histP.setPreferredSize(new Dimension(H_WIDTH, H_HEIGHT));
		histP.setBorder(new LineBorder(Color.blue));
		//System.out.println("w:" + histP.getWidth() + "  h:" + histP.getHeight() + " " + histP.HEIGHT);
		
		uplodP.setLayout(new FlowLayout());		
		uplodP.add(openFile);		
		uplodP.add(histogram);
		uplodP.add(threshold);
		Container c = getContentPane();
		c.setLayout(new BoxLayout(c, BoxLayout.Y_AXIS));
		//c.add(uP);
		JPanel p = new JPanel();
		p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
		p.add(uP);
		p.add(histP);
		c.add(p);
		c.add(uplodP);
		setSize(WIDTH, HEIGHT);
		setResizable(false);
		setLocationRelativeTo(null);
		setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
		setVisible(true);		
	}
	
	public void drawHistogram() {
		try {
			BufferedImage bfImg = ImageIO.read(new File(imgSrc));
			int w = bfImg.getWidth();
			int h = bfImg.getHeight();
			int pix[] = new int[w*h];
			int hist[] = new int[256];
			/*for(int i=0; i<hist.length; i++) {
				hist[i] = 0;
			}*/
			int imgType = bfImg.getType();
			int temp;
			bfImg.getRGB(0, 0, w, h, pix, 0, w);
			ColorModel cm = ColorModel.getRGBdefault();
			for(int i=0; i<pix.length; i++) {
				/*for(int j=0; j<hist.length; j++) {
					if(j ==  cm.getRed(pix[i])) {
						hist[j] ++;
					}
				}*/				
				temp = cm.getRed(pix[i]);
				hist[temp] ++;
			}
			//System.out.println(hist.length);
			
			int max = 0;
			for(int i=0; i<hist.length; i++) {
				if(hist[i] > max) {
					max = hist[i];
				}				
				
			}
			for(int i=0; i<hist.length; i++) {
				hist[i] = (int)(hist[i]/(float)max * 250);
				/*System.out.print(hist[i] + "\t");
				if(i%10 == 0) {
					System.out.println();
				}*/
			}		
			//histCanvas.setHistPix(hist);
			//histCanvas.repaint();
			
			Graphics g = histCanvas.getGraphics();
			Color c = g.getColor();
			g.setColor(Color.red);
			g.drawLine(10, H_HEIGHT-10, H_WIDTH-30, H_HEIGHT-10);
			g.drawLine(H_WIDTH-35, H_HEIGHT-15, H_WIDTH-30, H_HEIGHT-10);
			g.drawLine(H_WIDTH-35, H_HEIGHT-5, H_WIDTH-30, H_HEIGHT-10);
			g.drawString("灰度级", H_WIDTH-80, H_HEIGHT);
			g.drawLine(10,  H_HEIGHT-10, 10, 10);
			g.drawLine(5, 15, 10, 10);
			g.drawLine(15, 15, 10, 10);
			g.drawString("像素个数", 15, 15);
			g.setColor(Color.black);
			for(int i=0; i<hist.length; i++) {
				g.drawLine(10+i, H_HEIGHT-10, 10+i, H_HEIGHT-10-hist[i]);
				if(i%30 == 0) {
					g.drawString(i+"", 10+i, H_HEIGHT);
				}
			}
			g.setColor(c);
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	
	public void threshold(int threshold) {
		try {
			BufferedImage bfImg = ImageIO.read(new File(imgSrc));
			int w = bfImg.getWidth();
			int h = bfImg.getHeight();
			int pix[] = new int[w*h];
			
			int imgType = bfImg.getType();
			bfImg.getRGB(0, 0, w, h, pix, 0, w);
			int max = 0;
			ColorModel cm = ColorModel.getRGBdefault();
			for(int i=0; i<pix.length; i++) {
				if(cm.getRed(pix[i]) <= threshold) {
					pix[i] = new Color(255,255,255).getRGB();					
				} else {
					pix[i] = new Color(0, 0, 0).getRGB();
				}				
			}			
			bfImg.setRGB(0, 0, w, h, pix, 0, w);
				
			//histCanvas.setHistPix(hist);
			//histCanvas.repaint();
			
			Graphics g = histCanvas.getGraphics();
			g.clearRect(0, 0, H_WIDTH, H_HEIGHT);
			Color c = g.getColor();
			g.drawImage(bfImg, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, this);
			g.setColor(c);
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	
	/**
	 * 事件监听响应
	 */
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == openFile) {
			FileDialog openFileDialog = new FileDialog(this, "打开图片");
			openFileDialog.setMode(FileDialog.LOAD);	//设置此对话框为从文件加载内容
			openFileDialog.setFile("*.jpg;*.jpeg;*.gif;*.png;*.bmp;*.tif;");		//设置可打开文件的类型为:.txt,.java
			
			openFileDialog.setVisible(true);
			String fileName = openFileDialog.getFile();
			String directory = openFileDialog.getDirectory();
			if(null != fileName) {
				imgSrc = directory + fileName;
				img = Toolkit.getDefaultToolkit().getImage(imgSrc);	
				histCanvas.repaint();
			} else {
				JOptionPane.showMessageDialog(this, "您已经取消选择了,请重新选择!");
			}
		} else if(e.getSource() == histogram) {
			System.out.println(new Date());
			drawHistogram();
			System.out.println(new Date());
		} else if(e.getSource() == threshold) {
			threshold(65);
		}
	}
	/**
	 * 滑动条滑动响应事件
	 */
	public void stateChanged(ChangeEvent e) {
		if(e.getSource() == jsliderH) {
			float valueH = jsliderH.getValue();
			imgW = (int)(2*PWIDTH*(valueH/JS_MAXIMUM));	
			if(imgW < PWIDTH/4) {
				imgW = PWIDTH/4;
			}
			dx1 = xcentre-imgW/2;
			dy1 = ycentre-imgH/2;
			dx2 = xcentre + imgW/2;
			dy2 = ycentre + imgH/2;
			canvas.repaint();
		} else if(e.getSource() == jsliderV) {
			float valueV = jsliderV.getValue();
			imgH = (int)(2*PHEIGHT*(valueV/JS_MAXIMUM));
			if(imgH < PHEIGHT/4) {
				imgH = PHEIGHT/4;
			}
			dx1 = xcentre-imgW/2;
			dy1 = ycentre-imgH/2;
			dx2 = xcentre + imgW/2;
			dy2 = ycentre + imgH/2;
			canvas.repaint();
		}
	}
	
	public static void main(String[] args) {
		new Histogram();
	}
	
	/**
	 * 用于画图像的Canvas
	 */
	class MyCanvas extends Canvas {		
		public MyCanvas() {
			
		}
		public void paint(Graphics g) {
			Graphics2D g2 = (Graphics2D) g;
			//g.drawImage(img, xcentre-imgW/2, ycentre-imgH/2, imgW, imgH, this);
			sx2  = img.getWidth(this);
			sy2  = img.getHeight(this);
			g2.shear(shx, shy);
			g2.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, this);//Color.green, 
		}
	}
			
}

/*class HistCanvas extends Canvas {
int histPix[] = new int[0];
public void setHistPix(int[] pix) {
	histPix = pix;
}
public void paint(Graphics g) {
	Color c = g.getColor();
	g.setColor(Color.red);
	g.drawLine(10, H_HEIGHT-10, H_WIDTH-30, H_HEIGHT-10);
	g.drawLine(H_WIDTH-35, H_HEIGHT-15, H_WIDTH-30, H_HEIGHT-10);
	g.drawLine(H_WIDTH-35, H_HEIGHT-5, H_WIDTH-30, H_HEIGHT-10);
	g.drawString("灰度级", H_WIDTH-80, H_HEIGHT);
	g.drawLine(10,  H_HEIGHT-10, 10, 10);
	g.drawLine(5, 15, 10, 10);
	g.drawLine(15, 15, 10, 10);
	g.drawString("像素个数", 15, 15);
	g.setColor(Color.black);
	for(int i=0; i<histPix.length; i++) {
		g.drawLine(10+i, H_HEIGHT-10, 10+i, H_HEIGHT-10-histPix[i]);
		if(i%30 == 0) {
			g.drawString(i+"", 10+i, H_HEIGHT);
		}
	}
	g.setColor(c);
}
}*/





【上篇】
【下篇】

抱歉!评论已关闭.