这也许是我复现的所有论文中效果最好的了吧

这也许是我见过最好用的低照度图片了吧🦄

1

This is probably the best result I’ve reproduced from all the papers

This is probably the best low-light image enhancement I’ve ever seen🦄

1

开始之前,背景音乐先安排上。

Before we start, let’s get some background music going.

这篇博客介绍一下论文中的方法,目的不是让除了我以外的人能看懂,因为我也做不到让别人能读懂😓,大概就算是阅读笔记吧。欲知方法细节,查看论文原文.

方法简介

流程图

image-20210128171926493

算法共分为以下几个步骤:

  1. 提取 Y 通道。
  2. 根据 Y 通道图的直方图分布情况分别求出两个 γ\gamma ,使其分别有效作用于暗区和亮区域。
  3. 使用 DoG 函数对伽马校正结果图进行局部对比度增强。
  4. 对增强结果进行自适应的线性加权融合。
  5. 利用 Y 通道的融合结果对图像进行色彩校正得到最终的结果图。

提取 Y 通道

Lin (x,y)=0.299Iin R(x,y)+0.587Iin G(x,y)+0.114Iin B(x,y)\begin{aligned} L_{\text {in }}(x, y)=0.299 \cdot I_{\text {in }}^{R}(x, y)+0.587 & \cdot I_{\text {in }}^{G}(x, y) + 0.114 \cdot I_{\text {in }}^{B}(x, y) \end{aligned}

对 Y 通道进行对数归一化:

Llog(x,y)=logα(Lin(x,y)+1)L_{\log }(x, y)=\log _{\alpha}\left(L_{i n}(x, y)+1\right)

其中:

α=max(Lin(x,y))+1\alpha = max(L_{in}(x,y)) + 1

自适应伽马校正

首先,以 0.5 为阈值将对数归一化后的 Y 通道分为亮区域和暗区域两个部分,即大于 0.5 的像素值被划分在亮区域,小于或等于 0.5 的像素被划分在暗区域。

分别根据亮区域和暗区域的标准差来计算 期望中位数,再通过全局搜索的方式寻找两个 γ\gamma 使得经过伽马校正后的图像最接近期望中位数。

以下为暗区和亮区期望中位数的计算方法:

ML=13+σLMH=1σH\begin{array}{l} M_{L}=\frac{1}{3}+\sigma_{L} \\ M_{H}=1-\sigma_{H} \end{array}

其中:L 下标表示暗区;H 下标表示亮区。

两个 γ\gamma 的全局搜索方法如下:

γL=argminγi(med(Sdark γi)ML)γi{0.1,0.11,,1}γH=argmin(med(Sbright γi)MH)γiγi{1,1.1,,10}\begin{array}{r} \gamma_{L}=\underset{\gamma_{i}}{\arg \min }\left(\left|\operatorname{med}\left(S_{\text {dark }}^{\gamma_{i}}\right)-M_{L}\right|\right) \\ \gamma_{i} \in\{0.1,0.11, \ldots, 1\} \\ \gamma_{H}=\underset{\gamma_{i}}{\arg \min \left(\left|\operatorname{med}\left(S_{\text {bright }}^{\gamma_{i}}\right)-M_{H}\right|\right)} \\ \gamma_{i} \in\{1,1.1, \ldots, 10\} \end{array}

其中:med()med(·) 是中位数算子。SdarkγiS_{dark}^{\gamma_i} 表示的是 Llog(x,y)γi0.5L_{log}(x,y)^{\gamma _i} \le 0.5 的像素值。

分别使用以上两个 γ\gamma 对输入图像进行伽马校正,得到亮区结果和暗区结果。

Ld(x,y)=(Llog(x,y))γLLb(x,y)=(Llog(x,y))γH\begin{array}{l} L_{d}(x, y)=\left(L_{\log }(x, y)\right)^{\gamma_{L}} \\ L_{b}(x, y)=\left(L_{\log }(x, y)\right)^{\gamma_{H}} \end{array}

局部对比度增强

使用 DoG 模型分别作用于亮区校正结果图和暗区校正结果图,实现图像的对比度增强。具体方法为:

Ld(x,y)=Ld(x,y)+(LdDoGσc,σs)(x,y)Lb(x,y)=Lb(x,y)+(LbDoGσc,σs)(x,y)DoGσc,σs(x,y)=12πσc2exp(x2+y22σc2)12πσs2exp(x2+y22σs2)\begin{aligned} L_{d}^{\prime}(x, y)=& L_{d}(x, y)+\left(L_{d} * D o G_{\sigma_{c}, \sigma_{s}}\right)(x, y) \\ L_{b}^{\prime}(x, y)=& L_{b}(x, y)+\left(L_{b} * D o G_{\sigma_{c}, \sigma_{s}}\right)(x, y) \\ D o G_{\sigma_{c}, \sigma_{s}}(x, y)=& \frac{1}{2 \pi \sigma_{c}^{2}} \exp \left(-\frac{x^{2}+y^{2}}{2 \sigma_{c}^{2}}\right) -\frac{1}{2 \pi \sigma_{s}^{2}} \exp \left(-\frac{x^{2}+y^{2}}{2 \sigma_{s}^{2}}\right) \end{aligned}

自适应融合

这里使用一种依赖于亮度的自适应线性加权融合方法。

其权重的计算方式为:

w(x,y)=exp(Lb(x,y)22σw2)w(x, y)=\exp \left(-\frac{L_{b}(x, y)^{2}}{2 \sigma_{w}^{2}}\right)

此处设置 σw=0.5\sigma_w = 0.5

融合方法为:

Lout (x,y)=w(x,y)Ld(x,y)+(1w(x,y))Lb(x,y)L_{\text {out }}(x, y)=w(x, y) \cdot L_{d}^{\prime}(x, y)+(1-w(x, y)) \cdot L_{b}^{\prime}(x, y)

另外,此处对输出结果进行了一步线性归一化操作。

自适应的色彩恢复

此处依然是一种亮度依赖的自适应方法。

Iout c(x,y)=Lout (x,y)(Iinc(x,y)Lin (x,y))s(x,y)s(x,y)=1tanh(Lb(x,y))\begin{aligned} I_{\text {out }}^{c}(x, y) &=L_{\text {out }}(x, y)\left(\frac{I_{i n}^{c}(x, y)}{L_{\text {in }}(x, y)}\right)^{s(x, y)} \\ s(x, y) &=1-\tanh \left(L_{b}(x, y)\right) \end{aligned}

This blog post introduces the method in the paper. The purpose is not to make it understandable to anyone but me, because I can’t make others understand it anyway😓. It’s basically reading notes. For method details, see the original paper.

Method Overview

Flowchart

image-20210128171926493

The algorithm consists of the following steps:

  1. Extract the Y channel.
  2. Based on the histogram distribution of the Y channel image, compute two γ\gamma values respectively, making them work effectively on the dark and bright regions.
  3. Use the DoG function for local contrast enhancement on the gamma-corrected result image.
  4. Perform adaptive linear weighted fusion on the enhanced results.
  5. Use the fused result of the Y channel for color correction to obtain the final result image.

Extracting the Y Channel

Lin (x,y)=0.299Iin R(x,y)+0.587Iin G(x,y)+0.114Iin B(x,y)\begin{aligned} L_{\text {in }}(x, y)=0.299 \cdot I_{\text {in }}^{R}(x, y)+0.587 & \cdot I_{\text {in }}^{G}(x, y) + 0.114 \cdot I_{\text {in }}^{B}(x, y) \end{aligned}

Log-normalize the Y channel:

Llog(x,y)=logα(Lin(x,y)+1)L_{\log }(x, y)=\log _{\alpha}\left(L_{i n}(x, y)+1\right)

where:

α=max(Lin(x,y))+1\alpha = max(L_{in}(x,y)) + 1

Adaptive Gamma Correction

First, using 0.5 as the threshold, the log-normalized Y channel is divided into two parts: the bright region and the dark region. Pixels greater than 0.5 are classified into the bright region, and pixels less than or equal to 0.5 are classified into the dark region.

The expected median is computed from the standard deviations of the bright and dark regions respectively, and then two γ\gamma values are found by global search so that the gamma-corrected image is closest to the expected median.

The expected medians for the dark and bright regions are computed as follows:

ML=13+σLMH=1σH\begin{array}{l} M_{L}=\frac{1}{3}+\sigma_{L} \\ M_{H}=1-\sigma_{H} \end{array}

where the subscript L denotes the dark region and the subscript H denotes the bright region.

The global search for the two γ\gamma values is as follows:

γL=argminγi(med(Sdark γi)ML)γi{0.1,0.11,,1}γH=argmin(med(Sbright γi)MH)γiγi{1,1.1,,10}\begin{array}{r} \gamma_{L}=\underset{\gamma_{i}}{\arg \min }\left(\left|\operatorname{med}\left(S_{\text {dark }}^{\gamma_{i}}\right)-M_{L}\right|\right) \\ \gamma_{i} \in\{0.1,0.11, \ldots, 1\} \\ \gamma_{H}=\underset{\gamma_{i}}{\arg \min \left(\left|\operatorname{med}\left(S_{\text {bright }}^{\gamma_{i}}\right)-M_{H}\right|\right)} \\ \gamma_{i} \in\{1,1.1, \ldots, 10\} \end{array}

where med()med(·) is the median operator, and SdarkγiS_{dark}^{\gamma_i} denotes the pixel values with Llog(x,y)γi0.5L_{log}(x,y)^{\gamma _i} \le 0.5.

Use the two γ\gamma values above to apply gamma correction to the input image, obtaining the bright-region result and the dark-region result.

Ld(x,y)=(Llog(x,y))γLLb(x,y)=(Llog(x,y))γH\begin{array}{l} L_{d}(x, y)=\left(L_{\log }(x, y)\right)^{\gamma_{L}} \\ L_{b}(x, y)=\left(L_{\log }(x, y)\right)^{\gamma_{H}} \end{array}

Local Contrast Enhancement

Apply the DoG model to both the bright-region corrected result image and the dark-region corrected result image to enhance image contrast. Specifically:

Ld(x,y)=Ld(x,y)+(LdDoGσc,σs)(x,y)Lb(x,y)=Lb(x,y)+(LbDoGσc,σs)(x,y)DoGσc,σs(x,y)=12πσc2exp(x2+y22σc2)12πσs2exp(x2+y22σs2)\begin{aligned} L_{d}^{\prime}(x, y)=& L_{d}(x, y)+\left(L_{d} * D o G_{\sigma_{c}, \sigma_{s}}\right)(x, y) \\ L_{b}^{\prime}(x, y)=& L_{b}(x, y)+\left(L_{b} * D o G_{\sigma_{c}, \sigma_{s}}\right)(x, y) \\ D o G_{\sigma_{c}, \sigma_{s}}(x, y)=& \frac{1}{2 \pi \sigma_{c}^{2}} \exp \left(-\frac{x^{2}+y^{2}}{2 \sigma_{c}^{2}}\right) -\frac{1}{2 \pi \sigma_{s}^{2}} \exp \left(-\frac{x^{2}+y^{2}}{2 \sigma_{s}^{2}}\right) \end{aligned}

Adaptive Fusion

Here, an adaptive linear weighted fusion method that depends on brightness is used.

The weight is computed as follows:

w(x,y)=exp(Lb(x,y)22σw2)w(x, y)=\exp \left(-\frac{L_{b}(x, y)^{2}}{2 \sigma_{w}^{2}}\right)

Here σw=0.5\sigma_w = 0.5 is set.

The fusion method is:

Lout (x,y)=w(x,y)Ld(x,y)+(1w(x,y))Lb(x,y)L_{\text {out }}(x, y)=w(x, y) \cdot L_{d}^{\prime}(x, y)+(1-w(x, y)) \cdot L_{b}^{\prime}(x, y)

In addition, a linear normalization step is applied to the output here.

Adaptive Color Restoration

This is again a brightness-dependent adaptive method.

Iout c(x,y)=Lout (x,y)(Iinc(x,y)Lin (x,y))s(x,y)s(x,y)=1tanh(Lb(x,y))\begin{aligned} I_{\text {out }}^{c}(x, y) &=L_{\text {out }}(x, y)\left(\frac{I_{i n}^{c}(x, y)}{L_{\text {in }}(x, y)}\right)^{s(x, y)} \\ s(x, y) &=1-\tanh \left(L_{b}(x, y)\right) \end{aligned}

Matlab实现

分区

分区操作只需要记录亮区像素和暗区像素的值就可以,因此此处采用遍历图像的方式对每个像素点进行判断,大于0.5 则加入亮区数组,否则加入暗区数组。

Matlab Implementation

Partitioning

The partitioning operation only needs to record the values of the bright and dark pixels, so the image is traversed and each pixel is judged: if it is greater than 0.5, it is added to the bright array; otherwise, it is added to the dark array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function [Ld,Lb] = fen_qu(Lin)
i = 1;
j = 1;
[m,n] = size(Lin);
Ld = 0;
Lb = 0;
for k = 1:m*n
x = Lin(k);
if x <= 0.5
Ld(i) = x;
i = i + 1;
end
if x > 0.5
Lb(j) = x;
j = j + 1;
end
end
end

DoG 算子

DoG 算子实际上就是两个高斯函数的差,因此这里先实现一个二维的高斯函数。

二维高斯函数也可以使用 Matlab 内置函数fspecial来实现。

The DoG Operator

The DoG operator is actually the difference of two Gaussian functions, so a 2D Gaussian function is implemented first.

A 2D Gaussian function can also be implemented with the built-in Matlab function fspecial.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function gaussFun = GaussFun2D(hsize) 

% sigma = double(hsize)/6.0; % 3*sigma = radius, i.e., 6*sigma = diameter (hsize)
% gaussFun = fspecial('gaussian',hsize,sigma);

gaussFun = zeros(hsize,hsize);
rr = (hsize+1)/2;
%rr = (hsize-1)/2;
for i=1:hsize
for j=1:hsize
tmpV = (i-rr)*(i-rr) + (j-rr)*(j-rr);
gaussFun(i,j) = exp(-9.0*tmpV/rr/rr);
%gaussFun(i,j) = exp(-4.5*tmpV/rr/rr);
%sigma = rr/3;
%gaussFun(i,j) = exp(-tmpV/(2*sigma*sigma))/(2*pi*sigma*sigma);
end
end
end

DoG 算子的实现如下:

The implementation of the DoG operator is as follows:

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
28
29
30
31
32
33
34
35
36
37
38
39
function outImg = DoG(Img,rr_RF,rr_IF,m_qA1,m_qA2,antImg)

th1 = 2*rr_RF + 1;
hsize = th1;
pa_gauss1 = GaussFun2D(hsize);
for i=1:th1
for j=1:th1
di = i-rr_RF-1;
dj = j-rr_RF-1;
tmpV = di*di + dj*dj;
if tmpV>rr_RF*rr_RF
pa_gauss1(i,j) = 0.0;
end
end
end
pa_gauss1 = m_qA1*pa_gauss1/sum(sum(pa_gauss1));


th2 = 2*rr_IF + 1;
hsize = th2;
pa_gauss2 = GaussFun2D(hsize);
for i=1:th2
for j=1:th2
di = i-rr_IF-1;
dj = j-rr_IF-1;
tmpV = di*di + dj*dj;
if tmpV>rr_IF*rr_IF || tmpV<=rr_RF*rr_RF
pa_gauss2(i,j) = 0.0;
end
end
end
pa_gauss2 = m_qA2*pa_gauss2/sum(sum(pa_gauss2));

SurroundImgLists = imfilter(antImg,pa_gauss2,'conv','symmetric');
CenterImgLists = imfilter(Img,pa_gauss1,'conv','symmetric');

outImg = CenterImgLists - SurroundImgLists;
outImg(outImg<0.0) = 0.0;
end

线性归一化

Linear Normalization

1
2
3
4
5
function [outputs] = Normalization(arg)
MAX = max(arg(:));
MIN = min(arg(:));
outputs = (arg - MIN)./ (MAX - MIN);
end

其他操作

最后,将其他操作写在主函数中,详见代码注释。

Other Operations

Finally, the remaining operations are written in the main function; see the code comments for details.

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
function outputs = main(input)
I = im2double(input);
R = I(:,:,1);
G = I(:,:,2);
B = I(:,:,3);

% 计算 Y 通道
Lin = 0.299*R + 0.587*G +0.114*B;

% 对数归一化
alpha = max(max(Lin)) + 1;
Llog = log(Lin + 1) / log(alpha);

% 计算期望中位数
[Ld , Lb] = fen_qu(Llog);
ML = 1/3 + std(Ld);
MH = 1 - std(Lb);

% 搜索最优 γ
Min1 = zeros(1,91);
Min2 = zeros(1,91);
k = 1;
for i = 0.1:0.01:1
clear Ld
[Ld , ~] = fen_qu(Llog.^i);
Min1(k) = abs(median(Ld) - ML);
k = k + 1;
end
k = 1;
for i = 1:0.1:10
clear Lb
[~ , Lb] = fen_qu(Llog.^i);
Min2(k) = abs(median(Lb) - MH);
k = k + 1;
end
gamma_L = (find(Min1 == min(Min1)) - 1) * 0.01 + 0.1;
gamma_H = (find(Min2 == min(Min2)) - 1) * 0.1 + 1;

% 伽马校正
Ld = Llog .^ gamma_L;
Lb = Llog .^ gamma_H;

% 局部对比度增强
Ld_p = Ld + DoG(Ld,1,3,1,1,Ld);
Lb_p = Lb + DoG(Lb,1,3,1,1,Lb);

% 自适应权重计算与图像融合
w = exp(-(Lb.^2)./(2*0.5*0.5));
L_out = w .* Ld_p + (1-w) .* Lb_p;
L_out = Normalization(L_out);

% 自适应色彩恢复
s = 1 - tanh(Lb);

R_out = L_out .* ((R ./ Lin).^s);
G_out = L_out .* ((G ./ Lin).^s);
B_out = L_out .* ((B ./ Lin).^s);

% 输出
outputs = cat(3,R_out,G_out,B_out);
end

几张低照度图像

左为原图,右为结果图。

01

1

02

03

4

5

703

785

Some Low-Light Images

Left is the original image, right is the result image.

01

1

02

03

4

5

703

785

几张水下图像

左为原图,右为结果图。

10

57

9

184

8

7

910

41

Some Underwater Images

Left is the original image, right is the result image.

10

57

9

184

8

7

910

41