`

灰度直方图

阅读更多

图像的统计特性

图像的基本统计分析量如下:
1.熵

一个 X 值域为{x1, ..., xn}的随机变量的熵值 H 定义为:H(X)  =  \operatorname{E}(I(X))即熵的公式可以表示为:H(X) = \sum_{i=1}^n {p(x_i)\,I(x_i)} = -\sum_{i=1}^n {p(x_i) \log_b p(x_i)}

上式我们取集合X为图像灰度值构成的集合,这样我们就可以得到图像灰度的熵值


2.灰度平均值,灰度中值已经灰度方差都能很容易得到

3.直方图的计算


我们来看一个灰度图像,让n_i表示灰度i出现的次数,这样图像中灰度为i 的像素的出现概率是

p_x(i) = \frac{n_i}{n}, i\in {0,..., L - 1}

L 是图像中所有不同的灰度值,n 是图像中所有的像素数, p 实际上是图像的直方图,归一化到 0..1


4.图像的质量评价标准(其实就是误差估计)


在编写程序之前,我们应该了解图片格式以及相应文件数据结构,java语言默认支持jpg,png和gif三种图片格式(没有考证),如果我们要处理bmp图片格式的,我们必须对bmp图片解码提取出图片的特征以及每个像素的数据,然后在java类库的方法表示出图像,才能进行进一步的处理,换句话说就是将图片(这里指bmp)内存储像素转换到java语言的存储图片的像素。下面附上java语言读取转换bmp图片的程序

 

 

//BMPReader.java, from Mark Wutka
//Revised by Xie-Hua Sun


import java.awt.*;
import java.io.*;
import java.awt.image.*;

/**
 *This class provides a public static method that takes an InputStream to a Windows
 * .bmp file and converts it into an ImageProducer via a MemoryImageSource.
 *You can fetch a .bmp throough a URL with the following code:
 *URL url = new URL(<wherever your URL is>)
 *Image img= createImage(BMPReader.getBMPImage(url.openStream()));
 */
public class BMPReader extends Object 
{  
    //Constants indication how the data is stored
    public static final int BI_RGB  = 0;
    public static final int BI_RLE8 = 1;
    public static final int BI_RLE4 = 2;
  
    public static MemoryImageSource getBMPImage(FileInputStream stream) throws IOException
    {  	
	  	//DataInputStream allows you to read in 16 and 32 bit numbers
	  	DataInputStream in=new DataInputStream(stream);
	  	
	  	//Verify that the header starts with 'BM'
	  	if(in.read() != 'B')
	  	  throw new IOException("Not a .BMP file!");  	  
	  		  	
	  	if(in.read() != 'M')
	  	  throw new IOException("Not a .BMP file!");  	  
	  		  	
	  	//Get the total file size
	  	int fileSize = intelInt(in.readInt());
	  	
	  	//Skip the 2 16-bit reserved words
	  	in.readUnsignedShort();
	  	in.readUnsignedShort();
	  	
	  	int bitmapOffset = intelInt(in.readInt());
	  	
	  	int bitmapInfoSize = intelInt(in.readInt());
	  	
	  	int width  = intelInt(in.readInt());
	  	int height = intelInt(in.readInt());
	  	
	  	//Skip the 16-bit bitplane size
	  	in.readUnsignedShort();
	  	
	  	int bitCount = intelShort(in.readUnsignedShort());
	  	
	  	int compressionType = intelInt(in.readInt());
	  	
	  	int imageSize = intelInt(in.readInt());
	    
	    //Skip pixels per meter
	    in.readInt();
	    in.readInt();
	    
	    int colorsUsed      = intelInt(in.readInt());
	    int colorsImportant = intelInt(in.readInt());
	    if(colorsUsed == 0) colorsUsed = 1<<bitCount;
	    
	    int colorTable[] = new int[colorsUsed];
	    
	    //Read the bitmap's color table
	    for(int i = 0; i < colorsUsed; i++)
	        colorTable[i] = (intelInt(in.readInt())&0xffffff)+0xff000000;
	    	    
	    //Create space for the pixels
	  	int pixels[] = new int[width*height];
	  	//Read the pixels from the stream based on the compression type
	  	if(compressionType == BI_RGB)
	  	    if(bitCount == 24)
	  	  	    readRGB24(width,height,pixels,in);
	  	    else
	  	  	    readRGB(width,height,colorTable,bitCount,pixels,in);	  	    
	  	else if(compressionType == BI_RLE8)
	  	    readRLE(width,height,colorTable,bitCount,pixels,in,imageSize,8);	
	  	else if(compressionType == BI_RLE4)
	  	    readRLE(width,height,colorTable,bitCount,pixels,in,imageSize,4);	
	  		  	
	  	//Create a memory image source from the pixels
	  	System.out.println(pixels[0]+" "+pixels[1]+" "+pixels[pixels.length-2]);
	  	return new MemoryImageSource(width,height,pixels,0,width);
	}
  
    /*
     *Reads in pixels in 24-bit format. There is no color table, and the pixels are
     *stored in 3-byte pairs. Oddly, all windows bitmaps are stored upside - the 
     *bottom line is stored first.
     **/
    protected static void readRGB24(int width,int height,int pixels[],
                                    DataInputStream in) throws IOException
    {  	
	  	//start storing at the bottom of the array
	  	for(int h = height-1; h >= 0; h--)
	  	{
	  	    int pos = h*width;
	  	    for(int w = 0; w < width; w++)
	  	    {
		  	  	//Read in the red, green and blue components
		  	  	int red   = in.read();
		  	  	int green = in.read();
		  	  	int blue  = in.read();
		  	  	//Turn the red,green and blue values into an RGB color with an alpha value
		  	  	//of 255 (fully opaque)
		  	  	pixels[pos++] = 0xff000000+(red<<16)+(green<<8)+blue;
	  	    }
	  	}
    }
  
    //readRGB reads in pixels values that are stored uncompressed. The bits represent 
    //indices into the color table
    protected static void readRGB(int width,int height,int colorTable[], int bitCount, 
                                  int pixels[], DataInputStream in) throws IOException
    {  	
	  	//How many pixels can be stored in a byte?
	  	int pixelsPerByte = 8/bitCount;
	  	
	  	//A bit mask containing the number of bits in a pixel
	  	int bitMask = (1<<bitCount)-1;
	  	
	  	//The shift values that will move each pixel to the far right
	  	int bitShifts[] = new int[pixelsPerByte];
	  	
	  	for(int i = 0; i < pixelsPerByte; i++)
	  	    bitShifts[i] = 8-((i+1)*bitCount);  	    
  	
	  	int whichBit = 0;
	  	
	  	//Read in the first byte
	  	int currByte = in.read();
	  	
	  	//Start at the bottom of the pixel array and work up
	  	for(int h = height-1;h >= 0; h--)
	  	{
	  	    int pos = h*width;
	  	    for(int w = 0; w < width; w++)
	  	    {	  	  	
		  	  	//Get the next pixel from the current byte
		  	  	pixels[pos] = colorTable[(currByte>>bitShifts[whichBit])&bitMask];
		  	  	pos++;
		  	  	whichBit++;
		  	  	
		  	  	//If the current bit position is past the number of pixels in
		  	  	//a byte, you advance to the next byte
		  	  	if(whichBit >= pixelsPerByte)
		  	  	{
		  	  	    whichBit = 0;
		  	  	    currByte = in.read();
		  	  	}
	  	    }
	  	}
    }
  
    //readRLE reads run-length encoded data in either RLE4 or RLE8 format
    protected static void readRLE(int width,int height,int colorTable[],
                                int bitCount,int pixels[],DataInputStream in,
                                int imageSize,int pixelSize) throws IOException
    {
	  	int x = 0;
	  	int y = height-1;
	  	
	  	//You already know how many bytes are in the image, so only go through that many
	  	for(int i = 0; i < imageSize; i++)
	  	{
	  	    //RLE encoding is defined by two bytes	
	  	    int byte1 = in.read();
	  	    int byte2 = in.read();
	  	    i += 2;
	  	  
	  	    //If byte0==0, this is an escape code
	  	    if(byte1 == 0)
	  	    {
	  	  	    //If escaped, byte2==0 means you are at end of line
	  	  	    if(byte2 == 0)
	  	  	    {
	  	  	        x = 0; y--;
	  	  	        //If escaped, byte2==1 means end of bitmap
	  	  	    }
	  	  	    else if(byte2 == 1)
	  	  	    {
	  	  	        return;
	  	  	        //if escaped, byte2==2 adjusts the current x and y by
	  	  	        //an offset stored in the next two words
	  	  	    }
		  	  	else if(byte2 == 2)
		  	  	{
		  	  	    int xoff = (char)intelShort(in.readUnsignedShort());
		  	  	    i += 2;
		  	  	    int yoff = (char)intelShort(in.readUnsignedShort());
		  	  	    i += 2;
		  	  	    x += xoff;
		  	  	    y -= yoff;
		  	  	    //If escaped, any other value for byte 2 is the number of bytes
		  	  	    //that you should read as pixel values (these pixels are not 
		  	  	    //run-length encoded)
		  	  	}
		  	  	else
		  	  	{
		  	  	    int whichBit = 0;
		  	  	    //Read in the next byte
		  	  	    int currByte = in.read();
		  	  	    i++;
		  	  	    for(int j = 0; j < byte2; j++)
		  	  	    {
		  	  	  	    if(pixelSize == 4)
		  	  	  	    {
			  	  	  	    //The pixels are 4-bits,so half the time you shift the current byte
			  	  	  	    //to the right as the pixel value	
			  	  	  	    if(whichBit == 0){
			  	  	  	  	    pixels[y*width+x] = colorTable[(currByte>>4)&0xf];
			  	  	  	    }
			  	  	  	    else
			  	  	  	    {
			  	  	  	  	    //The rest of the time, you mask out the upper 4 bits, save the 
			  	  	  	  	    //pixel value, then read in the next byte
			  	  	  	  	    pixels[y*width+x] = colorTable[currByte&0xf];
			  	  	  	  	    currByte = in.read();
			  	  	  	  	    i++;
			  	  	  	    }
		  	  	  	    }
		  	  	  	    else
		  	  	  	    {
		  	  	  	        pixels[y*width+x] = colorTable[currByte];
		  	  	  	        currByte = in.read();
		  	  	  	        i++;
		  	  	  	    }
		  	  	  	    x++;
		  	  	  	    if(x >= width)
		  	  	  	    {
		  	  	  	        x = 0; y--;
		  	  	  	    }
		  	  	    }
	  	  	        //The pixels must be word-aligned, so if you read an unevel number of 
	  	  	        // bytes, read and ignore a byte to get aligned again
	  	  	        if((byte2&1) == 1)
	  	  	        {
	  	  	  	        in.read(); i++;
	  	  	        }
	  	        }
	  	        //If the first byte was not 0, it is the number of pixels that 
	  	        //are encoded by byte 2
	  	    }
	  	    else
	  	    {
		  	  	for(int j = 0;j < byte1; j++)
		  	  	{
		  	  	    if(pixelSize == 4)
		  	  	    {
		  	  	  	    //If j is odd, use the upper 4 bits
		  	  	  	    if((j&1) == 0)
		  	  	  	        pixels[y*width+x] = colorTable[(byte2>>4)&0xf];
		  	  	  	    else
		  	  	  	        pixels[y*width+x+1] = colorTable[byte2&0xf];		  	  	  	    
		  	  	    }
		  	  	    else
		  	  	  	    pixels[y*width+x+1] = colorTable[byte2];
		  	  	    
		  	  	    x++;
		  	  	    if(x >= width)
		  	  	    {
		  	  	  	    x = 0; y--;
		  	  	    }
		  	  	}
	  	    }
	    }
    }
  
    //intelShort converts a 16-bit number stored in intel byte order into
    //the local host format
    protected static int intelShort(int i)
    {
  	    return((i>>8)&0xff)+((i<<8)&0xff00);
    } 
  
    //intelInt converts a 32-bit number stored in intel byte order into
    //the local host format  转换成小端存储的机器整数
    protected static int intelInt(int i)
    {
  	    return((i&0xff)<<24)+((i&0xff00)<<8)+((i&0xff0000)>>8)+((i>>24)&0xff);
    }
}
  
  

 

 程序中提供了一个静态方法getBMPImage将bmp图片的数据转换生成MemoryImageSource对象,这样就可以用来构造java的Image对象。查看相应文档,同样可以编写出其他图片格式的读取程序。然后将getBMPImage返回的MemoryImageSource对象传给createImage函数就生成了一个Image(jpg,png,gif可以直接构造Image),下面就进行统计直方图的处理:1.将刚才得到的Image对象传给grabber函数得到对应的像素数组

 

public int[] grabber(Image im, int iw, int ih)
	{
		int [] pix = new int[iw * ih];
		try
		{
		    PixelGrabber pg = new PixelGrabber(im, 0, 0, iw,  ih, pix, 0, iw);
		    pg.grabPixels();
		    System.out.println(pix[0]+" "+pix[1]);
		}
		catch (InterruptedException e) 
		{
			e.printStackTrace();
		}	
		return pix;
	}

 2.根据1.中返回的像素数组统计不同灰度值的频率,如果对于一张本身就是灰度图像(8位灰度图像)来说,他的像素值就是它的灰度值(这就是我们程序采用的方法,也就是说我们处理的黑白图的灰度),如果是一张彩色图像,则它的灰度值需要经过函数映射来得到。灰度图像是由纯黑和纯白来过渡得到的,在黑色中加入白色就得到灰色,纯黑和纯白按不同的比例来混合就得到不同的灰度值。

public int[] getHist(int[] pix, int iw, int ih)
	{	
		int[] hist = new int[256];		
		for(int i = 0; i < iw*ih; i++) 
		{
			int grey = pix[i]&0xff;
			hist[grey]++;			
		}
		return hist;
	}

3.将灰度值频率显示出来

//显示直方图
    public void draw(Graphics g, int[] h, int max)
    {
    	g.clearRect(270, 0, 530, 350);    	
    	g.drawLine(270, 306, 525, 306); //x轴
    	g.drawLine(270, 50,  270, 306); //y轴
    	for(int i = 0; i < 256; i++)
    	    g.drawLine(270+i, 306, 270+i, 306-h[i]);
    	g.drawString(""+max, 275, 60);
       	g.drawString("直方图", 370, 320);
    }  

这是效果图:

其实灰度直方图反应了图片灰度值的一个分布情况,只是一个统计特性,并没有具体像素,但是我们可以从中得到图像的明亮程度,可以根据直方图知道我们照的照片的曝光程度,如果照片阴暗在低值的频率很大,过分曝光则在高灰度的频率很大。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 大小: 35.1 KB
1
5
分享到:
评论

相关推荐

    基于灰度直方图的图像检索

    "基于灰度直方图的图像检索"是一个使用VC++编程语言实现的小型软件,专门针对.bmp格式的图像进行操作。这个软件的核心在于利用灰度直方图作为图像特征,进行相似性比较,从而实现图像的检索。 首先,我们来理解灰度...

    灰度直方图分布测试

    在图像处理领域,灰度直方图是一种非常重要的分析工具,它可以帮助我们理解图像的亮度分布情况。"灰度直方图分布测试"是针对这种分析方法的一种代码实现,特别适合初学者进行学习和实践。下面我们将深入探讨灰度直方...

    图像灰度直方图

    图像灰度直方图是数字图像处理中的一个基础概念,它是一种统计图像中不同灰度级像素出现频率的图形表示。在单通道(通常为灰度图像)的情况下,直方图能够直观地揭示图像的整体亮度分布和局部特性,对理解和分析图像...

    灰度直方图寻找波峰

    在图像处理领域,灰度直方图是一种统计图像亮度分布的方法,它可以帮助我们理解图像的亮暗区域。在这个实验中,“灰度直方图寻找波峰”是利用Visual Studio 2010进行的一种实践,它引入了OpenCV库来辅助分析。OpenCV...

    MFC 图像处理之灰度直方图显示BMP图片(源码)

    该资源主要参考我的博客【数字图像处理】四.MFC对话框绘制灰度直方图,博客地址http://blog.csdn.net/eastmount/article/details/46237463 讲述VC++ 6.0关于数字图像处理的灰度直方图(中值灰度、平均灰度)、灰度、...

    用VC++显示图像的灰度直方图

    根据提供的信息,我们可以了解到这篇文章主要关注的是如何在VC++中实现图像灰度直方图的显示功能。在MATLAB环境中,实现这样的功能相对简单,但使用VC++则面临一定的技术挑战。下面将从不同的角度来解析这个过程中的...

    灰度直方图特征提取的Matlab实现

    灰度直方图特征提取,即从图像的灰度直方图中提取出有助于图像分析和理解的统计特征。这一技术广泛应用于医学图像处理,如文章提到的肝脏CT图像处理,也可以用于其他类型的图像分析,比如卫星图像分析、监控视频图像...

    基于灰度直方图的图片相似度判别

    本文将深入探讨如何使用C#语言通过灰度直方图的方法来实现图片相似度的判别。 首先,我们需要理解灰度直方图的概念。灰度直方图是表示图像亮度分布的一种统计图形,它将图像中的每个像素点按其灰度值(0到255之间)...

    MATLAB灰度直方图

    ### MATLAB灰度直方图详解 #### 一、引言 在图像处理领域,灰度直方图是一种非常重要的工具,它能够帮助我们了解图像中不同灰度级的分布情况,进而进行各种图像处理操作,如增强对比度、图像分割等。MATLAB作为一...

    matlab打开图像,显示灰度直方图及均值方差

    本教程将深入探讨如何使用MATLAB打开灰度图像,并展示其灰度直方图以及计算图像的均值和方差。这两个参数是衡量图像特性的重要指标,对理解和分析图像质量非常有帮助。 首先,让我们了解灰度图像。在彩色图像中,每...

    灰度化图像以及显示图像的灰度直方图

    在图像处理领域,灰度化图像和灰度直方图是两个重要的概念,它们对于理解和分析图像特性至关重要。本文将详细探讨这两个知识点及其在实际应用中的实现过程。 首先,我们来了解一下什么是“灰度化图像”。灰度图像,...

    Qt QImage+QCustomPlot实现图像灰度直方图

    在实现灰度直方图时,我们需要先用QImage加载图像文件。QImage提供了`load()`函数,可以方便地从指定路径加载图像。例如: ```cpp QImage image("path_to_image.jpg"); if (image.isNull()) { // 处理加载失败的...

    灰度直方图统计

    灰度直方图是图像处理领域的一个重要概念,它用于表示图像中各个灰度级的出现频率或像素数量。在MATLAB中,我们可以编写程序来计算和显示图像的灰度直方图,这对于理解图像的亮度分布、对比度以及图像特征具有重要...

    灰度直方图 源代码 C++

    在图像处理领域,灰度直方图是一种非常重要的概念,它用于描述图像中各个灰度级的分布情况。本文将详细讲解灰度直方图的原理、C++实现及其在图像处理中的应用。 首先,我们要理解什么是灰度直方图。在黑白图像或...

    huidutuzhifangtu_RGB空间直方图_灰度直方图_颜色直方图_

    在本主题中,我们将深入探讨“RGB空间直方图”、“灰度直方图”和“颜色直方图”这三种关键概念。 首先,让我们来看看“灰度直方图”。灰度直方图是针对单通道图像(如灰度图像)的统计表示,它将图像中的每个像素...

    做图像的灰度直方图

    先读入图片,对图片做灰度处理,对图像做分割,图像背景色填充,对需要处理的图片部分图像的灰度直方图

    图像的灰度直方图delphi源代码

    在图像处理领域,灰度直方图是一种非常重要的分析工具,它可以帮助我们理解图像的亮度分布情况。在Delphi编程环境中,我们可以编写源代码来实现这个功能。本篇将详细探讨Delphi处理图像并生成灰度直方图的原理、步骤...

    灰度直方图 MATLAB

    简单实用的MATLAB灰度直方图程序代码,统计图像中各个灰度的比例。

Global site tag (gtag.js) - Google Analytics