Opencv图像增强算法实现(直方图均衡化、Laplace、Log、Gamma)

增强图像中的有用信息,它可以是一个失真的过程,其目的是要改善图像的视觉效果,针对给定图像的应用场合,有目的地强调图像的整体或局部特性,将原来不清晰的图像变得清晰或强调某些感兴趣的特征,扩大图像中不同物体特征之间的差别,抑制不感兴趣的特征,使之改善图像质量、丰富信息量,加强图像判读和识别效果,满足某些特殊分析的需要。

直方图均衡化图像增强

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

  • 优点:这种方法对于背景和前景都太亮或者太暗的图像非常有用,这种方法尤其是可以带来X光图像中更好的骨骼结构显示以及曝光过度或者曝光不足照片中更好的细节。这种方法的一个主要优势是它是一个相当直观的技术并且是可逆操作,如果已知均衡化函数,那么就可以恢复原始的直方图,并且计算量也不大。
  • 缺点:缺点是它对处理的数据不加选择,它可能会增加背景杂讯的对比度并且降低有用信号的对比度;变换后图像的灰度级减少,某些细节消失;某些图像,如直方图有高峰,经处理后对比度不自然的过分增强。
    彩色图像的直方图均衡化实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #include "opencv2/opencv.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    using namespace std;
    using namespace cv;

    int main()
    {
    Mat src = imread("elephant.jpg");
    Mat src_RGB[3], dst;
    split(src, src_RGB);

    for (int i = 0; i < 3; i++)
    {
    equalizeHist(src_RGB[i], src_RGB[i]);
    }

    merge(src_RGB, 3, dst);
    imwrite("elephant_hist.jpg", dst);
    waitKey();
    return 0;
    }
    直方图均衡化前后对比如下:
    直方图均衡化

Laplace图像增强

拉普拉斯算子可以增强局部的图像对比度。
Laplace 8邻域卷积核:
0 -1 0
-1 5 -1
0 -1 0
采用filter2D函数实现对图像的卷积:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "opencv2/opencv.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace std;
using namespace cv;

int main()
{
Mat src = imread("cow.jpg");
Mat dst;
Mat kernel = (Mat_<int>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(src, dst, src.depth(), kernel);
imshow("dst",dst);
waitKey();
return 0;
}

图像进行Laplace卷积前后对比如下:
Laplace变换

对数Log变换图像增强

对数变换可以将图像的低灰度值部分扩展,显示出低灰度部分更多的细节,将其高灰度值部分压缩,减少高灰度值部分的细节,从而达到强调图像低灰度部分的目的。变换方法:
$$ s=c·\log_v(1+v·r) \longrightarrow r\in [0,1]$$
对于不同的底数,底数越大,对低灰度部分的扩展就越强,对高灰度部分的压缩也就越强。

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
#include "opencv2/opencv.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace std;
using namespace cv;

int main()
{
Mat src = imread("darknight.jpg");
Mat dst(src.size(), CV_32FC3);

for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
dst.at<Vec3f>(i, j)[0] = log(1 + src.at<Vec3b>(i, j)[0]);
dstdst.at<Vec3f>(i, j)[1] = log(1 + src.at<Vec3b>(i, j)[1]);
dst.at<Vec3f>(i, j)[2] = log(1 + src.at<Vec3b>(i, j)[2]);
}
}
normalize(dst, dst, 0, 255, CV_MINMAX);
convertScaleAbs(dst, dst);
imshow("darknight_log.jpg",dst);
waitKey();
return 0;
}

对图片进行Log变换前后对比如下:
Log变换

伽马变换的图像增强

伽马变换主要用于图像的校正,将灰度过高或者灰度过低的图片进行修正,增强对比度。变换公式就是对原图像上每一个像素值做乘积运算:
$$ s=cr^\gamma \longrightarrow r\in[0,1] $$
伽马变换对于图像对比度偏低,并且整体亮度值偏高(对于于相机过曝)情况下的图像增强效果明显。

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
27
#include "opencv2/opencv.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace std;
using namespace cv;
#define Gamma 3

int main()
{
Mat src = imread("src.jpg");
Mat dst(src.size(), CV_32FC3);

for (int i = 0; i < src.rows;i++)
{
for (int j = 0; j < src.cols; j++)
{
dst.at<Vec3f>(i, j)[0] = pow(src.at<Vec3b>(i, j)[0], Gamma);
dst.at<Vec3f>(i, j)[1] = pow(src.at<Vec3b>(i, j)[1], Gamma);
dst.at<Vec3f>(i, j)[2] = pow(src.at<Vec3b>(i, j)[2], Gamma);
}
}
normalize(dst, dst, 0, 255, CV_MINMAX);
convertScaleAbs(dst, dst);

waitKey();
return 0;
}

图像进行Laplace卷积前后对比如下:
伽马变换