直方图均衡化

  图像对比度加强的方法能够分红两类:一类是直接对比度加强方法;另外一类是间接对比度加强方法。直方图拉伸和直方图均衡化是两种最多见的间接对比度加强方法。直方图拉伸是经过对比度拉伸对直方图进行调整,从而“扩大”前景和背景灰度的差异,以达到加强对比度的目的,这种方法能够利用线性或非线性的方法来实现;直方图均衡化则经过使用累积函数对灰度值进行“调整”以实现对比度的加强。数组

  直方图均衡化的英文名称是Histogram Equalization. ide

  直方图均衡化是图像处理领域中利用图像直方图对对比度进行调整的方法。这种方法一般用来增长许多图像的局部对比度,尤为是当图像的有用数据的对比度至关接近的时候。经过这种方法,亮度能够更好地在直方图上分布。这样就能够用于加强局部的对比度而不影响总体的对比度,直方图均衡化经过有效地扩展经常使用的亮度来实现这种功能。函数

基本思想

  直方图均衡化处理的“中心思想”是把原始图像的灰度直方图从比较集中的某个灰度区间变成在所有灰度范围内的均匀分布。直方图均衡化就是对图像进行非线性拉伸,从新分配图像像素值,使必定灰度范围内的像素数量大体相同。直方图均衡化就是把给定图像的直方图分布改变成“均匀”分布直方图分布。ui

  直方图均衡化的基本思想是把原始图的直方图变换为均匀分布的形式,这样就增长了象素灰度值的动态范围从而可达到加强图像总体对比度的效果。设原始图像在(x,y)处的灰度为f,而改变后的图像为g,则对图像加强的方法可表述为将在(x,y)处的灰度f映射为g。在灰度直方图均衡化处理中对图像的映射函数可定义为:g = EQ (f),这个映射函数EQ(f)必须知足两个条件(其中L为图像的灰度级数):spa

  (1)EQ(f)在0≤f≤L-1范围内是一个单值单增函数。这是为了保证加强处理没有打乱原始图像的灰度排列次序,原图各灰度级在变换后仍保持从黑到白(或从白到黑)的排列。指针

  (2)对于0≤f≤L-1有0≤g≤L-1,这个条件保证了变换先后灰度值动态范围的一致性。 htm

  累积分布函数(cumulative distribution function,CDF)便可以知足上述两个条件,而且经过该函数能够完成将原图像f的分布转换成g的均匀分布。此时的直方图均衡化映射函数为:blog

  gk = EQ(fk) = (ni/n) = pf(fi) , ci

  (k=0,1,2,……,L-1) 资源

  上述求和区间为0到k,根据该方程能够由源图像的各像素灰度值直接获得直方图均衡化后各像素的灰度值。在实际处理变换时,通常先对原始图像的灰度状况进行统计分析,并计算出原始直方图分布,而后根据计算出的累计直方图分布求出fk到gk的灰度映射关系。在重复上述步骤获得源图像全部灰度级到目标图像灰度级的映射关系后,按照这个映射关系对源图像各点像素进行灰度转换,便可完成对源图的直方图均衡化。

 

 图像直方图变换的基本原理

设变量r表明图像中像素的灰度级,直方图变换就是假定一个变换式:

                            (1-1)

也就是,经过上述变换,每一个原始图像的像素灰度级r都会产生一个s值。变换函数T(r)应知足如下条件:

(1)       T(r)在区间中为单值且单调递增;

(2)       当 时,,即T(r)的取值范围与r相同。

2. 直方图均衡化:

对于离散值,咱们处理其几率与求和,而不是几率密度函数与积分。一幅图像中灰度级rk出现的几率近似为

                                                (1-2)

其中,n是图像中像素的总和, 是灰度级 的像素个数,L为图像中可能的灰度级总数。

                                               (1-3)

         上式中变换函数的离散形式为:    

                                             (1-4)

         式(1-4)给出的变换(映射)称为直方图均衡化或直方图线性化。

 

优缺点

  这种方法对于背景和前景都太亮或者太暗的图像很是有用,这种方法尤为是能够带来X光图像中更好的骨骼结构显示以及曝光过分或者曝光不足照片中更好的细节。这种方法的一个主要优点是它是一个至关直观的技术而且是可逆操做,若是已知均衡化函数,那么就能够恢复原始的直方图,而且计算量也不大。

  这种方法的一个缺点是它对处理的数据不加选择,它可能会增长背景杂讯的对比度而且下降有用信号的对比度;变换后图像的灰度级减小,某些细节消失;某些图像,如直方图有高峰,经处理后对比度不天然的过度加强。

 

/*************************************************************************

 *

 * 函数名称:

 * InteEqualize()

*

* 参数:

* LPSTR lpDIBBits - 指向源DIB图像指针

 * LONG lWidth - 源图像宽度(象素数)

* LONG lHeight - 源图像高度(象素数)

 *

* 返回值:

* BOOL - 成功返回TRUE,不然返回FALSE。

*

* 说明:

* 该函数用来对图像进行直方图均衡。

 *

 ************************************************************************/

BOOL WINAPI InteEqualize(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)

{

        // 指向源图像的指针

       unsigned char* lpSrc;

       // 临时变量

        LONG lTemp;

       // 循环变量

        LONG i; LONG j;

        // 灰度映射表

       BYTE bMap[256];

       // 灰度映射表

        LONG lCount[256];

       // 图像每行的字节数

       LONG lLineBytes;

        // 计算图像每行的字节数

        lLineBytes = WIDTHBYTES(lWidth * 8);

        // 重置计数为0

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

        {

              // 清零

               lCount[i] = 0;

       }

       // 计算各个灰度值的计数

        for (i = 0; i < lHeight; i ++)

       {

              for (j = 0; j < lWidth; j ++)

              {

                     lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j;

                      // 计数加1 l

                     Count[*(lpSrc)]++;

              }

       }

       / / 计算灰度映射表

       lTemp = 0;

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

       {                          

               lTemp += lCount[j];

                // 计算对应的新灰度值

               bMap[i] = (BYTE) (lTemp * 255 / lHeight / lWidth);

        }

         // 每行

        for(i = 0; i < lHeight; i++)

        {

                // 每列

                for(j = 0; j < lWidth; j++)

                 {

                         // 指向DIB第i行,第j个象素的指针

                         lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;

                         // 计算新的灰度值

                        *lpSrc = bMap[*lpSrc];

                 }

        }

        // 返回

        return TRUE;

        }

 

 

Split
分割多通道数组成几个单通道数组或者从数组中提取一个通道

void cvSplit( const CvArr* src, CvArr* dst0, CvArr* dst1,
CvArr* dst2, CvArr* dst3 );
#define cvCvtPixToPlane cvSplit
src
原数组.
dst0...dst3
目标通道
函数 cvSplit 分割多通道数组成分离的单通道数组d。可得到两种操做模式 . 若是原数组有N通道且前N输出数组非NULL, 全部的通道都会被从原数组中提取,若是前N个通道只有一个通道非NULL函数只提取该指定通道,不然会产生一个错误,馀下的通道(超过前N个通道的以上的)必须被设置成NULL,对于设置了COI的IplImage 结使用cvCopy 也能够从图像中提取单通道。

 

opencv多通道融合:Merge

Merge
从几个单通道数组组合成多通道数组或插入一个单通道数组

void cvMerge( const CvArr* src0, const CvArr* src1,
const CvArr* src2, const CvArr* src3, CvArr* dst );
#define cvCvtPlaneToPix cvMerge
src0... src3
输入的通道.
dst
输出数组.
函数cvMerge 是前一个函数的反向操做。若是输出数组有N个通道而且前N个输入通道非NULL,就拷贝全部通道到输出数组,若是在前N个通道中只有一个单通道非NULL ,只拷贝这个通道到输出数组,不然 就会产生错误。除前N通道之外的馀下的通道必须置NULL。对于设置了COI的 IplImage结构使用 cvCopy也能够实现向图像中插入一个通道 。

 

EqualizeHist

灰度图象直方图均衡化

void cvEqualizeHist( const CvArr* src, CvArr* dst );

src

输入的 8-比特 单信道图像

dst

输出的图像与输入图像大小与数据类型相同

函数 cvEqualizeHist 采用以下法则对输入图像进行直方图均衡化:


1. 计算输入图像的直方图 H

2.  直方图归一化,所以直方块和为255

3. 计算直方图积分: 

4. 采用H'做为查询表:dst(x,y)=H'(src(x,y))进行图像变换。

该方法归一化图像亮度和加强对比度。

 ----------------------------------------------------------------------------------------------

#include <highgui.h>
#include <cv.h>

int main(int argc, char** argv)
{
         int i;
         IplImage* src = cvLoadImage( argv[1], 1 );
         IplImage* imgChannel[4] = { 0, 0, 0, 0 };
         IplImage* dst = cvCreateImage( cvGetSize( src ), IPL_DEPTH_8U, 3 );

         if( src )
         {
                 for( i = 0; i < src -> nChannels; i++ )
                  {
                           imgChannel[i] = cvCreateImage( cvGetSize( src ), IPL_DEPTH_8U, 1 );  //要求单通道图像才能直方图均衡化
                  }
                   //通道分离
                   cvSplit( src, imgChannel[0], imgChannel[1], imgChannel[2], imgChannel[3] );
                   for( i = 0; i < dst -> nChannels; i++ )
                   {
                    //直方图均衡化,原始图像和目标图像必须是单通道
                    cvEqualizeHist( imgChannel[i], imgChannel[i] );
                   }

                   //通道组合
                   cvMerge( imgChannel[0], imgChannel[1], imgChannel[2], imgChannel[3], dst );
                   cvNamedWindow( "src", 1 );
                   cvShowImage( "src", src );
                   cvNamedWindow( "Equalize", 1 );
                   cvShowImage( "Equalize", dst );

                   cvWaitKey(0);
                   //释放资源
                   for( i = 0; i < src -> nChannels; i++ )
                   {
                             if( imgChannel[i] )
                             {
                                      cvReleaseImage( &imgChannel[i] );
                                      //imgChannel[i] = 0;
                             }
                   }
                   cvReleaseImage( &dst );
          }

          return 0; }