[AI安全论文] 09.ACE算法和暗通道先验图像去雾算法详解(Rizzi | 何恺明老师)
文章目录:
一.图像去雾
二.ACE去雾算法
1.算法原理
2.代码实现
三.暗通道先验去雾算法
1.算法原理
2.算法实现
四.图像噪声和雾生成
1.加盐噪声
2.雾的模拟生成
五.总结
《娜璋带你读论文》系列主要是督促自己阅读优秀论文及听取学术讲座,并分享给大家,希望您喜欢。由于作者的英文水平和学术能力不高,需要不断提升,所以还请大家批评指正,非常欢迎大家给我留言评论,学术路上期待与您前行,加油~
前文推荐:
[AI安全论文] 05.RAID-Cyber Threat Intelligence Modeling Based on GCN
[AI安全论文] 06.NDSS2020 UNICORN: Runtime Provenance-Based Detector for Advanced Persistent Threats
[AI安全论文] 09.ACE算法和暗通道先验图像去雾算法详解(Rizzi | 何恺明老师)
一.图像去雾
- 魏红伟, 等. 图像去雾算法研究综述[J]. 软件导刊, 2021.
- 王道累, 等. 图像去雾算法的综述及分析[J]. 图学学报, 2021.
- OpenCV图像增强万字详解(直方图均衡化、局部直方图均衡化、自动色彩均衡化)- Eastmount
直方图均衡化去雾算法
Retinex去雾算法
暗通道先验去雾算法
基于卷积神经网络的DehazeNet去雾算法
Retinex 算法
根据成像原理,消除了反射分量的影响,达到了图像增强去雾的效果
直方图均衡化算法
使图像的像素分布更加均匀,放大了图像的细节
偏微分方程算法
将图像视作一个偏微分方程,通过计算梯度场提高对比度
小波变换算法
对图像进行分解,放大有用的部分
暗通道先验去雾算法
通过对大量无雾图像进行特征分析,找到了无雾图像与大气散射模型中某些参数的先验关系。该算法复杂度低,去雾效果好,因此在其基础上出现了大量基于暗通道先验的改进算法。
使用 CNN 生成大气散射模型的某些参数,然后再根据大气散射模型来恢复无雾图像
使用 CNN (例如 GAN)直接根据模糊图像生成无雾的清晰图像
基于图像增强的方法不考虑有雾图像的形成过程,而是直接通过突出图像的细节,提高对比度等方式,从而使有雾图像看上去更加清晰。
基于图像复原的方法则是追寻图像降质的物理过程,通过物理模型还原出清晰的图像。
基于 CNN 的方法则是利用神经网络强大的学习能力,寻找有雾图像与图像复原物理模型中某些系数的映射关系或者使用 GAN,根据有雾图像还原出无雾的清晰图像。
二.ACE去雾算法
1.算法原理
- https://www.ipol.im/pub/art/2012/g-ace/? utm_source=doi
Automatic Color Enhancement (ACE) and its Fast Implementation- https://www.sciencedirect.com/science/article/abs/pii/ S0167865502003239
A new algorithm for unsupervised global and local color correction(原作者Rizzi大佬)
一是对图像进行色彩和空域调整,完成图像的色差校正,得到空域重构图像。模仿视觉系统的侧抑制性和区域自适应性,进行色彩的空域调整。侧抑制性是一个生理学概念,指在某个神经元受到刺激而产生兴奋时,再刺激相近的神经元,后者所发生的兴奋对前者产生的抑制作用。
二是对校正后的图像进行动态扩展。对图像的动态范围进行全局调整,并使图像满足灰度世界理论和白斑点假设。算法针对单通道,再延伸应用到RGB彩色空间的3通道图像,即对3个通道分别处理再进行整合完成。
2.代码实现
自动色彩均衡(ACE)快速算法 - zmshy2128老师
# -*- coding: utf-8 -*-
# By:Eastmount CSDN 2021-03-12
# 惨zmshy2128老师文章并修改成Python3代码
import cv2
import numpy as np
import math
import matplotlib.pyplot as plt
#线性拉伸处理
#去掉最大最小0.5%的像素值 线性拉伸至[0,1]
def stretchImage(data, s=0.005, bins = 2000):
ht = np.histogram(data, bins);
d = np.cumsum(ht[0])/float(data.size)
lmin = 0; lmax=bins-1
while lmin<bins:
if d[lmin]>=s:
break
lmin+=1
while lmax>=0:
if d[lmax]<=1-s:
break
lmax-=1
return np.clip((data-ht[1][lmin])/(ht[1][lmax]-ht[1][lmin]), 0,1)
#根据半径计算权重参数矩阵
g_para = {}
def getPara(radius = 5):
global g_para
m = g_para.get(radius, None)
if m is not None:
return m
size = radius*2+1
m = np.zeros((size, size))
for h in range(-radius, radius+1):
for w in range(-radius, radius+1):
if h==0 and w==0:
continue
m[radius+h, radius+w] = 1.0/math.sqrt(h**2+w**2)
m /= m.sum()
g_para[radius] = m
return m
#常规的ACE实现
def zmIce(I, ratio=4, radius=300):
para = getPara(radius)
height,width = I.shape
zh = []
zw = []
n = 0
while n < radius:
zh.append(0)
zw.append(0)
n += 1
for n in range(height):
zh.append(n)
for n in range(width):
zw.append(n)
n = 0
while n < radius:
zh.append(height-1)
zw.append(width-1)
n += 1
#print(zh)
#print(zw)
Z = I[np.ix_(zh, zw)]
res = np.zeros(I.shape)
for h in range(radius*2+1):
for w in range(radius*2+1):
if para[h][w] == 0:
continue
res += (para[h][w] * np.clip((I-Z[h:h+height, w:w+width])*ratio, -1, 1))
return res
#单通道ACE快速增强实现
def zmIceFast(I, ratio, radius):
print(I)
height, width = I.shape[:2]
if min(height, width) <=2:
return np.zeros(I.shape)+0.5
Rs = cv2.resize(I, (int((width+1)/2), int((height+1)/2)))
Rf = zmIceFast(Rs, ratio, radius) #递归调用
Rf = cv2.resize(Rf, (width, height))
Rs = cv2.resize(Rs, (width, height))
return Rf+zmIce(I,ratio, radius)-zmIce(Rs,ratio,radius)
#rgb三通道分别增强 ratio是对比度增强因子 radius是卷积模板半径
def zmIceColor(I, ratio=4, radius=3):
res = np.zeros(I.shape)
for k in range(3):
res[:,:,k] = stretchImage(zmIceFast(I[:,:,k], ratio, radius))
return res
#主函数
if __name__ == '__main__':
img = cv2.imread('car.png')
res = zmIceColor(img/255.0)*255
cv2.imwrite('car-Ice.jpg', res)
运行结果如图所示,ACE算法能有效进行图像去雾处理,实现图像的细节增强。
最后是目标检测去雾和女神去雾的效果,哈哈,继续加油!
三.暗通道先验去雾算法
该算法是计算机视觉领域何恺明大佬于2009年提出的图像去雾经典算法,并获取当年CVPR最佳论文。论文题目为《Single Image Haze Removal Using Dark Channel Prior》。下图是大佬的百科简介,是真的厉害,值得我们大家学习。
2003年5月,何恺明拿到保送清华的资格,是当年执信中学唯一保送上清华大学的学生;高考结果出炉以后,何恺明获得满分900分的成绩,成为当年广东省9位满分状元之一。
2009年,何恺明成为首获计算机视觉领域三大国际会议之一CVPR“最佳论文奖”的中国学者。
在2015年的ImageNet图像识别大赛中,何恺明和他的团队用“图像识别深度差残学习”系统,击败谷歌、英特尔、高通等业界团队,荣获第一。
何恺明作为第一作者获得了CVPR 2009,CVPR 2016和ICCV 2017(Marr Prize)的最佳论文奖,并获得了ICCV 2017最佳学生论文奖。
2018年,第31届计算机视觉和模式识别大会(Conference on Computer Vision and Pattern Recognition, CVPR)在美国盐湖城召开,何恺明获得本届大会的PAMI年轻学者奖。
1.算法原理
言归正传,如果是图像处理或研究图像去雾领域的作者,建议大家认真阅读这篇英文原文,能在2009年提出该算法真的很惊艳。
英文原文:
- https://ieeexplore.ieee.org/document/5567108
Single Image Haze Removal Using Dark Channel Prior- https://ieeexplore.ieee.org/document/5206515
Single image haze removal using dark channel prior
引用及参考中文论文:
- 何涛, 等. 基于暗通道先验的单幅图像去雾新算法[J]. 计算机科学, 2021.
- 王蓉, 等. 基于改进加权融合暗通道算法的图像去雾研究[J]. 浙江科技学院学报, 2021.
- 图像去雾算法的原理、实现、效果(速度可实时)- 挚爱图像处理
- 图像去雾之何凯明暗通道先验去雾算法原理及c++代码实现 - Do it !
暗通道先验(Dark Channel Prior, DCP)去雾算法 依赖大气散射模型进行去雾处理,通过对大量有雾图像和无雾图像进行观察总结,得到其中存在的一些映射关系,然后根据有雾图像的形成过程来进行逆运算,从而恢复清晰图像。
算法实现过程及原理如下,参考何恺明老师和何涛老师的论文。
(1) 大气散射模型
在计算机视觉和计算机图形学中,方程所描述的大气散射模型被广泛使用。参数解释如下:
x是图像的空间坐标
I(x)代表有雾图像(待去雾图像)
J(x)代表无雾图像(待恢复图像)
A代表全球大气光值
t(x)代表透射率
方程右边第一项为场景直接衰减项,第二项为环境光项。
(2) 暗通道定义
在绝大多数非天空的局部区域中,某些像素总会至少有一个颜色通道的值很低。对于一幅图像J(x),其暗通道的数学定义表示如下:
其中,Ω(x)表示以x为中心的局部区域,上标c表示RGB三个通道。该公式的意义用代码表达也很简单,首先求出每个像素RGB分量中的最小值,存入一副和原始图像大小相同的灰度图中,然后再对这幅灰度图进行最小值滤波,滤波的半径由窗口大小决定。
(3) 暗通道先验理论
暗通道先验理论指出:对于非天空区域的无雾图像J(x)的暗通道趋于0,即:
实际生活中造成暗原色中低通道值主要有三个因素:
a) 汽车、建筑物和城市中玻璃窗户的阴影,或者是树叶、树与岩石等自然景观的投影;
b) 色彩鲜艳的物体或表面,在RGB的三个通道中有些通道的值很低(比如绿色的草地/树/植物,红色或黄色的花朵/叶子,或者蓝色的水面);
c) 颜色较暗的物体或者表面,例如灰暗色的树干和石头。
总之,自然景物中到处都是阴影或者彩色,这些景物的图像的暗原色总是很灰暗的,而有雾的图像较亮。因此,可以明显的看到暗通道先验理论的普遍性。
(4) 公式变形
根据大气散射模型,将第一个公式稍作处理,变形为下式:
假设每一个窗口的透射率t(x)为常数,记为t’(x),并且A值已给定,对式两边同时进行两次最小值运算,可得:
其中,J(x)是要求的无雾图像,根据前述的暗通道先验理论可知:
因此可推导出:
(5) 透射率计算
将上式带入可得到透射率t’(x)的预估值,如下所示:
现实生活中,即便晴空万里,空气中也会存在一些颗粒,在眺望远处的景物时,人们还是能感觉到雾的存在。另外,雾的存在让人们感受到景深,因此在去雾的同时有必要保留一定程度的雾。可以通过引入一个0到1之 间 的 因 子 w(一 般取0.95)对预估透射率进行修正,如式所示:
以上的推导过程均假设大气光值A是已知的,在实际中,可以借助暗通道图从原始雾图中求取。具体步骤如下:
先求取暗通道图,在暗通道图中按照亮度的大小提取最亮的前0.1%的像素
在原始雾图I(x)中找对应位置上具有最高亮度的点的值,作为大气光值A
此外,由于透射率t偏小时,会造成J偏大,恢复的无雾图像整体向白场过度,因此有必要对透射率设置一个下限值t0(一般取值为0.1),当t值小于t0 时,取t=t0。将以上求得的透射率和大气光值代入公式,最终整理得到图像的恢复公式如下:
这就是暗通道先验去雾算法的原理过程,下面简单补充论文中的处理效果图。
再次膜拜偶像,极力推荐大家阅读论文。
2.算法实现
实现代码引用木老师的,感觉比我写得好,参考如下:
openCV+python实现图像去雾 - 木盏老师
# -*- coding: utf-8 -*-
"""
Created on Sat Sep 11 00:16:07 2021
@author: xiuzhang
参考资料:
https://blog.csdn.net/leviopku/article/details/83898619
"""
import sys
import cv2
import math
import numpy as np
def DarkChannel(im,sz):
b,g,r = cv2.split(im)
dc = cv2.min(cv2.min(r,g),b)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(sz,sz))
dark = cv2.erode(dc,kernel)
return dark
def AtmLight(im,dark):
[h,w] = im.shape[:2]
imsz = h*w
numpx = int(max(math.floor(imsz/1000),1))
darkvec = dark.reshape(imsz,1)
imvec = im.reshape(imsz,3)
indices = darkvec.argsort()
indices = indices[imsz-numpx::]
atmsum = np.zeros([1,3])
for ind in range(1,numpx):
atmsum = atmsum + imvec[indices[ind]]
A = atmsum / numpx;
return A
def TransmissionEstimate(im,A,sz):
omega = 0.95
im3 = np.empty(im.shape,im.dtype)
for ind in range(0,3):
im3[:,:,ind] = im[:,:,ind]/A[0,ind]
transmission = 1 - omega*DarkChannel(im3,sz)
return transmission
def Guidedfilter(im,p,r,eps):
mean_I = cv2.boxFilter(im,cv2.CV_64F,(r,r))
mean_p = cv2.boxFilter(p, cv2.CV_64F,(r,r))
mean_Ip = cv2.boxFilter(im*p,cv2.CV_64F,(r,r))
cov_Ip = mean_Ip - mean_I*mean_p
mean_II = cv2.boxFilter(im*im,cv2.CV_64F,(r,r))
var_I = mean_II - mean_I*mean_I
a = cov_Ip/(var_I + eps)
b = mean_p - a*mean_I
mean_a = cv2.boxFilter(a,cv2.CV_64F,(r,r))
mean_b = cv2.boxFilter(b,cv2.CV_64F,(r,r))
q = mean_a*im + mean_b
return q
def TransmissionRefine(im,et):
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
gray = np.float64(gray)/255
r = 60
eps = 0.0001
t = Guidedfilter(gray,et,r,eps)
return t
def Recover(im,t,A,tx = 0.1):
res = np.empty(im.shape,im.dtype)
t = cv2.max(t,tx)
for ind in range(0,3):
res[:,:,ind] = (im[:,:,ind]-A[0,ind])/t + A[0,ind]
return res
if __name__ == '__main__':
fn = 'car-02.png'
src = cv2.imread(fn)
I = src.astype('float64')/255
dark = DarkChannel(I,15)
A = AtmLight(I,dark)
te = TransmissionEstimate(I,A,15)
t = TransmissionRefine(src,te)
J = Recover(I,t,A,0.1)
arr = np.hstack((I, J))
cv2.imshow("contrast", arr)
cv2.imwrite("car-02-dehaze.png", J*255 )
cv2.imwrite("car-02-contrast.png", arr*255)
cv2.waitKey();
实现效果如下图所示:
如果想和后续目标汽车检测结合,同样可以先去雾再进行检测,如下图所示:
四.图像噪声和雾生成
图像处理总少不了噪声添加或生成,下面补充两个简单的椒盐噪声和雾气模拟生成的代码。这与本文的实验紧密相关,能为我们提供更多的GAN生成样本。后面人工智能系列文章,GAN我们看看能不能学习真实雾化场景的图像,值得期待,哈哈!
1.加盐噪声
原图是一张风景图像:
代码如下:
# -*- coding:utf-8 -*-
import cv2
import numpy as np
#读取图片
img = cv2.imread("fj.png", cv2.IMREAD_UNCHANGED)
rows, cols, chn = img.shape
#加噪声
for i in range(50000):
x = np.random.randint(0, rows)
y = np.random.randint(0, cols)
img[x,y,:] = 210
cv2.imshow("noise", img)
#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite('fj-res.png',img)
输出结果如下图所示:
2.雾的模拟生成
代码如下:
import numpy as np
import cv2 as cv
import os
import random
file = ['fj.png']
output = 'fj-wu.png'
for file_img in file:
#打开图像
img = cv.imread(file_img)
mask_img = cv.imread(file_img)
#雾的颜色
mask_img[:, :] = (166, 178, 180)
#里面参数可调,主要调整雾的浓度
image = cv.addWeighted(img,
round(random.uniform(0.03, 0.28), 2),
mask_img, 1, 0)
#保存的文件夹
cv.imwrite(output, image)
输出结果如下图所示,效果还不错。
五.总结
这篇文章就写到这里了,希望对您有所帮助。由于作者英语实在太差,论文的水平也很低,写得不好的地方还请海涵和批评。同时,也欢迎大家讨论,真心推荐原文。学安全两年,认识了很多安全大佬和朋友,希望大家一起进步。同时非常感谢参考文献中的大佬们,感谢老师、实验室小伙伴们的教导和交流,深知自己很菜,得努力前行。感恩遇见,且行且珍惜,小珞珞太可爱了,哈哈。
如果你是一名Python初学者或想了解图像处理知识,推荐作者《Python图像处理》系列,并且多实践多写代码,最后希望文章对您有所帮助。
又认识了很多朋友,也解答了许多学生和博友的问题,虽然自己技术不是很好,但真心感激这一路走来认识了许多伙伴,也享受相互交流的过程,感恩遇见,不负青春。
这半个月交流让我印象深刻的是复旦、浙大和武大离职读博想当老师的朋友,我们交流了许多学习心得并鼓励前行;也有贵财计科、软工、电商几位学生工作的问题;以及家乡贵财、贵大、兴义师范、贵师大、贵理工选择考研或已经读研同学的咨询,我们相互学习;当然还有许多创业、工作、学习或寻求正能量的交流,包括来自广东、南航、中北、湖北工业、建筑转NLP、安全或AI行业的博友。最让我享受的是,许多我教过的学生或相互鼓励前行的博友,经常祝福我们一家并保持良好的情谊,这或许就是分享的魅力,觉不亚于一次holy shit。教育的方式多种多样,我享受这样的交流和鼓励方式,山川异域,携手同行。
最后补充一句,父母能带给孩子最好的礼物,或许就是“处于逆境时的应对能力”,希望小珞珞能坚强、健康、快乐的成长,女神也能美丽和幸福一辈子。爱你们哟。
(By:Eastmount 2021-11-04 夜于武大)