深度神经网络教你如何图像去雾:
https://www.leiphone.com/news/201610/RC7IylYdZge7idm9.html
参考:http://blog.csdn.net/songhhll/article/details/12612681
关于何博士的一些资料和论文,大家可以访问这里:http://research.microsoft.com/en-us/um/people/kahe/
最开始接触何的这篇论文是在2011年,说实在的那个时候,只是随便浏览了下,看到里面的soft matting过程比较复杂,并且执行速度非常慢,就没有什么大的兴趣。最近又偶尔拾起,仔细研读,觉得论文的推理步骤特别清晰,讲解很到位。恰好适逢浏览到其另外一篇文章《Guided Image Filtering》 ,其中提到了可以用导向滤波来代替soft matting的过程,且速度很快,因此,我对去雾的兴趣算法又大大提高了。
本文主要上是对《Single Image Haze Removal Using Dark Channel Prior》的翻译、整理、及部分解释。如果您的英文水平好,建议看原文可能来的更爽些。
一、论文思想的简单描述
首先看看暗通道先验是什么:
在绝大多数非天空的局部区域里,某一些像素总会有至少一个颜色通道具有很低的值。换言之,该区域光强度的最小值是个很小的数。
我们给暗通道一个数学定义,对于任意的输入图像J,其暗通道可以用下式表达:
式中Jc表示彩色图像的每个通道 ,Ω(x)表示以像素X为中心的一个窗口。
式(5)的意义用代码表达也很简单,首先求出每个像素RGB分量中的最小值,存入一副和原始图像大小相同的灰度图中,然后再对这幅灰度图进行最小值滤波,滤波的半径由窗口大小决定,一般有WindowSize = 2 * Radius + 1;
暗通道先验的理论指出:
实际生活中造成暗原色中低通道值主要有三个因素:a)汽车、建筑物和城市中玻璃窗户的阴影,或者是树叶、树与岩石等自然景观的投影;b)色彩鲜艳的物体或表面,在RGB的三个通道中有些通道的值很低(比如绿色的草地/树/植物,红色或黄色的花朵/叶子,或者蓝色的水面);c)颜色较暗的物体或者表面,例如灰暗色的树干和石头。总之,自然景物中到处都是阴影或者彩色,这些景物的图像的暗原色总是很灰暗的。
这个有完整代码,有导向滤波器(guided filter)代码:
http://blog.csdn.net/chongshangyunxiao321/article/details/50997111
python3版本:
#!/usr/bin/env python # -*- coding: utf-8 -*- from PIL import Image from guidedfilter import * def getDark(input_img, filter, frame): """get dark image from the input image""" size = input_img.size output = [] for x in range(size[1]): temp = [] for y in range(size[0]): temp.append(min(input_img.getpixel((y, x)))) output.append(temp) output = filter2d(output, filter, frame) output_img = Image.new('L', size) for x in range(size[1]): for y in range(size[0]): output_img.putpixel((y, x), output[x][y]) return output_img def getLight(srcImage, darkImage, cut): """get atmospheric light from the picture""" size = darkImage.size light = [] for x in range(size[0]): for y in range(size[1]): light.append(darkImage.getpixel((x, y))) light.sort() light.reverse() threshold = light[int(cut * len(light))] atmosphere = {} for x in range(size[0]): for y in range(size[1]): if darkImage.getpixel((x, y)) >= threshold: atmosphere.update({(x, y): sum(srcImage.getpixel((x, y))) / 3.0}) pos = sorted(atmosphere.items(), key = lambda item: item[1], reverse = True)[0][0] return srcImage.getpixel(pos) def getTransmission(input_img, light, omiga): """get transmission from the picture""" size = input_img.size output = [] for x in range(size[1]): temp = [] for y in range(size[0]): temp.append(min(input_img.getpixel((y, x))) / float(min(light))) output.append(temp) transmission = [] for x in range(size[1]): temp = [] for y in range(size[0]): temp.append(1 - omiga * minimizeFilter(output, (x, y), (10, 10))) transmission.append(temp) return transmission def getRadiance(input_img, transmission, light, t0): """get radiance from the picture""" size = input_img.size output = Image.new('RGB', size) for x in range(size[1]): for y in range(size[0]): r, g, b = input_img.getpixel((y, x)) r = int((r - light[0]) / float(max(t0, transmission[x][y])) + light[0]) g = int((g - light[1]) / float(max(t0, transmission[x][y])) + light[1]) b = int((b - light[2]) / float(max(t0, transmission[x][y])) + light[2]) output.putpixel((y, x), (r, g, b)) return output def ensure(n): if n < 0: n = 0 if n > 255: n = 255 return int(n) if __name__ == '__main__': image = Image.open('image/huoche.jpg') image = image.convert('RGB') dark = getDark(image, minimizeFilter, (10, 10)) dark.save('3_dark.png') light = getLight(image, dark, 0.001) transmission = getTransmission(image, light, 0.9) tranImage = Image.new('L', image.size) grayImage = image.convert('L') for x in range(image.size[0]): for y in range(image.size[1]): tranImage.putpixel((x, y), int(transmission[y][x] * 255)) guided = guidedFilter(grayImage, tranImage, 25, 0.001) guidedImage = Image.new('L', image.size) for x in range(image.size[0]): for y in range(image.size[1]): guidedImage.putpixel((x, y), ensure(guided[y][x])) guided[y][x] /= 255.0 #guidedImage.show() guidedImage.save('3_guided.png') output = getRadiance(image, guided, light, 0.1) output.save('3_haze.png')
#!/usr/bin/env python # -*- coding: utf-8 -*- from PIL import Image import numpy as np def filter2d(input_img, filter, frame): """filter of the 2-dimension picture""" size = len(input_img), len(input_img[0]) output = [] for i in range(size[0]): temp = [] for j in range(size[1]): temp.append(filter(input_img, (i, j), frame)) output.append(temp) return output def minimizeFilter(input_img, point, size): """minimize filter for the input image""" begin = np.int32((point[0] - size[0] / 2, point[0] + size[0] / 2 + 1)) end = np.int32((point[1] - size[1] / 2, point[1] + size[1] / 2 + 1)) l = [] for i in range(*begin): for j in range(*end): if (i >= 0 and i < len(input_img)) and (j >= 0 and j < len(input_img[0])): l.append(input_img[i][j]) return min(l) def convertImageToMatrix(image): size = image.size out = [] for x in range(size[1]): temp = [] for y in range(size[0]): temp.append(image.getpixel((y, x))) out.append(temp) return out def boxFilter(im, radius): """box filter for the image of the radius""" height, width = len(im), len(im[0]) imDst = [] imCum = [] for x in range(height): imDst.append([0.0] * width) imCum.append([0.0] * width) #cumulative sum over Y axis for i in range(width): for j in range(height): if j == 0: imCum[j][i] = im[j][i] else: imCum[j][i] = im[j][i] + imCum[j - 1][i] #difference over Y axis for j in range(radius + 1): for i in range(width): imDst[j][i] = imCum[j + radius][i] for j in range(radius + 1, height - radius): for i in range(width): imDst[j][i] = imCum[j + radius][i] - imCum[j - radius - 1][i] for j in range(height - radius, height): for i in range(width): imDst[j][i] = imCum[height - 1][i] - imCum[j - radius - 1][i] #cumulative sum over X axis for j in range(height): for i in range(width): if i == 0: imCum[j][i] = imDst[j][i] else: imCum[j][i] = imDst[j][i] + imCum[j][i - 1] #difference over X axis for j in range(height): for i in range(radius + 1): imDst[j][i] = imCum[j][i + radius] for j in range(height): for i in range(radius + 1, width - radius): imDst[j][i] = imCum[j][i + radius] - imCum[j][i - radius - 1] for j in range(height): for i in range(width - radius, width): imDst[j][i] = imCum[j][width - 1] - imCum[j][i - radius - 1] return imDst def dot(matrix1, matrix2, operation): """dot operation for the matrix1 and matrix2""" out = [] size = len(matrix1), len(matrix1[0]) for x in range(size[0]): temp = [] for y in range(size[1]): temp.append(operation(matrix1[x][y], matrix2[x][y])) out.append(temp) return out def guidedFilter(srcImage, guidedImage, radius, epsilon): """guided filter for the image src image must be gray image guided image must be gray image """ size = srcImage.size src = convertImageToMatrix(srcImage) guided = convertImageToMatrix(guidedImage) one = [] for x in range(size[1]): one.append([1.0] * size[0]) n = boxFilter(one, radius) plus = lambda x, y: x + y minus = lambda x, y: x - y multiple = lambda x, y: x * y divide = lambda x, y: x / y meanI = dot(boxFilter(src, radius), n, divide) meanP = dot(boxFilter(guided, radius), n, divide) meanIP = dot(boxFilter(dot(src, guided, multiple), radius), n, divide) covIP = dot(meanIP, dot(meanI, meanP, multiple), minus) meanII = dot(boxFilter(dot(src, src, multiple), radius), n, divide) varI = dot(meanII, dot(meanI, meanI, multiple), minus) epsilonMatrix = [] for x in range(size[1]): epsilonMatrix.append([epsilon] * size[0]) a = dot(covIP, dot(varI, epsilonMatrix, plus), divide) b = dot(meanP, dot(a, meanI, multiple), minus) meanA = dot(boxFilter(a, radius), n, divide) meanB = dot(boxFilter(b, radius), n, divide) return dot(dot(meanA, src, multiple), meanB, plus) if __name__ == '__main__': a=(-5,6) import numpy as np a=np.int32(a) for i in range(*a): print(i)
原文:http://blog.csdn.net/zmshy2128/article/details/53443227
这个代码有问题,下面一行报错了:
res = np.minimum(I, I[[0] + range(h - 1), :])
何凯明博士的去雾文章和算法实现已经漫天飞了,我今天也就不啰里啰唆,直接给出自己python实现的完整版本,全部才60多行代码,简单易懂,并有简要注释,去雾效果也很不错。
在这个python版本中,计算量最大的就是最小值滤波,纯python写的,慢,可以进一步使用C优化,其他部分都是使用numpy和opencv的现成东东,效率还行。