数字图像点运算实践,图像直方图变换和几何变

2020-03-02 10:47 来源:未知

图像直方图(英语:Image Histogram)是用以表示数字图像中亮度分布的直方图,标绘了图像中每个亮度值的像素数。可以借助观察该直方图了解需要如何调整亮度分布。这种直方图中,横坐标的左侧为纯黑、较暗的区域,而右侧为较亮、纯白的区域。因此,一张较暗图片的图像直方图中的数据多集中于左侧和中间部分;而整体明亮、只有少量阴影的图像则相反。很多数码相机提供图像直方图功能,拍摄者可以通过观察图像直方图了解到当前图像是否过分曝光或者曝光不足。计算机视觉领域常借助图像直方图来实现图像的二值化.

灰度图像--图像增强 直方图均衡化(Histogram equalization)

转载请标明本文出处:

文章代码已托管,欢迎共同开发:

zsm 

  • 直方图变换
  • 灰度变换
  • 点运算
  • 几何变换

图像的直方图用来表征该图像像素值的分布情况。用一定数目的小区间来指定表征像素值的范围,每个小区间会得到落入该小区间表示范围的像素数目。

开篇废话

 

        废话开始,图像处理这些代码已经有三千多行了,不多,但是感觉多加练习以后对算法理解和写代码的能力上都有很大提高,毕竟对于算法来说想明白了一定要用一下才会真正掌握,但不能靠记忆去记住一个算法,这就需要我们懒人的天性,不愿意记住完整的公式,更愿意记住一个简单的起始,通过自己的理解和数学推导算法,这是个很不错的 方法,而写代码属于一种技术工作,熟能生巧,要多加练习,并且也要思考其中的技术细节,总之,做一切事情思考下还是不错的。

       废话完成,说说直方图均衡,在冈萨雷斯的书里面直方图均衡化在第三章提出,因为之前想按照书上目录上的顺序来写着一些列的博客,后来发现还是自己总结下的学习思路,按照自己理解的知识网络来走,所以刚要写直方图均衡的时候就是转向自己的节奏开始按照二值图像,灰度图像,彩色图像的知识结构介绍。

       直方图均衡的目的和前面灰度变换一样,为了增强对比度,使图像的灰度分布在整个灰度范围内更加均衡,其中直方图需要来解释下,直方图是个统计概念,比如我们有十种颜色的球,每种颜色的球有不同的数量,假设颜色分布为a0~a9,数量为n(x)(x取值为a0~a9)那么直方图就是以a0~a9为横坐标,n为纵坐标的统计直方图:

美高梅网投平台 1

       如果将上图中的数据归一化(每个分量除以球数总和),也就是使得各分量总和为1,各个分量就表示这种颜色的球出现的频率,就得到频率直方图。

       如果将各种颜色换成各灰度值,球的个数等效的换成具有该灰度的像素数量,或者换成该灰度出现的频率,就成了图像的直方图,对于彩色图像和灰度图像,直方图具有重要的统计意义,而对于二值图像来说,该意义不大,因为二值图像就两个灰度,所以其只能反映黑白面积比例。

       直方图均衡的目的是为了使灰度分布的更广泛,从而来拉伸对比度:

美高梅网投平台 2

       事实表明当灰度的直方图范围从上面的左边变换成右边后,图像对比度得到提升,也就达到了我们增强图像的目的--更便于观察,更容易区分不同灰度间细节。

 

摘要


图像直方图图形化显示不同的像素值在不同的强度值上的出现频率,对于灰度图像来说强度范围为[0~255]之间,对于RGB的彩色图像可以独立显示三种颜色的图像直方图。

数学原理

 

     直方图变换的最终操作和前面提到的灰度操作是一样的,即:

美高梅网投平台 3

      这是一种从灰度到灰度的映射,并且该映射与前面伽马变换对数变换的映射不同的是,它不具有确定的表达公式,而是根据原始图像的灰度分布不同而“自适应”的产生映射,并且必须具有以下两个性质:

  1. 该函数必须单调递增(因为要从s反射回r所以该函数必须是严格的单调递增,即r和s为一对一的关系)
  2. 美高梅网投平台,0<=r<=L-1时,必须满足0<=s<=L-1

      这是两点约束,即我们找到的T必须使得上面成立,而且还要达到均衡直方图的目的。即完成下面的转化:

美高梅网投平台 4

上面的是直方图的原始分布和目标分布,下面是响应的T。

推导过程:

       先提出一个概率密度函数pdf的概念,就是每个灰度值对应出现的概率,用p表示,pr(r)表示原始灰度r出现的概率,其计算是用灰度值为r的像素总个数除以图像的像素总个数。同理变换后的ps(s)表示变换后灰度为s的像素的概率。

  1. r到s是一对一的映射,所以若r0映射到s0那么pr(r0)=ps(s0)这个式子是因为像素个数不会改变,只是对应的灰度值改变了,这个就是我们接下来要用到的最基本的原理。
  2. 我们的目标灰度分布是均匀分布,也就是上图右上的概率分布图,因为绿色部分面积必然为1,所以,ps的目标分布为:                                          美高梅网投平台 5

根据上述的基本原理和假设存在:

美高梅网投平台 6

根据积分定理,w为积分假变量,那么:

美高梅网投平台 7

所以:

美高梅网投平台 8

将上面离散化:

美高梅网投平台 9

上面为大概的公式推导,如有不严谨之处还请指出。

所以我们将按照上面得出的结论进行编程:

美高梅网投平台 10

 

 

人类所获得的信息大约70%来自于图像,数字图像处理是计算机对采样量化的图像进行去除噪声、增强、复原、分割、提前特征等处理的方法和技术,它对一个物体的数字表示施加一系列的操作,以得到所期望的结果。这种技术在航空航天、生物医学、通信工程、军事、文化、电子商务等方面应用广泛。本实验根据课堂所学的关于数字图像点运算的知识实现对数字图像的灰度直方图均衡处理分段线性拉伸处理

直方图变换

1.灰度直方图

灰度直方图:数字图像中每一灰度级像素出现的频次(该灰度级的像素数目)(也可以标准化到概率的表示)

灰度直方图性质

  • 无空间信息。(一种值的统计,丢弃位置信息)
  • 直方图与图像一对多的关系
  • 可叠加性(全图=子图叠加)

直方图反映图像的清晰程度,直方图均匀分布时,图像最清晰。

判定一幅图像是否清晰,查看是否合理的利用了全部允许的灰度级。

一幅图像应该尽可能利用全部的灰度级

2.直方图均衡化

直方图修正:通过灰度映射函数$G_{new} = T(G_{old})$,将原灰度直方图改造成所希望的直方图。

直方图均衡化是一种最常用的直方图修正,把直方图分布改造成均匀直方图分布,均衡化后,图像直方图是平直的,即各灰度级出现频数相同,图像看起来更清晰了。

直方图均衡化灰度映射函数

  • 连续灰度级情况:概率密度函数为P(r),0<= r <= 1,代表灰度级。

    变换函数s=T(r),使直方图变平直。

    要求:

    • [0,1]范围内,T(r)是单增函数,且T的值域为[0,1]
    • 反变换函数为单减函数,值域也为[0,1]。

    变换示意图:图1

    美高梅网投平台 11

    图片.png

变换函数T:图2

美高梅网投平台 12

图片.png

  • 数字图像的直方图均衡化:设总像素n个,分L个灰度级,第k个灰度级出现的概率P(Rk)=Nk/N,Nk表示第k个灰度级出现的频数。

    变换函数:连续变换函数离散化,概率求和。公式如下,图3

    美高梅网投平台 13

    图片.png

数字图像灰度直方图均衡化步骤(8个灰度级为例),如图4:

美高梅网投平台 14

图片.png

Matlab处理

  • i2 = histeq(i1),对i1直方图均衡化
  • imhist(i2) ,绘制i2的直方图
  • i2 = adapthisteq(i1),改进的直方图均衡化效果,针对空间信息做了改进。

具体情况:若原图各个灰度等级都存在,但分布不均,均衡化后虽然分布很平直,但是可能变换后的灰度等级缩小了,变换到了一个更小的灰度等级空间,此时可能效果并不好,所有具体情况要具体处理。如下图5

美高梅网投平台 15

图片.png

3.直方图规定化(直方图匹配)

修改一幅图像的直方图,使得它与另一幅图像的直方图匹配或具有一种预先规定的函数情况。

目标:突出感兴趣的灰度范围,改善图像质量。

场景:上一小节,我们将灰度分布不均的图像通过均衡化转换为灰度理论均匀(分布概率密度曲线平直)的图像,增强了图像效果,但是实际场景,我们可能要突出某一些部分,又或是我们发现灰度在靠近0和1的部分太暗或太亮会导致细节模糊甚至丢失,自然的我们想到类似于均衡变换,将不均的概率分布曲线转换成我们特定的预设的一种灰度分布上(如高斯分布),以实现我们需要的增强效果。

方法:1)直接通过f到g的映射,f为原函数,g为变换后的函数,但过程可能很复杂。2)通过均衡变换为中介,将原图灰度分布f1和预设的直方图分布f2都做一个变换到均衡分布,分布使用映射函数s和t,那么对原图做s变换,再做t的反变换就得到了f2的分布。过程简单。

步骤如图6所示:

美高梅网投平台 16

图片.png

预设分布:规定化的效果较好,但是前提是需要知道图像的变换的较好的预设分布,这里需要根据具体情况分析,比如根据图中的场景,能分析该图主要应该呈现两种色调,那么对预设的分布,我们可以给出一种“双峰”的灰度分布,那么处理后的图像就会趋于呈现两种色调。

特例:二值图,双峰分布图中间添加阈值。


美高梅网投平台 17直方图演示.png

代码

 

[cpp] view plain copy

 

 美高梅网投平台 18美高梅网投平台 19

  1. /******************************************************************************************** 
  2.  直方图基本操作 
  3.  *******************************************************************************************/  
  4. void InitMappingTable(void * arry,int size,int Data_type){  
  5.     if(Data_type==TABLE_INT)  
  6.         for(int i=0;i<size;i )  
  7.             ((int*)arry)[i]=0;  
  8.     else if(Data_type==TABLE_CHAR)  
  9.         for(int i=0;i<size;i )  
  10.             ((char*)arry)[i]=0;  
  11.     else if(Data_type==TABLE_DOUBLE)  
  12.         for(int i=0;i<size;i )  
  13.             ((double*)arry)[i]=0;  
  14.       
  15. }  
  16. void InitHistogram(int *hist){  
  17.     for(int i=0;i<GRAY_LEVEL;i )  
  18.         hist[i]=0;  
  19. }  
  20.   
  21. void setHistogram(double *src,int *hist,int width,int height){  
  22.     InitHistogram(hist);  
  23.     for(int j=0;j<height;j )  
  24.         for(int i=0;i<width;i ){  
  25.             int tempv=src[j*width i];  
  26.             hist[tempv] ;  
  27.         }  
  28. }  
  29. int findHistogramMax(int *hist){  
  30.     for(int i=GRAY_LEVEL-1;i>=0;i--){  
  31.         if(hist[i]!=0)  
  32.             return i;  
  33.     }  
  34.     return -1;  
  35.   
  36. }  
  37. int findHistogramMin(int *hist){  
  38.     for(int i=0;i<GRAY_LEVEL;i ){  
  39.         if(hist[i]!=0)  
  40.             return i;  
  41.     }  
  42.     return -1;  
  43. }  
  44. void fillMaptable(double * map){  
  45.       
  46.     for(int i=1;i<GRAY_LEVEL;i ){  
  47.         if(map[i]==0)  
  48.             map[i]=map[i-1];  
  49.       
  50.     }  
  51.   
  52. }  
  53. /******************************************************************************************** 
  54.  直方图均衡 
  55.  *******************************************************************************************/  
  56. //均衡直方图,将原图直方图,经过公式得到目标直方图  
  57. void EqualizationHist(int *src_hist,double *dst_map){  
  58.     int temphist[GRAY_LEVEL];  
  59.     InitHistogram(temphist);  
  60.     int max=findHistogramMax(src_hist);  
  61.     int min=findHistogramMin(src_hist);  
  62.     temphist[min]=src_hist[min];  
  63.     for(int i=min 1;i<=max;i )  
  64.         temphist[i]=temphist[i-1] src_hist[i];  
  65.     for(int i=min;i<=max;i )  
  66.         temphist[i]-=temphist[min];  
  67.     int total=temphist[max];  
  68.     for(int i=min;i<=max;i ){  
  69.         dst_map[i]=((double)GRAY_LEVEL-1.0)*temphist[i]/total;  
  70.     }  
  71.       
  72. }  
  73. //直方图均很,用输入图像得到输出图像  
  74. void HistogramEqualization(double *src,double *dst,int width,int height){  
  75.     int hist[GRAY_LEVEL];  
  76.     setHistogram(src, hist, width, height);  
  77.     double GrayMappingTable[GRAY_LEVEL];  
  78.     InitMappingTable(GrayMappingTable,GRAY_LEVEL,TABLE_DOUBLE);  
  79.     EqualizationHist(hist, GrayMappingTable);  
  80.     for(int i=0;i<width;i )  
  81.         for(int j=0;j<height;j )  
  82.             dst[j*width i]=GrayMappingTable[(int)src[j*width i]];  
  83.       
  84. }  

 

 

灰度变换

场景:曝光不足或过度等原因,产生对比度不足,使图像细节分辨不清。

方法:使用灰度变换方法解决这些问题。

对比度:简单讲就是最白与最黑的亮度单位的相除值,体现的是灰度级的max和min的极差。

灰度级变换:空间域点运算,通过某个变换函数有:g(x,y)=T(f(x,y)),T即为变换函数。也可以写作R = T(r)

1.线性灰度变换

变换函数T为线性函数。

  • 加常数:会缩小动态范围,降低对比度,调节整体亮度,可能会损失某一部分灰度等级。如下图所示,图7

    美高梅网投平台 20

    图片.png

(特例)图像反转:g(x,y)=255-f(x,y),简单理解为"黑白颠倒".

  • 乘常数:g(x,y)=Cf(x,y).改变动态范围。

  • 分段线性变换:变换函数采用分段的线性函数,突出感兴趣的部分。

    (特例)削波,cliping。

    (特例)阈值化,thresholding。二值图。

    (特例)灰度窗口变换,将某一区间的灰度级和其他部分(背景)分开。

非线性灰度变换

  • 对数变化,低灰度区扩展,高灰度区压缩
  • 之所变化,高灰度区扩展,低灰度区抑制。
  • 幂函数。
  • LUT变换,Look Up Table,查找表。一种映射表。

Matlab处理

  • bc = imcomplement(b),图像反转
  • th = imadjust(t,[],[],0.5),用于进行图像的灰度变换

 final Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.test_hist2); image0.setImageBitmap; CV4JImage cv4jImage = new CV4JImage; image1.setImageBitmap(drawHist(cv4jImage.getProcessor(),new Paint;

结果

 

原图:

美高梅网投平台 21

原图直方图:

美高梅网投平台 22

直方图均衡后图片:

美高梅网投平台 23

直方图均衡后直方图:

美高梅网投平台 24

 

关键词

图像运算

1.算术运算:加减乘除

  • 加法:C(x,y)=A(x,y) B(x,y)。去除“叠加性”噪音;生成图像叠加效果。
  • 减法:与加法类似。
  • 乘法:C(x,y)=A(x,y)*B(x,y)。局部显示;二值蒙版图像与原图像做乘法。
  • 除法:不常用

2.逻辑运算:与或非

3.比较运算:如,取平均,最大,最小


drawHist()用于展示图像的直方图,并把它转换成bitmap。

总结

 

        上面给出的结果为经典结果,很多文章都使用的这幅图片,值得解释的是,虽然我们从r到s的映射是一对一的,但r和s是离散的整数,如果s被映射到非整数,将就近取整,所以有些灰度值会被合并。

        直方图运算速度快,效果好,应用范围很广,故总结如上。

        待续。。。

 

 

 

 

 

直方图均衡化算法实现

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。

数字图像  点运算  灰度直方图  直方图均衡  分段线性拉伸

图像几何变换

几何失真分为系统失真和非系统失真,系统失真是有规律的、能预测的,非系统失真则是随机的。

  • 镜头畸变
  • 遥感图像矫正:飞行器和地球相对运动造成呈现扫描不规整。
  • 图像配准:工业生产、医院中装置定位。

几何变换是图像中物体的空间变换,可以看成是图像内各物体在图像内移动的过程,如转动、扭曲、倾斜、拉伸。

1.基本几何变换的定义

原图为f(x,y),变换为,x'=T1(x,y),y'=T2(x,y),几何变换仅对x,y坐标做变换,灰度值不变。(注意:这里的变换不简单为单个变量的变换,如x'的变换实际上同时涉及变量x和y)

目标图像为g(x,y)=f(T1(x,y),T2(x,y))

2.常用的几何变换

  • 平移变换。g(x,y)=f(x tx,y ty),原图平移向量为(tx,ty)。(这里需要注意计算机呈像中的坐标选取,是左上角为坐标原点的,理论研究中采用常用的数学坐标)。写做矩阵形式为,图8

    美高梅网投平台 25

    图片.png

  • 镜像:水平镜像和垂直镜像

    • 水平镜像:沿Y轴翻转。g(x,y)=f(width-x,y),矩阵形式为图9

      美高梅网投平台 26

      图片.png

    • 垂直镜像:沿x轴翻转。g(x,y)=f(x,heigh-y),矩阵形式为图10

      美高梅网投平台 27

      图片.png

  • 转置:x,y坐标对换。与旋转是不同的,事实上,转置后的图与旋转90度后的图是水平镜像关系。矩阵表示如图11

    美高梅网投平台 28

    图片.png

  • 旋转变换:绕原点旋转a度,(注:逆时针为正向角度)。旋转后画布变大,图像增大。数学关系用极坐标表示较为方便。如图12

    美高梅网投平台 29

    图片.png

    通常的做法,是以图像中心做旋转,方法:

    • 图像中心平移到原点
    • 顺时针以原点做旋转
    • 图像中心平移回原坐标

    以上三个变换可以写成三种变换的矩阵相乘的形式,就可以一步到位。

    问题:旋转中会出现锯齿、网纹、断裂。

    • 像素的方向是固定的,纵横。旋转的时候并不会按某一个旋转角度分布像素,这样旋转后像素点就会有交错,不规整,错位。像素排列不完全按照原有的相邻关系。
    • 计算过程中,xy的映射涉及到三角函数,会进行浮点数取整,最终造成某些点空洞(没有取值),漏点

    问题的本质都是应为像素值填充不是连续的

    解决办法:插值填充

  • 缩放变换:缩小的时候要满足采样定理,否则会发生信息丢失;放大的时候需要对空位填入适当的新值,是信息的估计。矩阵表示如下图13.

    美高梅网投平台 30

    图片.png

  • 拉伸变换:混合的几何变换,或者说是几何变换的一般形式。如下图14

    美高梅网投平台 31

    图片.png

3.灰度级差值

解决的问题:旋转中出现的漏点、放大中新增的空点、拉伸中的空点,都存在未知像素值的点。

解决方法:插值法,利用邻域的像素来估计新的像素值。

a)最邻近插值:重复最临近点,取最近点的像素值。简单,但效果一般,放大倍数太大时会出现马赛克现象。

b)双线性插值:根据该空点上下左右4个点进行两次插值。f(x,y)=ax by cxy d。(xy两个方向上都取线性变换值)

c)三次立方插值(立方卷积插值):差值函数为S(x)(是一个拟合的正弦差值函数,sinx/x,这是信息论中已知的优秀的差值算法,认为图像中的任何两个连续点的灰度值不是线性变换,而是一种sinx/x的函数,故采用拟合该函数的一个立方差值函数来代替计算),如下图15

美高梅网投平台 32

图片.png

待求像素的灰度值由周围16个点的灰度值加权内插得到,计算量大,效果较好。矩阵表示为图16

美高梅网投平台 33

图片.png


 private Bitmap drawHist(ImageProcessor imageProcessor, Paint paint) { CalcHistogram calcHistogram = new CalcHistogram(); int bins = 127; int[][] hist = new int[imageProcessor.getChannels()][bins]; calcHistogram.calcHist(imageProcessor,bins,hist,true); Bitmap bm = Bitmap.createBitmap(imageProcessor.getWidth(),imageProcessor.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas; paint.setColor(Color.BLACK); paint.setStyle(Paint.Style.FILL_AND_STROKE); canvas.drawRect(0,0,imageProcessor.getWidth(),imageProcessor.getHeight; float step = imageProcessor.getWidth()/127; int xoffset; int yoffset; int channels = imageProcessor.getChannels(); int h = imageProcessor.getHeight(); int[] colors = new int[]{Color.argb(77,255,0,0),Color.argb(77,0,255,0),Color.argb(77,0,0,255)}; for (int i=0;i<channels;i  ) { paint.setColor(colors[i]); for (int j=0;j<bins;j  ) { xoffset = ; yoffset = hist[i][j]*h/255; canvas.drawRect(xoffset,h-yoffset,xoffset step,h,paint); } } return bm; }

直方图

直方图(histogram)是灰度级的函数,它表示图像中具有每种灰度级的像素的个数,

反映原图中各种灰度值分布的情况。

如下图所示,灰度直方图的横坐标是灰度级,纵坐标是该灰度级出现的频率,是图像的最基本的统计特征。

 

上面的是标准直方图

灰度统计累计直方图:

                  H(k)= ∑ni(i<=k)

 

累积直方图中第k列的高度是图像中所有灰度值<=k的像素的个数

一、 任务说明

用Java编程语言实现一个带GUI的数字图像处理程序,实现读出数字图像并进行灰度直方图均衡处理和分段线性拉伸处理的功能。

需要注意的是,在本程序中,对于分段线性拉伸处理,程序中会先根据源图像的灰度直方图找出集中分布区间(像素个数之和占图像总像素个数85%以上的区间中长度最短的区间),然后让用户输入一个要拉伸到的区间,再进行分段线性拉伸。拉伸前后灰度范围都默认为 [0,255]。

实践任务

Matlab和Python分别实现下列任务

  • 加载图像
  • 预备任务:彩色图像到灰度图像的变换(因为之后的学习大多处理灰度图,所有需要将彩色图变换到灰度图)
  • 实践1:灰度图及其灰度直方图,和均衡化后的图及其直方图,4个subplot做对比呈现
  • 实践2:灰度图按高斯分布和双峰分布做直方图匹配,给出4个subplot对比呈现
  • 实践3:图像旋转,及插值处理。
  • 实践4:图像高倍放大,及插值算法处理比较。

如果对CalcHistogram感兴趣,可以查看cv4j的具体实现。

灰度直方图的求取算法实现

1
2
3
4
5
6
7
8
9
10
11
12
void GetHistogram(BYTE *image_Src, int width, int height, unsigned long *histogram)
{
    int pixelCount = width*height;//imageSize->pixelCount
    memset(histogram, 0, 256*4);//注意最后一个参数是数组的大小(单位是字节)
    for (int i = 0; i <= pixelCount - 1;  i)
    {
        int gray = image_Src[0];
        histogram[gray] ;
        //下一个像素
        image_Src =1;
    }
}

 

二、 算法原理

(一)直方图均衡

1、            背景意义

直方图反映的是一幅图像的灰度级与出现这种灰度级概率之间关系的图形。直方图均衡的目的是使所有灰度级出现的相对概率相同,此时图像的熵最大,图像包含的信息最大。经过直方图均衡处理后,图像的对比度会增强,特别是对于背景或前景都太亮或太暗的图像非常有用。例如,其可以带来X光图像中更好的骨骼结构显示以及曝光过度或者曝光不足照片中更好的细节。

直方图均衡的主要优势是它是一个相当直观的技术并且是可逆操作,如果已知均衡化函数,那么就可以恢复原始的直方图,并且计算量也不大。这种方法的一个缺点是它对处理的数据不加选择,它可能会增加背景噪声的对比度并且降低有用信号的对比度。

 

2、            基本算法

若灰度级概率分布函数为 ,则此时直方图均衡的变换函数 s=T[r] 应该满足如下条件:

 

(a)       T[r]为单值单调递增函数

(b)       0<T[r]<1,保证变换后像素灰度级仍在允许范围内

由转换原理可求得

则原灰度值 r 经变换后对应的新灰度值为

 

3、            扩展算法

上述基本算法是对于灰度级连续的情况而言的,而在计算机中图像的灰度级是离散的,实际上与连续情况类似,我们可以得到离散情况下的变换函数:

假定离散情况下共有L个灰度级,第k个灰度级出现的像素个数为,图像的总像素个数为N,则第k个灰度级出现的概率为:

 

从而均衡化的变换函数为:

 

则原灰度值r对应的新灰度值为

因此通过转换原图像每个像素的灰度值就可实现直方图均衡处理。

 

(二)分段线性拉伸

1、            背景意义

一般成像系统只具有一定的亮度响应范围,亮度的最大值与最小值之比称为对比度。由于成像系统的限制,常常出现对比度不足的问题,使人眼观看图像时的视觉效果较差,可以采用灰度变换(灰度修正)方法提高图像的对比度,增强图像。常用的灰度修正方法有:

(1)       线性变换

(2)       分段线性变换

(3)       非线性变换,如指数变换、对数变换等

这里采用的是 分段线性变换

2、            基本算法

为了突出感兴趣的目标或灰度区间,相对抑制不感兴趣的灰度区间,可以采用分段线性变换。常用三段线性变换方法。

设原灰度直方图的灰度级的分布范围为[0,],集中分布在[a,b],又设变换后的直方图灰度级的分布范围为[0,],集中分布在[c,d],则变换公式如下:

对 :

对 :

对 :

3、            扩展算法

在本实验中,和都当成255,而原灰度级的集中分布范围 [a,b] 是通过程序算出来的,即从原图像的灰度直方图中找出一个连续灰度区间 [a,b] ,这个区间满足两个条件:

 

(1)       在此灰度级区间内的像素个数和占总像素个数的85%以上

(2)       此区间是满足(1)的区间中区间长度最短的

 

注:上述比例85%是在程序中默认的,其实应该做成能让用户自己输入一个比例,然后程序找出这个比例下灰度级的集中分布区间,但由于时间有限,程序中只默认为85%,没有实现让用户输入比例的功能。

直方图均衡化(histogram equalization)是一种借助直方图变换实现灰度映射从而达到图像增强目的的方法。直方图均衡化通常是对图像灰度值进行归一化的一个非常好的方法,并且可以增强图像的对比度。

直方图的特点

直方图具有很多的优点,直方图能反映图像的概貌,

  • 图像中有几类目标,目标和背景的分布如何;

  • 通过直方图可以直接计算图像中的最大亮度、最小亮度、平均亮度、对比度以及中间亮度等。

  • 使用直方图可以完成图像分割、目标检索等。因为不同的目标具有不同的颜色分布。使用归一化直方图作目标匹配,还不易受到目标翻转和目标大小变化的影响。

  • 在图像查询的系统中,直方图有很大的应用,用它存储目标的特征占有空间小,且执行速度快。

  • 其缺点:因其没有记录位置信息,不同的图像会具有相同或相近的直方图。一幅图像旋转、翻转后的直方图是相同的;放大、缩小后的直方是相近的。

     

 

三、 算法实现

功能函数:功能说明,输入参数说明,输出参数说明,算法流程(代码或伪代码,注释)

(一)         使用语言

本程序采用Java语言编写,开发平台为Eclipse (Version: Juno)

(二)         编译环境

java version "1.7.0_25"

Java(TM) SE Runtime Environment (build 1.7.0_25-b17)

(三)         功能函数

1、private BufferedImage getGrayPicture(BufferedImage originalImage)

(1)   功能说明:此函数获得输入图像的灰度图像,以及对应的灰度分布

(2)   输入参数说明:originalImage为输入的图像,类型为BufferedImage

(3)   输出参数说明:调用此函数后得到输入图像对应的灰度图像,并把个灰度级的像素个数存入全局数组huidunum[]中,供后面处理之用

(4)   算法流程:

遍历每个像素——>

获得该像素RGB值——>

获得R、G、B分量——>

得到灰度值——>

以灰度值为新R、G、B分量,得到新RGB值——>

新像素

* *

    // 获得图像的灰度图,并得到该图像个灰度级的像素个数 huidunum[]

    private BufferedImage getGrayPicture(BufferedImage originalImage) {

        int rgb, gray, alph, red, green, blue;

        int imgwidth = originalImage.getWidth();

        int imgheight = originalImage.getHeight();

        BufferedImage huiduimg = new BufferedImage(imgwidth, imgheight,

                originalImage.getType());// 不在原图像上修改,而是创建同样大小的一张图片

        for (int i = 0; i < 256; i )

            huidunum[i] = 0; // 灰度分布初始化为0,即各灰度值像素个数初始化为0

        for (int i = 0; i < imgwidth; i ) {

            for (int j = 0; j < imgheight; j ) {// 遍历图像所以像素

                rgb = originalImage.getRGB(i, j);// 获得该像素的rgb值,为一个4字节的整数,从高到低各字节值

                                                    // 分别表示

                                                    // 透明度appha、red、green、blue

 

                alph = rgb >> 24; // 得到appha的值

                red = (rgb & 0xff0000) >> 16;// 得到red值

                green = (rgb & 0xff00) >> 8;// 得到green值

                blue = (rgb & 0xff);// 得到blue值

 

                gray = (int) (red * 299 green * 587 blue * 114) / 1000;// 根据公式由rgb三分量值得到灰度值gray

 

                huidunum[gray] ;// 该灰度值像素个数加一

 

                rgb = (alph << 24) | (gray << 16) | (gray << 8) | gray;// 由灰度值转rgb值,三分量都是gray值

                huiduimg.setRGB(i, j, rgb);// 新rgb值

            }

        }

        return huiduimg;

}

* *

2、private BufferedImage hisEqual(BufferedImage originalImage)

(1)    功能说明:此函数实现直方图均衡化的功能

(2)    输入参数说明:originalImage为读入的图像

(3)    输出参数说明:获得对应的经过直方图均衡处理后的图像

(4)    算法流程:

遍历每个灰度值的像素个数huidunum[]——>

得到灰度值范围[0,当前灰度值]内的像素个数temp——>

该区间与总像素个数的比值——>

新灰度值=原灰度值×比值——>

以新灰度值为R、G、B分量得到RGB值——>

新像素

    // 直方图均衡处理,不改变源图像

    private BufferedImage hisEqual(BufferedImage originalImage) {

        int alph, rgb, red, green, blue, gray;

        int width = originalImage.getWidth();

        int height = originalImage.getHeight();

        double temp = 0.0;

 

        BufferedImage transimg = new BufferedImage(width, height,

                originalImage.getType());// 创建一张同样大小的新图片

 

        for (int i = 0; i < 256; i ) {//遍历灰度直方图

            temp = 0.0;

            for (int j = 0; j <= i; j ) {//

                temp = (double) huidunum[j] temp;

            }

            temp = (temp / (double) width) / (double) height;

            transhuidu[i] = (int) (255.0 * temp);

        }

        for (int i = 0; i < width; i ) {

            for (int j = 0; j < height; j ) {

                rgb = originalImage.getRGB(i, j);

 

                alph = rgb >> 24;

                red = (rgb & 0xff0000) >> 16;

                green = (rgb & 0xff00) >> 8;

                blue = (rgb & 0xff);

 

                gray = (int) (red * 299 green * 587 blue * 114) / 1000;

                gray = transhuidu[gray];// 新灰度值

                rgb = (alph << 24)|(gray << 16)|(gray << 8) | gray;//新RGB值

                transimg.setRGB(i, j, rgb);

            }

        }

        return transimg;

    }

 

3、private void getRecommendRange(int width, int height, int huidunum[])

(1)    功能说明:获得像素集中分布的灰度值范围

(2)       输入参数说明:三个参数分别为图像宽、高、各灰度值的像素个数

(3)       输出参数说明:函数得到像素集中分别的灰度值范围,下界、上界分别存入全局变量recommendstart、recommendend

(4)    算法流程:

初始化待求区间为[0,255]——>

以i遍历huidunum[]——>

以j遍历huidunum[i,255]——>

以k遍历huidunum[i,j] 并统计此区间内像素总个数sum——>

若sum不少于总像素个数的85%且区间[i,j]长度小于上次得到的区间长度,则取[i,j]。如此循环直到完。

 

    // 获得源图像中占大部分的连续灰度值区间 [recommendstart,recommendend]

    private void getRecommendRange(int width, int height, int huidunum[]) {

        double sum = 0.0;

        recommendstart = 0;

        recommendend = 255;

        for (int i = 0; i < 256; i ) {

            for (int j = i; j < 256; j ) {

                sum = 0.0;

                for (int k = i; k <= j; k ) {

                    sum = sum (double) huidunum[k];

                }

                if (sum > percentage * width * height) {

                    if (j - i < recommendend - recommendstart) {

                        recommendstart = i;

                        recommendend = j;

                    }

                }

            }

        }

}

 

 

4、**private int getNewGrayValue(int f, int a, int b, int c, int d)**

(1)    功能说明:此函数实现灰度值转换

(2)    输入参数说明:f为原灰度值,[b,c]为原图像灰度值集中范围,[c,d]为要拉伸到的范围,由用户输入

(3)    输出参数说明:函数得到变换后的新灰度值

(4)    算法流程:此部分就是 二(二)2的编程实现,比较简单不再赘述

* *

    private int getNewGrayValue(int f, int a, int b, int c, int d) {

        int newGrayValue = f;

        if (f < a) {

            newGrayValue = (int) ((double) c * (double) f / (double) a);

        } else if (f > b) {

            newGrayValue = (int) ((double) (f - b) * (double) (255 - d)

                    / (double) (255 - b) d);

        } else {

            newGrayValue = (int) ((double) (f - a) * (double) (d - c)

                    / (double) (b - a) c);

        }

        return newGrayValue;

}

* *

5、     private BufferedImage Linearstretch(BufferedImage originalImage, int newgraystart, int newgrayend)

(1)    功能说明:根据用户输入的灰度值范围[newgraystart, newgrayend]进行分段线性拉伸

(2)    输入参数说明originalImage为原图像,[newgraystart, newgrayend]为用户输入的灰度值范围

(3)    输出参数说明函数执行成功后得到原图像经分段线性拉伸后的图像

(4)   算法流程

执行getRecommendRange函数获得原图像计组像素集中分布的灰度值范围——>

遍历原图像的像素——>

获得该像素的rgb值——>

获得rgb值的分量r、g、b——>

获得灰度值gray——>

执行getNewGrayValue函数获得对应的新灰度值——>

以gray为三个分量获得新rgb值——>

得到新像素

 

private BufferedImage Linearstretch(BufferedImage originalImage,

            int newgraystart, int newgrayend) {

        int newhuidunum[] = new int[256];

 

        int alph, rgb, red, green, blue, gray;

        int width = originalImage.getWidth();

        int height = originalImage.getHeight();

 

        BufferedImage transimg = new BufferedImage(width, height,

                originalImage.getType());

 

        // 获得灰度大部分集中的范围 [recommendstart, recommendend]

        getRecommendRange(width, height, huidunum);

 

        for (int i = 0; i < width; i ) {

            for (int j = 0; j < height; j ) {

                rgb = originalImage.getRGB(i, j);

 

                alph = rgb >> 24;

                red = (rgb & 0xff0000) >> 16;

                green = (rgb & 0xff00) >> 8;

                blue = (rgb & 0xff);

 

                gray = (int) (red * 299 green * 587 blue * 114) / 1000;

 

                // 根据拉伸变换得到新的灰度值

                gray = getNewGrayValue(gray, recommendstart, recommendend,

                        newgraystart, newgrayend);

                rgb = (alph << 24) | (gray << 16) | (gray << 8) | gray;

                transimg.setRGB(i, j, rgb);

                newhuidunum[gray] ;

            }

        }

        return transimg;

}

基本思想:把原始图的直方图变换成为均匀分布的形式,这样,就增加了像素灰度值的动态范围,从而达到增强图像整体对比度的效果。

直方图均衡化

原理

为了增强图像整体的对比效果,增加灰度值的动态范围

由图像点运算可知,图像增强的公式可以表示为

G(x,y)=F(g(x,y))

这里,由于要增强对比效果,所以
这里假设原图灰度级范围位为采用归一化的[0,1]

  • F()在整个灰度级范围[0,1]内是递增函数(因为要增强对比)

  • F()的值域也是[0,1]

可以证明累计分布函数满足上面的变换函数要求,而图像中,这个累计分布函数,就是原始图像的累计直方图。
F()通常都是作为查找表LUT出现的,因为是离散的,所以累计直方图也是可以作为LUT出现

实际上:累计分布直方图作为图像变换函数(本质为LUT)。从而将增强了原图像的对比效果。而通常图像变换函数是离散的,通过LUT实现,所以通过累计分布直方图作就可以实现直方图均衡化。

 

也可以用熵的原理来解释均衡化原理:

熵(Entropy):是信息量的度量,其定义为:

 

                                美高梅网投平台 34

 

其中, pi是符号 i出现的概率。  在图像中,美高梅网投平台 35pr是灰度级r 出现的概率。

可以证明,当p0=p1=p2=…=p255=1/256时,H取最大值,即图像信息量最大。  

根据熵理论可知,直方图中,当H[0],H[1]…,H[n-1]相等时,图像信息量最大-》均衡化的目的是使每个Hi都相等,即把原始图的直方图变换为均匀分布的形式,这样就增加了象素值的范围,增强了图像的对比效果。

 

对于熵这个概念,我也是费了好大的劲才大概能够明白他的意思:

熵越大,系统的不确定性越大,系统越混乱,从而信息量也就越大。

   对于单个信息,可以理解为发生的概率越小  ,熵越大    

         对于一个系统,如果系统由多个部分组成,则可以理解为各个部分发生概率基本相等时熵最大

关于熵的概念,大家可以参考吴军老师的《数学之美》中关于熵的解释,比较通俗易懂。

 

直方图均衡化算法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void GetHistogramEqualize(BYTE *image_Src,BYTE *image_Dst, int width, int height)
{
    //-------step 1.求灰度直方图
    unsigned long historgam[256];
    GetHistogram(image_Src, width, height, historgam);
 
    //------step 2.求累计分布直方图(灰度变换函数,LUT)
    //累计分布直方图符合增强对比度函数的要求
    int LUT[256];
    LUT[0] = historgam[0];
    int sum = historgam[0];
    for (int i = 1; i <= 255;  i)
    {
        sum  = historgam[i];
        LUT[i] =255* sum / (width*height);
    }
 
    //----step 3.对原图像做图像增强
    int pixelCount = width*height;
    for (int i = 0; i <= pixelCount - 1;  i)
    {
        int gray = image_Src[i];
        image_Dst[i] = LUT[gray];
         
    }
}

效果图(借助了Opencv来显示图片)

 

美高梅网投平台 36

 

四、 实验

(一)灰度直方图均衡

  1. 1.      实验与结果

美高梅网投平台 37  

美高梅网投平台 38

 

  1. 2.      结果分析

图像经过直方图均衡处理后,图像的对比度会增强,特别是对于背景或前景都太亮或太暗的图像非常有用。

均衡化后的各灰度级更加均衡,对于灰度范围小,直方图分布极不均匀的图像,可人为的适当的扩大灰度范围,均衡化后能取得较好的层次感,使图像信息变得更清晰。

(二)分段线性拉伸

(1)      
实验与结果

美高梅网投平台 39

 美高梅网投平台 40

美高梅网投平台 41

美高梅网投平台 42

 

 

(2)       结果分析

从以上实验及其结果对比可看出,线性变换可以把原图像相对较集中的灰度级拉伸到到指定的灰度级范围,当灰度级范围比原范围低时,图像将变暗,反之则变亮。

美高梅网投平台 43直方图均衡化算法.png美高梅网投平台 44直方图均值化.png

五、 结论

直方图均衡和线性拉伸是对数字图像进行处理的方法中的两种,是点运算。

直方图均衡处理可以使所有灰度级出现的相对概率相同,经过直方图均衡处理后,图像的对比度会增强,会更有层次感,特别是对于背景或前景都太亮或太暗的图像非常有用。

线性拉伸可以把原图像集中的灰度值区间拉伸到指定的区间上,这样可以突出感兴趣的目标或灰度区间,相对抑制不感兴趣的灰度区间。

参考文献

[1] 冈萨雷斯. 数字图像处理[M]. 北京:电子工业出版社, 2011.

 

 Resources res = getResources(); final Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.test_hist); image0.setImageBitmap; CV4JImage cv4jImage0 = new CV4JImage; ImageProcessor imageProcessor = cv4jImage0.convert2Gray().getProcessor(); Paint paint = new Paint(); calcImage0.setImageBitmap(drawHist(imageProcessor,paint)); CV4JImage cv4jImage = new CV4JImage; imageProcessor = cv4jImage.convert2Gray().getProcessor(); if (imageProcessor instanceof ByteProcessor) { EqualHist equalHist = new EqualHist(); equalHist.equalize((ByteProcessor) imageProcessor); image1.setImageBitmap(cv4jImage.getProcessor().getImage().toBitmap; paint = new Paint(); calcImage1.setImageBitmap(drawHist(imageProcessor,paint)); }

 private Bitmap drawHist(ImageProcessor imageProcessor,Paint paint) { CalcHistogram calcHistogram = new CalcHistogram(); int bins = 127; int[][] hist = new int[imageProcessor.getChannels()][bins]; calcHistogram.calcHist(imageProcessor,bins,hist,true); Bitmap bm = Bitmap.createBitmap(512,512, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas; paint.setColor(Color.BLACK); paint.setStyle(Paint.Style.FILL_AND_STROKE); canvas.drawRect(0,0,512,512,paint); float step = 512.0f/127; int xoffset; int yoffset; int channels = imageProcessor.getChannels(); int[] colors = new int[]{Color.argb(127,255,0,0),Color.argb(127,0,255,0),Color.argb(127,0,0,255)}; for (int i=0;i<channels;i  ) { paint.setColor(colors[i]); for (int j=0;j<bins;j  ) { xoffset = ; yoffset = hist[i][j]*512/255; canvas.drawRect(xoffset,512-yoffset,xoffset step,512,paint); } } return bm; }

同样,如果对EqualHist感兴趣,可以查看cv4j的具体实现。

图像是由像素构成的,然而直方图能够反映像素的分布情况,可以作为是图像一个很重要的特征。在实际开发中,图像直方图在特征提取、图像匹配等方面都有很好的应用。除此之外,直方图还能做图像的相似度匹配。

直方图均衡化则用于增强图片,利于人的视觉效果或便于机器识别。

CalcHistogram 和 EqualHist 是cv4j中直方图相关操作的类。

cv4j 是gloomyfish和我一起开发的图像处理库,纯java实现,目前还处于早期的版本。

美高梅网投平台 45cv4j.png

上周末我们开始做直方图的相关操作,预计下周能做完这个模块。

另外,在Google I/O之后,我们第一时间便更新了cv4j中的rxcv4j模块。该模块顾名思义是对cv4j使用RxJava进行封装,我们将该模块用Kotlin重写,也算是赶了一回时髦:)。

该系列先前的文章:模拟油画和铅笔画的滤镜效果二值图像分析之轮廓分析基于边缘保留滤波实现人脸磨皮的算法二值图像分析:案例实战(文本分离 硬币计数)Java实现高斯模糊和图像的空间卷积Java实现图片滤镜的高级玩法Java实现图片的滤镜效果

TAG标签:
版权声明:本文由美高梅网投平台发布于新闻中心,转载请注明出处:数字图像点运算实践,图像直方图变换和几何变