0%

OpenCV 调整图片对比度及亮度

参考链接

如果记 $f(x)$ 为原图片的像素信息,$g(x)$ 为输出图片的像素信息,

那么可以通过 $g(i,j) = \alpha \cdot f(i,j) + \beta$ 来对像素进行操作,此处 $i,j$ 分别表示该像素点所在的行和列,$\alpha \gt 0$。

$\alpha$ 在此被称为 “增益”,可以用于调节对比度;$\beta$ 在此被称为 “偏移” 或 “偏置”,可以用于调整亮度。

  • $\alpha$ 可以用于调节对比度的原因:

    当 $\alpha \gt 1$ 时,$\alpha \cdot f(i,j)$ 的操作会增大各像素值之间的差异,使差异从原来的 $d$ 增加到了 $\alpha d$,此时增强了对比度。

    当 $\alpha \lt 1$ 时,$\alpha \cdot f(i,j)$ 的操作会缩小各像素值之间的差异,使差异从原来的 $d$ 减小至了 $\alpha d$,此时减弱了对比度。

  • $\beta$ 可以用于调节亮度的原因:

    通过最终加算一个 $\beta$,所有像素值都增加或减少了一个固定的量。这会导致图像整体变亮或变暗,因此我们说 $\beta$ 可以改变图像的亮度。

但是,这种操作容易丢失亮部或暗部的信息。

我们希望,如果原像素的亮度已经足够高,那么继续提亮对这个像素点的影响应该是较小的。

换言之,我们需要一种非线性的方法 $g(x)$ 来改变图片的亮度。

我们可以通过 $O = \left(\dfrac{I}{255}\right)^\gamma \times 255$ 来实现这一功能。

这种操作可以在尽量多地保留亮部信息的前提下提亮暗部、在尽量多地保留暗部信息的前提下压暗亮部。

中间是原图的直方图;左侧是调 $\beta$ 后的直方图;右侧是调 $\gamma$ 后的直方图。

并且我们可以针对每一个 $\gamma$ 预处理出来一个表,代表 0-255 所有值处理后的结果。

然后就不需要每次都算一遍了,将复杂度从 $O(nm\log\gamma)$ 优化至 $O(nm+\log\gamma)$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//官方提供的示例 
//https://github.com/opencv/opencv/blob/4.x/samples/cpp/tutorial_code/ImgProc/changing_contrast_brightness_image/changing_contrast_brightness_image.cpphttps://github.com/opencv/opencv/blob/4.x/samples/cpp/tutorial_code/ImgProc/changing_contrast_brightness_image/changing_contrast_brightness_image.cpp

void gammaCorrection(const Mat &img, const double gamma_)
{
CV_Assert(gamma_ >= 0);
//! [changing-contrast-brightness-gamma-correction]
Mat lookUpTable(1, 256, CV_8U);
uchar* p = lookUpTable.ptr();
for( int i = 0; i < 256; ++i)
p[i] = saturate_cast<uchar>(pow(i / 255.0, gamma_) * 255.0);

Mat res = img.clone();
LUT(img, lookUpTable, res);
//! [changing-contrast-brightness-gamma-correction]
//这里是把原图和处理后的图左右拼到一起形成对比图
hconcat(img, res, img_gamma_corrected);
imshow("Gamma correction", img_gamma_corrected);
}