OpenCV 对比度受限的自适应直方图均衡化(CLAHE) C++实现

直方图均衡化(HE)是一种很常用的直方图类方法,基本思想是通过图像的灰度分布直方图确定一条映射曲线,用来对图像进行灰度变换,以达到提高图像对比度的目的。该映射曲线其实就是图像的累计分布直方图(CDF)(严格来说是呈正比例关系)。然而HE是对图像全局进行调整的方法,不能有效地提高局部对比度,而且某些场合效果会非常差。
对比度受限的自适应直方图均衡(CLAHE,Contrast Limited Adaptive Histogram Equalization)算法。尽管最初它仅仅是被当作一种图像增强算法被提出,但是现今在图像去雾、低照度图像增强,水下图像效果调节、以及数码照片改善等方面都有应用。这个算法的算法原理看似简单,但是实现起来却并不那么容易。我们将结合相应的OpenCV代码来对其进行解释。

 

先来看一下待处理的图像效果:

OpenCV 对比度受限的自适应直方图均衡化(CLAHE) C++实现_第1张图片

下面是利用CLAHE算法处理之后得到的两个效果(后面我们还会具体介绍我们所使用的策略)

OpenCV 对比度受限的自适应直方图均衡化(CLAHE) C++实现_第2张图片

OpenCV 对比度受限的自适应直方图均衡化(CLAHE) C++实现_第3张图片

 

对于一幅图像而言,它不同区域的对比度可能差别很大。可能有些地方很明亮,而有些地方又很暗淡。如果采用单一的直方图来对其进行调整显然并不是最好的选择。于是人们基于分块处理的思想提出了自适应的直方图均衡算法AHE。维基百科上说的也比较明白:AHE improves on this by transforming each pixel with a transformation function derived from a neighbourhood region. 但是这种方法有时候又会将一些噪声放大,这是我们所不希望看到的。于是荷兰乌得勒支大学的Zuiderveld教授又引入了CLAHE,利用一个对比度阈值来去除噪声的影响。特别地,为了提升计算速度以及去除分块处理所导致的块边缘过渡不平衡效应,他又建议采用双线性插值的方法。关于算法的介绍和描述,下面这两个资源已经讲得比较清楚。

[1] https://en.wikipedia.org/wiki/Adaptive_histogram_equalization#Contrast_Limited_AHE

[2] K. Zuiderveld: Contrast Limited Adaptive Histogram Equalization. In: P. Heckbert: Graphics Gems IV, Academic Press 1994 (http://www.docin.com/p-119164091.html)

https://en.wikipedia.org/wiki/Adaptive_histogram_equalization

关于他的原理很多教程已经明白了,现在直说Opencv怎么用它。

OpenCV中 CLAHE代码地址如下:

/modules/imgproc/src/clahe.cpp

代码使用

static void color_transfer_with_spilt( cv::Mat &input, std::vector &chls )
{
    cv::cvtColor( input, input, cv::COLOR_BGR2YCrCb);
    cv::split( input, chls );
}

static void color_retransfer_with_merge( cv::Mat &output, std::vector &chls )
{
    cv::merge( chls, output );
    cv::cvtColor( output, output, cv::COLOR_YCrCb2BGR );
}

cv::Mat clahe_deal( cv::Mat &src)
{
    cv::Mat ycrcb = src.clone();
    std::vector channels;

    color_transfer_with_spilt(ycrcb, channels);

    cv::Mat clahe_img;
    cv::Ptr clahe = cv::createCLAHE();
    // 直方图的柱子高度大于计算后的ClipLimit的部分被裁剪掉,然后将其平均分配给整张直方图
    // 从而提升整个图像
    clahe->setClipLimit(4.);    // (int)(4.*(8*8)/256)
    clahe->setTilesGridSize(Size(8, 8)); // 将图像分为8*8块
    clahe->apply(channels[0], clahe_img);
    channels[0].release();
    clahe_img.copyTo(channels[0]);
    color_retransfer_with_merge(ycrcb, channels);
    return ycrcb;

}

你可能感兴趣的:(OpenCV,C++,数字图像处理,OpenCV,C++数字图像处理,冈萨雷斯第三版)