灰度直方图

图像的统计特性

图像的基本统计分析量如下:
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图片的程序

 

 

读取bmp代码   收藏代码
  1. //BMPReader.java, from Mark Wutka  
  2. //Revised by Xie-Hua Sun  
  3.   
  4.   
  5. import java.awt.*;  
  6. import java.io.*;  
  7. import java.awt.image.*;  
  8.   
  9. /**  
  10.  *This class provides a public static method that takes an InputStream to a Windows  
  11.  * .bmp file and converts it into an ImageProducer via a MemoryImageSource.  
  12.  *You can fetch a .bmp throough a URL with the following code:  
  13.  *URL url = new URL(<wherever your URL is>)  
  14.  *Image img= createImage(BMPReader.getBMPImage(url.openStream()));  
  15.  */  
  16. public class BMPReader extends Object   
  17. {    
  18.     //Constants indication how the data is stored  
  19.     public static final int BI_RGB  = 0;  
  20.     public static final int BI_RLE8 = 1;  
  21.     public static final int BI_RLE4 = 2;  
  22.     
  23.     public static MemoryImageSource getBMPImage(FileInputStream stream) throws IOException  
  24.     {     
  25.         //DataInputStream allows you to read in 16 and 32 bit numbers  
  26.         DataInputStream in=new DataInputStream(stream);  
  27.           
  28.         //Verify that the header starts with 'BM'  
  29.         if(in.read() != 'B')  
  30.           throw new IOException("Not a .BMP file!");        
  31.                   
  32.         if(in.read() != 'M')  
  33.           throw new IOException("Not a .BMP file!");        
  34.                   
  35.         //Get the total file size  
  36.         int fileSize = intelInt(in.readInt());  
  37.           
  38.         //Skip the 2 16-bit reserved words  
  39.         in.readUnsignedShort();  
  40.         in.readUnsignedShort();  
  41.           
  42.         int bitmapOffset = intelInt(in.readInt());  
  43.           
  44.         int bitmapInfoSize = intelInt(in.readInt());  
  45.           
  46.         int width  = intelInt(in.readInt());  
  47.         int height = intelInt(in.readInt());  
  48.           
  49.         //Skip the 16-bit bitplane size  
  50.         in.readUnsignedShort();  
  51.           
  52.         int bitCount = intelShort(in.readUnsignedShort());  
  53.           
  54.         int compressionType = intelInt(in.readInt());  
  55.           
  56.         int imageSize = intelInt(in.readInt());  
  57.           
  58.         //Skip pixels per meter  
  59.         in.readInt();  
  60.         in.readInt();  
  61.           
  62.         int colorsUsed      = intelInt(in.readInt());  
  63.         int colorsImportant = intelInt(in.readInt());  
  64.         if(colorsUsed == 0) colorsUsed = 1<<bitCount;  
  65.           
  66.         int colorTable[] = new int[colorsUsed];  
  67.           
  68.         //Read the bitmap's color table  
  69.         for(int i = 0; i < colorsUsed; i++)  
  70.             colorTable[i] = (intelInt(in.readInt())&0xffffff)+0xff000000;  
  71.                   
  72.         //Create space for the pixels  
  73.         int pixels[] = new int[width*height];  
  74.         //Read the pixels from the stream based on the compression type  
  75.         if(compressionType == BI_RGB)  
  76.             if(bitCount == 24)  
  77.                 readRGB24(width,height,pixels,in);  
  78.             else  
  79.                 readRGB(width,height,colorTable,bitCount,pixels,in);              
  80.         else if(compressionType == BI_RLE8)  
  81.             readRLE(width,height,colorTable,bitCount,pixels,in,imageSize,8);      
  82.         else if(compressionType == BI_RLE4)  
  83.             readRLE(width,height,colorTable,bitCount,pixels,in,imageSize,4);      
  84.                   
  85.         //Create a memory image source from the pixels  
  86.         System.out.println(pixels[0]+" "+pixels[1]+" "+pixels[pixels.length-2]);  
  87.         return new MemoryImageSource(width,height,pixels,0,width);  
  88.     }  
  89.     
  90.     /*  
  91.      *Reads in pixels in 24-bit format. There is no color table, and the pixels are  
  92.      *stored in 3-byte pairs. Oddly, all windows bitmaps are stored upside - the   
  93.      *bottom line is stored first.  
  94.      **/  
  95.     protected static void readRGB24(int width,int height,int pixels[],  
  96.                                     DataInputStream in) throws IOException  
  97.     {     
  98.         //start storing at the bottom of the array  
  99.         for(int h = height-1; h >= 0; h--)  
  100.         {  
  101.             int pos = h*width;  
  102.             for(int w = 0; w < width; w++)  
  103.             {  
  104.                 //Read in the red, green and blue components  
  105.                 int red   = in.read();  
  106.                 int green = in.read();  
  107.                 int blue  = in.read();  
  108.                 //Turn the red,green and blue values into an RGB color with an alpha value  
  109.                 //of 255 (fully opaque)  
  110.                 pixels[pos++] = 0xff000000+(red<<16)+(green<<8)+blue;  
  111.             }  
  112.         }  
  113.     }  
  114.     
  115.     //readRGB reads in pixels values that are stored uncompressed. The bits represent   
  116.     //indices into the color table  
  117.     protected static void readRGB(int width,int height,int colorTable[], int bitCount,   
  118.                                   int pixels[], DataInputStream in) throws IOException  
  119.     {     
  120.         //How many pixels can be stored in a byte?  
  121.         int pixelsPerByte = 8/bitCount;  
  122.           
  123.         //A bit mask containing the number of bits in a pixel  
  124.         int bitMask = (1<<bitCount)-1;  
  125.           
  126.         //The shift values that will move each pixel to the far right  
  127.         int bitShifts[] = new int[pixelsPerByte];  
  128.           
  129.         for(int i = 0; i < pixelsPerByte; i++)  
  130.             bitShifts[i] = 8-((i+1)*bitCount);            
  131.       
  132.         int whichBit = 0;  
  133.           
  134.         //Read in the first byte  
  135.         int currByte = in.read();  
  136.           
  137.         //Start at the bottom of the pixel array and work up  
  138.         for(int h = height-1;h >= 0; h--)  
  139.         {  
  140.             int pos = h*width;  
  141.             for(int w = 0; w < width; w++)  
  142.             {             
  143.                 //Get the next pixel from the current byte  
  144.                 pixels[pos] = colorTable[(currByte>>bitShifts[whichBit])&bitMask];  
  145.                 pos++;  
  146.                 whichBit++;  
  147.                   
  148.                 //If the current bit position is past the number of pixels in  
  149.                 //a byte, you advance to the next byte  
  150.                 if(whichBit >= pixelsPerByte)  
  151.                 {  
  152.                     whichBit = 0;  
  153.                     currByte = in.read();  
  154.                 }  
  155.             }  
  156.         }  
  157.     }  
  158.     
  159.     //readRLE reads run-length encoded data in either RLE4 or RLE8 format  
  160.     protected static void readRLE(int width,int height,int colorTable[],  
  161.                                 int bitCount,int pixels[],DataInputStream in,  
  162.                                 int imageSize,int pixelSize) throws IOException  
  163.     {  
  164.         int x = 0;  
  165.         int y = height-1;  
  166.           
  167.         //You already know how many bytes are in the image, so only go through that many  
  168.         for(int i = 0; i < imageSize; i++)  
  169.         {  
  170.             //RLE encoding is defined by two bytes    
  171.             int byte1 = in.read();  
  172.             int byte2 = in.read();  
  173.             i += 2;  
  174.             
  175.             //If byte0==0, this is an escape code  
  176.             if(byte1 == 0)  
  177.             {  
  178.                 //If escaped, byte2==0 means you are at end of line  
  179.                 if(byte2 == 0)  
  180.                 {  
  181.                     x = 0; y--;  
  182.                     //If escaped, byte2==1 means end of bitmap  
  183.                 }  
  184.                 else if(byte2 == 1)  
  185.                 {  
  186.                     return;  
  187.                     //if escaped, byte2==2 adjusts the current x and y by  
  188.                     //an offset stored in the next two words  
  189.                 }  
  190.                 else if(byte2 == 2)  
  191.                 {  
  192.                     int xoff = (char)intelShort(in.readUnsignedShort());  
  193.                     i += 2;  
  194.                     int yoff = (char)intelShort(in.readUnsignedShort());  
  195.                     i += 2;  
  196.                     x += xoff;  
  197.                     y -= yoff;  
  198.                     //If escaped, any other value for byte 2 is the number of bytes  
  199.                     //that you should read as pixel values (these pixels are not   
  200.                     //run-length encoded)  
  201.                 }  
  202.                 else  
  203.                 {  
  204.                     int whichBit = 0;  
  205.                     //Read in the next byte  
  206.                     int currByte = in.read();  
  207.                     i++;  
  208.                     for(int j = 0; j < byte2; j++)  
  209.                     {  
  210.                         if(pixelSize == 4)  
  211.                         {  
  212.                             //The pixels are 4-bits,so half the time you shift the current byte  
  213.                             //to the right as the pixel value     
  214.                             if(whichBit == 0){  
  215.                                 pixels[y*width+x] = colorTable[(currByte>>4)&0xf];  
  216.                             }  
  217.                             else  
  218.                             {  
  219.                                 //The rest of the time, you mask out the upper 4 bits, save the   
  220.                                 //pixel value, then read in the next byte  
  221.                                 pixels[y*width+x] = colorTable[currByte&0xf];  
  222.                                 currByte = in.read();  
  223.                                 i++;  
  224.                             }  
  225.                         }  
  226.                         else  
  227.                         {  
  228.                             pixels[y*width+x] = colorTable[currByte];  
  229.                             currByte = in.read();  
  230.                             i++;  
  231.                         }  
  232.                         x++;  
  233.                         if(x >= width)  
  234.                         {  
  235.                             x = 0; y--;  
  236.                         }  
  237.                     }  
  238.                     //The pixels must be word-aligned, so if you read an unevel number of   
  239.                     // bytes, read and ignore a byte to get aligned again  
  240.                     if((byte2&1) == 1)  
  241.                     {  
  242.                         in.read(); i++;  
  243.                     }  
  244.                 }  
  245.                 //If the first byte was not 0, it is the number of pixels that   
  246.                 //are encoded by byte 2  
  247.             }  
  248.             else  
  249.             {  
  250.                 for(int j = 0;j < byte1; j++)  
  251.                 {  
  252.                     if(pixelSize == 4)  
  253.                     {  
  254.                         //If j is odd, use the upper 4 bits  
  255.                         if((j&1) == 0)  
  256.                             pixels[y*width+x] = colorTable[(byte2>>4)&0xf];  
  257.                         else  
  258.                             pixels[y*width+x+1] = colorTable[byte2&0xf];                          
  259.                     }  
  260.                     else  
  261.                         pixels[y*width+x+1] = colorTable[byte2];  
  262.                       
  263.                     x++;  
  264.                     if(x >= width)  
  265.                     {  
  266.                         x = 0; y--;  
  267.                     }  
  268.                 }  
  269.             }  
  270.         }  
  271.     }  
  272.     
  273.     //intelShort converts a 16-bit number stored in intel byte order into  
  274.     //the local host format  
  275.     protected static int intelShort(int i)  
  276.     {  
  277.         return((i>>8)&0xff)+((i<<8)&0xff00);  
  278.     }   
  279.     
  280.     //intelInt converts a 32-bit number stored in intel byte order into  
  281.     //the local host format  转换成小端存储的机器整数  
  282.     protected static int intelInt(int i)  
  283.     {  
  284.         return((i&0xff)<<24)+((i&0xff00)<<8)+((i&0xff0000)>>8)+((i>>24)&0xff);  
  285.     }  
  286. }  
  287.     
  288.     

 

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

 

返回image的像素数组代码   收藏代码
  1. public int[] grabber(Image im, int iw, int ih)  
  2.     {  
  3.         int [] pix = new int[iw * ih];  
  4.         try  
  5.         {  
  6.             PixelGrabber pg = new PixelGrabber(im, 00, iw,  ih, pix, 0, iw);  
  7.             pg.grabPixels();  
  8.             System.out.println(pix[0]+" "+pix[1]);  
  9.         }  
  10.         catch (InterruptedException e)   
  11.         {  
  12.             e.printStackTrace();  
  13.         }     
  14.         return pix;  
  15.     }  

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

得到灰度频率数组代码   收藏代码
  1. public int[] getHist(int[] pix, int iw, int ih)  
  2.     {     
  3.         int[] hist = new int[256];        
  4.         for(int i = 0; i < iw*ih; i++)   
  5.         {  
  6.             int grey = pix[i]&0xff;  
  7.             hist[grey]++;             
  8.         }  
  9.         return hist;  
  10.     }  

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

显示直方图代码   收藏代码
  1. //显示直方图  
  2.     public void draw(Graphics g, int[] h, int max)  
  3.     {  
  4.         g.clearRect(2700530350);        
  5.         g.drawLine(270306525306); //x轴  
  6.         g.drawLine(27050,  270306); //y轴  
  7.         for(int i = 0; i < 256; i++)  
  8.             g.drawLine(270+i, 306270+i, 306-h[i]);  
  9.         g.drawString(""+max, 27560);  
  10.         g.drawString("直方图"370320);  
  11.     }    

这是效果图:

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


以下内容为补充内容


信息是一个随机变量,它是指某一信源发出某一消息所含有的信息量。所发出 的消息不同,它们所含有的信息量也就不同。任何一个消息的自信息量都代表不了 信源所包含的平均自信息量。不能作为整个信源的信息测度,因此定义自信息量的 
数学期望为信源的平均自信息量:
 
信息熵的意义:信源的信息熵H是从整个信源的统计特性来考虑的。它是从平均意 义上来表征信源的总体特性的。对于某特定的信源,其信息熵只有一个。不同的信 源因统计特性不同,其熵也不同。 
3.学习图像熵基本概念,能够求出图像一维熵和二维熵。 
图像熵是一种特征的统计形式,它反映了图像中平均信息量的多少。图像的一 维熵表示图像中灰度分布的聚集特征所包含的信息量,令P 
i 表示图像中灰度值为i的像素所占的比例,则定义灰度图像的一元灰度熵为: 

 
图像的一维熵可以表示图像灰度分布的聚集特征,却不能反映图像灰度分布的空间 特征,为了表征这种空间特征,可以在一维熵的基础上引入能够反映灰度分布空间 特征的特征量来组成图像的二维熵。选择图像的邻域灰度均值作为灰度分布的空间 
特征量,与图像的像素灰度组成特征二元组,记为( i, j ),其中i 表示像素的灰度值 (0 <= i <= 255),j 表示邻域灰度(0 <= j <= 255), 

上式能反应某像素位置上的灰度值与其周围像素灰度分布的综合特征,其中f(i, j) 为特征二元组(i, j)出现的频数,N 为图像的尺度,定义离散的图像二维熵为: 

构造的图像二维熵可以在图像所包含信息量的前提下,突出反映图像中像素位置的 灰度信息和像素邻域内灰度分布的综合特征

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值