论文阅读:Fast Single Image Dehazing Using Saturation Based Transmission Map Estimation

论文题目及作者
代码在文末给出,因为只有一个py文件。该代码是作者给出的。

1. 提出的方法

1.1 大气散射模型

    大气散射模型:
H ( x ) = t ( x ) J ( x ) + [ 1 − t ( x ) ] A (1) \mathbf{H}(x)=t(x) \mathbf{J}(x)+[1-t(x)] \mathbf{A} \tag{1} H(x)=t(x)J(x)+[1t(x)]A(1)

    移项整理后:
J ( x ) = D ( H ( x ) , A , t ( x ) ) = H ( x ) − A t ( x ) + A (2) \mathbf{J}(x)=D(\mathbf{H}(x), \mathbf{A}, t(x))=\frac{\mathbf{H}(x)-\mathbf{A}}{t(x)}+\mathbf{A} \tag{2} J(x)=D(H(x),A,t(x))=t(x)H(x)A+A(2)

    这里雾图使用 H ( x ) \mathbf{H}(x) H(x)而不是 I ( x ) \mathbf{I}(x) I(x),因为后面会用到 I I I的符号。

1.2 传输率图公式

    给定 A \mathbf{A} A的情况下,用 A \mathbf{A} A归一化 ( 1 ) (1) (1)得:
H c ( x ) A c = t ( x ) J c ( x ) A c + 1 − t ( x ) , c ∈ { r , g , b } (3) \frac{H^{c}(x)}{A^{c}}=t(x) \frac{J^{c}(x)}{A^{c}}+1-t(x), c \in\{r, g, b\} \tag{3} AcHc(x)=t(x)AcJc(x)+1t(x),c{r,g,b}(3)

    两边对通道求最小值操作,得到:
min ⁡ c H n c = t ( x ) min ⁡ c J n c + 1 − t ( x ) (4) \min _{c} H_{n}^{c}=t(x) \min _{c} J_{n}^{c}+1-t(x) \tag{4} cminHnc=t(x)cminJnc+1t(x)(4)

    其中, H n c ( x ) = H c ( x ) A c H_{n}^{c}(x)=\frac{H^{c}(x)}{A^{c}} Hnc(x)=AcHc(x) J n c ( x ) = J c ( x ) A c J_{n}^{c}(x)=\frac{J^{c}(x)}{A^{c}} Jnc(x)=AcJc(x)。移项整理后得:
t ( x ) = 1 − m H n ( x ) 1 − m J n ( x ) (5) t(x)=\frac{1-m_{\mathbf{H}_{n}}(x)}{1-m_{\mathbf{J}_{n}}(x)} \tag{5} t(x)=1mJn(x)1mHn(x)(5)

    其中, m H n ( x ) = min ⁡ c H n c ( x ) m_{\mathbf{H}_{n}}(x)=\min\limits_{c} H_{n}^{c}(x) mHn(x)=cminHnc(x) m J n ( x ) = min ⁡ c J n c ( x ) m_{\mathbf{J}_{n}}(x)=\min\limits_{c} J_{n}^{c}(x) mJn(x)=cminJnc(x)。下图展示了本文提出的 m J n ( x ) m_{\mathbf{J}_{n}}(x) mJn(x)和暗通道先验中,清晰图像用 A \mathbf{A} A归一化的结果。
大气光归一化结果

图1 大气光归一化结果

1.3 传输率图估计

    定义饱和度公式:给定一幅图像 K ( x ) \mathbf{K}(x) K(x),像素点 x x x的饱和度定义为 S K ( x ) S_{\mathbf{K}}(x) SK(x)。公式如下:
S K ( x ) = 1 − m K ( x ) I K ( x ) (6) S_{\mathbf{K}}(x)=1-\frac{m_{\mathbf{K}}(x)}{I_{\mathbf{K}}(x)} \tag{6} SK(x)=1IK(x)mK(x)(6)

    其中, m K ( x ) = min ⁡ c ∈ { r , g , b } K c ( x ) m_{\mathbf{K}}(x)=\min\limits_{c \in\{r, g, b\}} K^{c}(x) mK(x)=c{r,g,b}minKc(x) I K ( x ) I_{\mathbf{K}}(x) IK(x) K ( x ) \mathbf{K}(x) K(x)的强度,定义为:
I K ( x ) = K r ( x ) + K g ( x ) + K b ( x ) 3 (7) I_{\mathbf{K}}(x)=\frac{K^{r}(x)+K^{g}(x)+K^{b}(x)}{3} \tag{7} IK(x)=3Kr(x)+Kg(x)+Kb(x)(7)

     ( 6 ) (6) (6)移项整理得到 m K ( x ) = I K ( x ) ( 1 − S K ( x ) ) m_{\mathbf{K}}(x)=I_{\mathbf{K}}(x)\left(1-S_{\mathbf{K}}(x)\right) mK(x)=IK(x)(1SK(x)),用该形式重写 ( 5 ) (5) (5)得:
t ( x ) = 1 − I H n ( x ) ( 1 − S H n ( x ) ) 1 − I J n ( x ) ( 1 − S J n ( x ) ) (8) t(x)=\frac{1-I_{\mathbf{H}_{n}}(x)\left(1-S_{\mathbf{H}_{n}}(x)\right)}{1-I_{\mathbf{J}_{n}}(x)\left(1-S_{\mathbf{J}_{n}}(x)\right)} \tag{8} t(x)=1IJn(x)(1SJn(x))1IHn(x)(1SHn(x))(8)

    由上可知,传输率图可以通过归一化场景辐射的强度和饱和度来确定。两个未知数( I J n ( x ) I_{\mathbf{J}_{n}}(x) IJn(x) S J n ( x ) S_{\mathbf{J}_{n}}(x) SJn(x))用于估计 t ( x ) t(x) t(x)
    用 A \mathbf{A} A归一化 ( 2 ) (2) (2),加入强度定义 ( 7 ) (7) (7)得到:
I J n ( x ) = I H n ( x ) − 1 t ( x ) + 1 (9) I_{\mathbf{J}_{n}}(x)=\frac{I_{\mathbf{H}_{n}}(x)-1}{t(x)}+1 \tag{9} IJn(x)=t(x)IHn(x)1+1(9)

J ( x ) = H ( x ) − A t ( x ) + A (2) \mathbf{J}(x)=\frac{\mathbf{H}(x)-\mathbf{A}}{t(x)}+\mathbf{A} \tag{2} J(x)=t(x)H(x)A+A(2)

    用 A \mathbf{A} A归一化:
J c ( x ) A c = H c ( x ) A c − 1 t ( x ) + 1 \frac{{J}^c(x)}{A^c} = \frac{\frac{{H}^c(x)}{A^c} - 1}{t(x)} + 1 AcJc(x)=t(x)AcHc(x)1+1

    加入定义 J n c ( x ) = J c ( x ) A c J_{n}^{c}(x)=\frac{J^{c}(x)}{A^{c}} Jnc(x)=AcJc(x) H n c ( x ) = H c ( x ) A c H_{n}^{c}(x)=\frac{H^{c}(x)}{A^{c}} Hnc(x)=AcHc(x)得:
J n c ( x ) = H n c ( x ) − 1 t ( x ) + 1 J_n^c(x) = \frac{H_n^c(x) - 1}{t(x)} + 1 Jnc(x)=t(x)Hnc(x)1+1

    三个通道:
J n r ( x ) = H n r ( x ) − 1 t ( x ) + 1 J_n^r(x) = \frac{H_n^r(x) - 1}{t(x)} + 1 Jnr(x)=t(x)Hnr(x)1+1

J n g ( x ) = H n g ( x ) − 1 t ( x ) + 1 J_n^g(x) = \frac{H_n^g(x) - 1}{t(x)} + 1 Jng(x)=t(x)Hng(x)1+1

J n b ( x ) = H n b ( x ) − 1 t ( x ) + 1 J_n^b(x) = \frac{H_n^b(x) - 1}{t(x)} + 1 Jnb(x)=t(x)Hnb(x)1+1

    上面那三个式子相加,加入 ( 7 ) (7) (7)的定义得:
3 I J n ( x ) = 3 I H n ( x ) − 3 t ( x ) + 3 3I_{\mathbf{J}_{n}}(x)=\frac{3I_{\mathbf{H}_{n}}(x)-3}{t(x)}+3 3IJn(x)=t(x)3IHn(x)3+3

    化简得 ( 9 ) (9) (9)

    将 ( 9 ) (9) (9)带入 ( 8 ) (8) (8)中,得:
t ( x ) = 1 − I H n ( x ) ( 1 − S H n ( x ) ) 1 − ( I H n ( x ) − 1 t ( x ) + 1 ) ( 1 − S J n ( x ) ) (10) t(x)=\frac{1-I_{\mathbf{H}_{n}}(x)\left(1-S_{\mathbf{H}_{n}}(x)\right)}{1-(\frac{I_{\mathbf{H}_{n}}(x)-1}{t(x)}+1)\left(1-S_{\mathbf{J}_{n}}(x)\right)} \tag{10} t(x)=1(t(x)IHn(x)1+1)(1SJn(x))1IHn(x)(1SHn(x))(10)

    化简得:
t ( x ) = 1 − I H n ( x ) ( 1 − S H n ( x ) S J n ( x ) ) (11) t(x)=1-I_{\mathbf{H}_{n}}(x)\left(1-\frac{S_{\mathbf{H}_{n}}(x)}{S_{\mathbf{J}_{n}}(x)}\right) \tag{11} t(x)=1IHn(x)(1SJn(x)SHn(x))(11)

     ( 10 ) (10) (10)移项:
t ( x ) − ( I H n ( x ) − 1 + t ( x ) ) ( 1 − S J n ( x ) ) = 1 − I H n ( x ) ( 1 − S H n ( x ) ) t(x) - (I_{\mathbf{H}_{n}}(x)-1 + t(x))(1-S_{\mathbf{J}_{n}}(x)) = 1-I_{\mathbf{H}_{n}}(x)(1-S_{\mathbf{H}_{n}}(x)) t(x)(IHn(x)1+t(x))(1SJn(x))=1IHn(x)(1SHn(x))

t ( x ) ( 1 − ( 1 − S J n ( x ) ) ) − ( I H n ( x ) − 1 ) ( 1 − S J n ( x ) ) = 1 − I H n ( x ) ( 1 − S H n ( x ) ) t(x)(1 - (1 - S_{\mathbf{J}_{n}}(x))) - (I_{\mathbf{H}_{n}}(x)-1)(1 - S_{\mathbf{J}_{n}}(x)) = 1-I_{\mathbf{H}_{n}}(x)(1-S_{\mathbf{H}_{n}}(x)) t(x)(1(1SJn(x)))(IHn(x)1)(1SJn(x))=1IHn(x)(1SHn(x))

t ( x ) S J n ( x ) =   1 − I H n ( x ) ( 1 − S H n ( x ) ) + I H n ( x ) ( 1 − S J n ( x ) ) − ( 1 − S J n ( x ) ) =   S J n ( x ) − I H n ( S J n ( x ) − S H n ( x ) ) \begin{aligned} t(x)S_{\mathbf{J}_{n}}(x) =& \ 1- I_{\mathbf{H}_{n}}(x)(1-S_{\mathbf{H}_{n}}(x)) + I_{\mathbf{H}_{n}}(x)(1-S_{\mathbf{J}_{n}}(x)) - (1-S_{\mathbf{J}_{n}}(x)) \\ =& \ S_{\mathbf{J}_{n}}(x) - I_{\mathbf{H}_{n}} (S_{\mathbf{J}_{n}}(x) - S_{\mathbf{H}_{n}}(x)) \end{aligned} t(x)SJn(x)== 1IHn(x)(1SHn(x))+IHn(x)(1SJn(x))(1SJn(x)) SJn(x)IHn(SJn(x)SHn(x))

    两边乘以 S J n ( x ) S_{\mathbf{J}_{n}}(x) SJn(x) ( 11 ) (11) (11)

    有了 ( 11 ) (11) (11),未知单元就只剩下 S J n ( x ) S_{\mathbf{J}_{n}}(x) SJn(x)。估计 S J n ( x ) S_{\mathbf{J}_{n}}(x) SJn(x)比估计 m J ( x ) m_{\mathbf{J}}(x) mJ(x)要简单得多。

1.4 估计场景辐射得饱和度

     ( 11 ) (11) (11)移项变形后得:
S H n ( x ) = t ( x ) I J n ( x ) I H n ( x ) S J n ( x ) (12) S_{\mathbf{H}_{n}}(x)=t(x) \frac{I_{\mathbf{J}_{n}}(x)}{I_{\mathbf{H}_{n}}(x)} S_{\mathbf{J}_{n}}(x) \tag{12} SHn(x)=t(x)IHn(x)IJn(x)SJn(x)(12)

     I H n ( x ) {I_{\mathbf{H}_{n}}(x)} IHn(x) I J n ( x ) {I_{\mathbf{J}_{n}}(x)} IJn(x)的关系通过 ( 9 ) (9) (9)可得:
I H n ( x ) = t ( x ) I J n ( x ) + 1 − t ( x ) (13) I_{\mathbf{H}_{n}}(x)=t(x) I_{\mathbf{J}_{n}}(x)+1-t(x) \tag{13} IHn(x)=t(x)IJn(x)+1t(x)(13)

    因为 0 ≤ t ( x ) ≤ 1 0 \le t(x) \le 1 0t(x)1,从 ( 12 ) ( 13 ) (12)(13) (12)(13)可得 I J n ( x ) ≤ I H n ( x ) I_{\mathbf{J}_{n}}(x) \leq I_{\mathbf{H}_{n}}(x) IJn(x)IHn(x) S J n ( x ) ≥ S H n ( x ) S_{\mathbf{J}_{n}}(x) \geq S_{\mathbf{H}_{n}}(x) SJn(x)SHn(x)

    由 ( 13 ) (13) (13) 0 ≤ t ( x ) ≤ 1 0 \le t(x) \le 1 0t(x)1得:
t ( x ) = I H n ( x ) − 1 I J n ( x ) − 1 ≤ 1 t(x) = \frac{I_{\mathbf{H}_{n}}(x) - 1}{I_{\mathbf{J}_{n}}(x) - 1} \le 1 t(x)=IJn(x)1IHn(x)11

    因为 I H n ( x ) I_{\mathbf{H}_{n}}(x) IHn(x) I J n ( x ) I_{\mathbf{J}_{n}}(x) IJn(x)都已归一化,即 0 ≤ I H n ( x ) , I J n ( x ) ≤ 1 0 \le I_{\mathbf{H}_{n}}(x), I_{\mathbf{J}_{n}}(x) \le 1 0IHn(x),IJn(x)1。所以 I J n ( x ) ≤ I H n ( x ) I_{\mathbf{J}_{n}}(x) \leq I_{\mathbf{H}_{n}}(x) IJn(x)IHn(x),结合 ( 12 ) (12) (12)得: S J n ( x ) ≥ S H n ( x ) S_{\mathbf{J}_{n}}(x) \geq S_{\mathbf{H}_{n}}(x) SJn(x)SHn(x)

    通过以上推导,可知雾图的饱和度小于清晰图像的饱和度。本文通过将雾图的饱和度进行拉伸得到清晰图像的饱和度。文中给出了三种饱和度拉伸的方法,分别如下:

  1. 拉伸函数1
    τ ( z , p ) = { 0.5 ( 1 − ( 1 − z 0.5 ) p ) , z ≤ 0.5 0.5 + 0.5 ( z − 0.5 0.5 ) 2 , 0.5 < z ≤ 1 (14) \tau(z, p)=\left\{\begin{array}{ll} 0.5\left(1-\left(1-\frac{z}{0.5}\right)^{p}\right), & z \leq 0.5 \\ 0.5+0.5\left(\frac{z-0.5}{0.5}\right)^{2}, & 0.5<z \leq 1 \end{array}\right. \tag{14} τ(z,p)={0.5(1(10.5z)p),0.5+0.5(0.5z0.5)2,z0.50.5<z1(14)

    其中, τ ( z , p ) \tau(z, p) τ(z,p)是关于 z z z自适应的拉伸函数, p ( p > 0 ) p(p > 0) p(p>0)为功率常数。

  1. 拉伸函数2
    q ( z ) = z ( 2 − z ) (15) q(z)=z(2-z) \tag{15} q(z)=z(2z)(15)

    在 ( 15 ) (15) (15)中, q ( z ) q(z) q(z) z z z的二次函数,在 z = 1 z = 1 z=1时最大值为 1 1 1

  1. 拉伸函数3
    η ( z , γ ) = ( z 1 γ + ( 1 − ( 1 − z ) 1 γ ) ) 2 (16) \eta(z, \gamma)=\frac{\left(z^{\frac{1}{\gamma}}+\left(1-(1-z)^{\frac{1}{\gamma}}\right)\right)}{2} \tag{16} η(z,γ)=2(zγ1+(1(1z)γ1))(16)

     γ \gamma γ为决定 η ( z , γ ) \eta(z, \gamma) η(z,γ)形状的常数。
    图2显示了三个拉伸函数的示例。图2(a)展示了这些拉伸函数的曲线图。在图2(b)中,展示了一幅雾图及其灰度图,以及三种对灰度图不同拉伸函数的结果图。
三种拉伸函数

图2 三种拉伸函数

    图3展示了使用各种拉伸函数的去雾图像。如图3所示,去雾结果在很大程度上不取决于拉伸功能。
三种拉伸函数的去雾结果

图3 三种拉伸函数的去雾结果

1.5 处理颜色偏色

     通常,假定三个通道大气光值都是相似的,所以雾几乎没有颜色成分,假定所有大气光都是相似的。但是,黄色的粉尘或某些照明条件下可能会使雾带有颜色偏色。图5展示了颜色偏色的情况。颜色偏色的情况下,去雾效果并不理想。
大气光偏色情况

图4 大气光偏色情况

    本文提出了一种使用白平衡方法的简单的偏色去除算法。 H ( x ) \mathbf{H}(x) H(x)白平衡处理后的结果 H W B ( x ) \mathbf{H}_{WB}(x) HWB(x)通过下式获得:
H W B c ( x ) = W ( H c ( x ) ) = μ ( H g ( x ) ) μ ( H c ( x ) ) H c ( x ) (17) H_{W B}^{c}(x)=W\left(H^{c}(x)\right)=\frac{\mu\left(H^{g}(x)\right)}{\mu\left(H^{c}(x)\right)} H^{c}(x) \tag{17} HWBc(x)=W(Hc(x))=μ(Hc(x))μ(Hg(x))Hc(x)(17)

    其中, μ ( H c ( x ) ) \mu(H^{c}(x)) μ(Hc(x)) H c ( x ) H^{c}(x) Hc(x)的均值, W ( ⋅ ) W(\cdot) W()为白平衡函数。
    经过白平衡处理后,得到白平衡雾图 H W B ( x ) \mathbf{H}_{WB}(x) HWB(x)。该图的大气光值为 A W B \mathbf{A}_{WB} AWB。如果 A \mathbf{A} A A W B \mathbf{A}_{WB} AWB有较大偏差,说明雾是有偏色的。因此,比较 A \mathbf{A} A A W B \mathbf{A}_{WB} AWB的偏差,决定是否使用白平衡后的雾图来去雾。
    定义 Δ ( y ) \Delta(\mathbf{y}) Δ(y) y \mathbf{y} y的最大值和最小值的差值。分两种情况:

  1. Δ ( A ) ≤ Δ ( A W B ) \Delta(\mathbf{A}) \leq \Delta\left(\mathbf{A}_{W B}\right) Δ(A)Δ(AWB)
        此时,上述白平衡处理会增加 A \mathbf{A} A最大值和最小值的差值。所以不使用白平衡处理,直接使用 ( 2 ) (2) (2)得到去雾图像,即 J ( x ) = D ( H ( x ) , A , t ( x ) ) \mathbf{J}(\mathrm{x})=D(\mathbf{H}(\mathrm{x}), \mathbf{A}, \mathrm{t}(\mathrm{x})) J(x)=D(H(x),A,t(x))

  2. Δ ( A ) > Δ ( A W B ) \Delta(\mathbf{A}) > \Delta\left(\mathbf{A}_{W B}\right) Δ(A)>Δ(AWB)
        此时,由于灰度世界假设,上述白平衡处理会减少 A \mathbf{A} A最大值和最小值的差值。此时使用如下公式去雾: J ( x ) = W [ D ( H ( x ) , A W B , t ( x ) ) ] \mathbf{J}(\mathrm{x})=W\left[D\left(\mathbf{H}(\mathrm{x}), \mathbf{A}_{W B}, t(\mathrm{x})\right)\right] J(x)=W[D(H(x),AWB,t(x))]

    即,对于一幅雾图 H ( x ) \mathbf{H}(x) H(x),其去雾结果通过下面式子获得:
J ( x ) = { D ( H ( x ) , A , t ( x ) ) , Δ ( A ) ≤ Δ ( A W B ) W [ D ( H ( x ) , A W B , t ( x ) ) ] ,  otherwise  (18) \mathbf{J}(x)=\left\{\begin{array}{ll} D(\mathbf{H}(x), \mathbf{A}, t(x)), & \Delta(\mathbf{A}) \leq \Delta\left(\mathbf{A}_{W B}\right) \\ W\left[D\left(\mathbf{H}(x), \mathbf{A}_{W B}, t(x)\right)\right], & \text { otherwise } \end{array}\right. \tag{18} J(x)={D(H(x),A,t(x)),W[D(H(x),AWB,t(x))],Δ(A)Δ(AWB) otherwise (18)

    如下图5所示。对于(a), Δ ( A ) < Δ ( A W B ) \Delta(\mathbf{A}) < \Delta\left(\mathbf{A}_{W B}\right) Δ(A)<Δ(AWB),比较白平衡处理与否的结果,显然,未处理的结果更好。反之(b), Δ ( A ) > Δ ( A W B ) \Delta(\mathbf{A}) > \Delta\left(\mathbf{A}_{W B}\right) Δ(A)>Δ(AWB),白平衡处理的结果更好。从而验证了 ( 18 ) (18) (18)的正确性。
白平衡处理效果

图5 白平衡处理效果

1.6 大气光估计

    本文采用了三种不同的方法估计大气光,分别为He,Tang和quad-tree subdivision-based方法。实验结果表明,使用何种大气光估计方法,对去雾结果影响不大。如下图6所示。
三种估计大气光方法对去雾结果的影响

图6 三种估计大气光方法对去雾结果的影响

1.7 算法总结

算法总结
    由于博客的公式编号和原文不同,所以上述总结中公式编号还请查看原文。

2. 实验结果

    参考原文。

3. 读后感

    本文提出了一种传统方法,该方法简单有效。
    一句话总结:将大气散射模型通过作者定义的饱和度变换成如下形式 t ( x ) = 1 − I H n ( x ) ( 1 − S H n ( x ) S J n ( x ) ) t(x)=1-I_{\mathbf{H}_{n}}(x)\left(1-\frac{S_{\mathbf{H}_{n}}(x)}{S_{\mathbf{J}_{n}}(x)}\right) t(x)=1IHn(x)(1SJn(x)SHn(x)),再通过对 S H n ( x ) S_{\mathbf{H}_{n}}(x) SHn(x)的对比度拉伸获得唯一未知量 S J n ( x ) S_{\mathbf{J}_{n}}(x) SJn(x),从而得到传输率图。

4. 代码

# -*- coding: utf-8 -*-
"""
Created on Thu Sep 19 15:09:58 2019

@author: Se Eun Kim, Tae Hee Park, and Il Kyu
Paper: Fast Single Image Dehazing Using Saturation Based Transmission Map Estimation, 
To be appear in IEEE Transaction on Image Processing, 2020
""" 

import numpy as np
import cv2
from skimage import morphology
import math
from tkinter import filedialog
from tkinter import *
from tkinter.filedialog import askopenfilename
import time

'''
   pixel value: i2f: 0-255 to 0-1, f2i: 0-1 to 0-255 
'''
def i2f(i_image):
    f_image = np.float32(i_image)/255.0
    return f_image

def f2i(f_image):
    i_image = np.uint8(f_image*255.0)
    return i_image 

'''
    Compute 'A' as described by Tang et al. (CVPR 2014)
'''
def Compute_A_Tang(im):

    # Parameters
    erosion_window = 15
    n_bins = 200

    R = im[:, :, 2]
    G = im[:, :, 1]
    B = im[:, :, 0]
    
    # compute the dark channel
    dark = morphology.erosion(np.min(im, 2), morphology.square(erosion_window))

    [h, edges] = np.histogram(dark, n_bins)
    numpixel = im.shape[0]*im.shape[1]
    thr_frac = numpixel*0.99
    csum = np.cumsum(h)
    nz_idx = np.nonzero(csum > thr_frac)[0][0]
    dc_thr = edges[nz_idx]
    mask = dark >= dc_thr
    # similar to DCP till this step
    # next, median of these top 0.1% pixels
    # median of the RGB values of the pixels in the mask
    rs = R[mask]
    gs = G[mask]
    bs = B[mask]
    
    A = np.zeros((1,3))

    A[0, 2] = np.median(rs)
    A[0, 1] = np.median(gs)
    A[0, 0] = np.median(bs)

    return A

'''
    Compute intensity: GetIntensity, and Saturation: GetSauration
'''

def GetIntensity(fi):
    return cv2.divide(fi[:, :, 0] + fi[:, :, 1] + fi[:, :, 2], 3)
    
def GetSaturation(fi, intensity):
    min_rgb = cv2.min(cv2.min( fi[:, :, 0], fi[:, :, 1]), fi[:, :, 2])
    me = np.finfo(np.float32).eps
    S = 1.0 - min_rgb/(intensity+me)
    return S 

'''
    Estimate saturation of scene radiance: 3 memthods
    
'''
def EstimateSaturation(h_saturation, p1):
    p2 = 2.0
    k1 =0.5*(1.0-cv2.pow(1.0-2.0*h_saturation, p1))
    k2 = 0.5+0.5*cv2.pow((h_saturation-0.5)/0.5, p2)
    j_saturation = np.where(h_saturation<=0.5, k1, k2)
    j_saturation = np.maximum(j_saturation, h_saturation)     

    return j_saturation      

def EstimateSaturation_Quadratic(h_saturation):
    return h_saturation*(2.0-h_saturation)   

def EstimateSaturation_Gamma(h_saturation, g):
    j_saturation = (np.power(h_saturation, 1.0/g) +1.0- np.power(1.0-h_saturation,1.0/g))/2.0
    j_saturation = np.maximum(j_saturation, h_saturation)     
    
    return j_saturation  

'''
    Estimate Transmission Map
'''
def EstimateTransimission(h_intensity, h_saturation, j_saturation):
      
    Td = h_intensity*(j_saturation-h_saturation)
    Tmn =j_saturation
    Tmap = 1.0 - (Td/Tmn)
    me = np.finfo(np.float32).eps
    Tmap = np.clip(Tmap,me, 1.0)
    cv2.imshow('Transmission Map ', f2i(Tmap))
    cv2.waitKey()
    a=1
    return Tmap 

'''
    Recover dehazed image
'''
def Recover(im, tmap, A):
 
    res = np.empty(im.shape,im.dtype) 
    
    for ind in range(0,3):
        res[:,:,ind] = (im[:,:,ind]-A[0,ind])/tmap+A[0,ind]
        res[:,:,ind] = np.clip(res[:,:,ind], 0.0, 1.0)
   
    return res

'''
    Adjust image range
'''
def Adjust(im, perh, perl):
    aim = np.empty(im.shape,im.dtype)
    temp = np.empty(im.shape,im.dtype)
    im_h = np.percentile(im, perh)
    im_l = np.percentile(im, perl)

    for ind in range(0,3):
 
        aim[:,:,ind] = (im[:,:,ind]-im_l)/(im_h-im_l)
        temp[:,:,ind] = np.clip(aim[:,:,ind], 0.0, 1.0)
        a=1
    return aim


'''                
    Normalize image 0 between 1
'''
def Normalize(im):
    aim = np.empty(im.shape,im.dtype) 

    for ind in range(0,3):
        im_h = np.max(im[:,:,ind])
        im_l = np.min(im[:,:,ind])     
        aim[:, :, ind] = (im[:, :, ind]-im_l)/(im_h-im_l)
        aim[:,:,ind] = np.clip(aim[:,:,ind], 0.0, 1.0)     
        
    return aim

'''
   White balance using grayworld assumption
'''
def gray_world(im):
    aim = np.empty(im.shape,im.dtype) 

    mu_r = np.average(im[:,:,2])
    mu_g = np.average(im[:,:,1])
    mu_b = np.average(im[:,:,0])
    aim[:,:,0] = np.minimum(im[:,:,0]*(mu_g/mu_b),1.0)
    aim[:,:,2] = np.minimum(im[:,:,2]*(mu_g/mu_r),1.0)
    aim[:,:,1] = im[:,:,1]
 
    return  aim

'''
  CLAHE
'''
def Clahe(im, clip):
  HSV = cv2.cvtColor(f2i(im), cv2.COLOR_BGR2HSV)
  clahe = cv2.createCLAHE(clipLimit=clip, tileGridSize=(8,8))
  HSV[:, :, 2] = clahe.apply(HSV[:, :, 2])
  result_im = i2f(cv2.cvtColor(HSV, cv2.COLOR_HSV2BGR))  

  return result_im
   
'''
 Main
'''
Tk().withdraw()
filename = askopenfilename(title = 'Select input hazy image')
hazy_image = i2f(cv2.imread(filename, cv2.IMREAD_COLOR))

start_time = time.time()

A = Compute_A_Tang(hazy_image)
S_A = np.max(A)-np.min(A)

'''
  Compute white balanced A
'''
hazy_imageWB = gray_world(hazy_image)
A_WB = Compute_A_Tang(hazy_imageWB)
S_AWB = np.max(A_WB)-np.min(A_WB)

'''
  Parameter set
      parameters for Adjust: perh = 99.9, perl = 0.5 
     (for full-reference image: perh = 100, perl = 0
      parameter for selecting two branch: epsilon = 0.00 - 0.1
      parameter for CLAHE: clip size  = 1 (0-2)
'''
perh = 99.9
perl = 0.5
epsilon = 0.02
cl  = 1

if S_A < S_AWB+epsilon:
   print('Phase I - Normal')    
   hazy_imagen = np.empty(hazy_image.shape,hazy_image.dtype) 

   for ind in range(0,3):
       hazy_imagen[:,:,ind]=hazy_image[:,:,ind]/A[0,ind]   

   hazy_imagen = Normalize(hazy_imagen)       
   hazy_I = GetIntensity(hazy_imagen)
   hazy_S = GetSaturation(hazy_imagen, hazy_I)         

   '''
   Stretch function I: 0.2 (heavy haze) - 0.4 (low haze)
   Stretch function II: no parameter
   Stretch function III: 4.0 (heavy haze) - 2.0 (low haze) 
   ''' 

   est_S = EstimateSaturation_Gamma(hazy_S, 0.2)
   #est_S = EstimateSaturation_Quadratic(hazy_S)
   #est_S = EstimateSaturation(hazy_S, 2.0)   
   Transmap = EstimateTransimission(hazy_I, hazy_S, est_S)
   r_image = Recover(hazy_image,Transmap, A)
   r_image = Adjust(r_image, perh, perl)
  
else: 
   print('Phase II -White Balance')    
   hazy_imagen = np.empty(hazy_image.shape,hazy_image.dtype) 
   
   for ind in range(0,3):
       hazy_imagen[:,:,ind]=hazy_image[:,:,ind]/A_WB[0,ind]
   
   hazy_imagen = Normalize(hazy_imagen)       
   hazy_I = GetIntensity(hazy_imagen)
   hazy_S = GetSaturation(hazy_imagen, hazy_I)   

   est_S = EstimateSaturation_Gamma(hazy_S, 0.2)
   #est_S = EstimateSaturation_Quadratic(hazy_S)
   #est_S = EstimateSaturation(hazy_S, 2.0)
    
   Transmap = EstimateTransimission(hazy_I, hazy_S, est_S)
   r_image = Recover(hazy_image,Transmap, A_WB)
   r_image = Adjust(r_image, perh, perl)
   r_image = gray_world(r_image)
   
result_ce = Clahe(r_image, cl)

end_time = time.time()

print("--- %s seconds ---" %(end_time - start_time))

cv2.imwrite('result.png', f2i(r_image))
cv2.imwrite('result_ce.png', f2i(result_ce))
cv2.imwrite('trmap.png', f2i(Transmap))

(h,w) = hazy_image.shape[:2]
max_size = 800
if h>=w:
    if h>max_size:
        ns = h/max_size
        nh = int(h/ns)
        nw = int(w/ns)
    else:
        nh = h
        nw = w
        
else:
    if w>max_size:
        ns = w/max_size
        nh = int(h/ns)
        nw = int(w/ns)
    else:
        nh = h
        nw = w      

hazy_r = cv2.resize(hazy_image, (nw,nh))
trans_r = cv2.resize(Transmap, (nw,nh))
r_r = cv2.resize(r_image, (nw,nh))
ce_r = cv2.resize(result_ce, (nw,nh))

cv2.imshow('Input hazy image', f2i(hazy_r))
cv2.imshow('Transmission Map ', f2i(trans_r))
cv2.imshow('first dehazed image', f2i(r_r))
cv2.imshow('enhanced dehazed image',f2i(ce_r))
cv2.waitKey()
cv2.destroyAllWindows()
  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
dea-net是一种基于细节增强卷积和对比度的单幅图像去雾算法。它的主要目标是提高图像的可视质量,减少雾霾对图像造成的影响。 dea-net算法使用了细节增强卷积和对比度两种技术来去除雾霾,以提高图像的细节信息和对比度。细节增强卷积是通过对图像进行一系列卷积操作,突出图像中的细节信息,从而提高图像的清晰度和细节表现力。而对比度提升则是通过调整图像的亮度和对比度,增强图像的视觉效果。 dea-net算法在去除雾霾的过程中,首先通过细节增强卷积提取图像的细节信息,然后利用对比度提升技术增强图像的对比度。接下来,通过对像素值进行归一化处理来消除雾霾的像素值的弱化效应。最后,再利用细节增强卷积增强图像的细节信息,提高图像的清晰度。 实验结果表明,dea-net算法在单幅图像去雾方面取得了较好的效果。与其他算法相比,在恢复图像的细节和对比度方面具有明显的优势。该算法能够有效地去除雾霾并恢复图像的清晰度和细节,提高图像的可视质量。 总结而言,dea-net是一种基于细节增强卷积和对比度的单幅图像去雾算法,通过提取细节信息和增强对比度的方式,有效地去除雾霾,提高图像的清晰度和细节表现力。该算法在图像去雾方面具有较好的效果,对于提升图像的可视质量具有重要的应用价值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值