何凯明的经典图像去雾算法,直接上代码啦,理论后续讲解哈~
Python代码如下:
#!/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 xrange(size[1]):
temp = []
for y in xrange(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 xrange(size[1]):
for y in xrange(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 xrange(size[0]):
for y in xrange(size[1]):
light.append(darkImage.getpixel((x, y)))
light.sort()
light.reverse()
threshold = light[int(cut * len(light))]
atmosphere = {}
for x in xrange(size[0]):
for y in xrange(size[1]):
if darkImage.getpixel((x, y)) >= threshold:
atmosphere.update({(x, y): sum(srcImage.getpixel((x, y))) / 3.0})
pos = sorted(atmosphere.iteritems(), 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 xrange(size[1]):
temp = []
for y in xrange(size[0]):
temp.append(min(input_img.getpixel((y, x))) / float(min(light)))
output.append(temp)
transmission = []
for x in xrange(size[1]):
temp = []
for y in xrange(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 xrange(size[1]):
for y in xrange(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('1.png')
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 xrange(image.size[0]):
for y in xrange(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 xrange(image.size[0]):
for y in xrange(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
def filter2d(input_img, filter, frame):
"""filter of the 2-dimension picture"""
size = len(input_img), len(input_img[0])
output = []
for i in xrange(size[0]):
temp = []
for j in xrange(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 = (point[0] - size[0] / 2, point[0] + size[0] / 2 + 1)
end = (point[1] - size[1] / 2, point[1] + size[1] / 2 + 1)
l = []
for i in xrange(*begin):
for j in xrange(*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 xrange(size[1]):
temp = []
for y in xrange(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 xrange(height):
imDst.append([0.0] * width)
imCum.append([0.0] * width)
#cumulative sum over Y axis
for i in xrange(width):
for j in xrange(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 xrange(radius + 1):
for i in xrange(width):
imDst[j][i] = imCum[j + radius][i]
for j in xrange(radius + 1, height - radius):
for i in xrange(width):
imDst[j][i] = imCum[j + radius][i] - imCum[j - radius - 1][i]
for j in xrange(height - radius, height):
for i in xrange(width):
imDst[j][i] = imCum[height - 1][i] - imCum[j - radius - 1][i]
#cumulative sum over X axis
for j in xrange(height):
for i in xrange(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 xrange(height):
for i in xrange(radius + 1):
imDst[j][i] = imCum[j][i + radius]
for j in xrange(height):
for i in xrange(radius + 1, width - radius):
imDst[j][i] = imCum[j][i + radius] - imCum[j][i - radius - 1]
for j in xrange(height):
for i in xrange(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 xrange(size[0]):
temp = []
for y in xrange(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 xrange(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 xrange(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)
测试结果如下:
原图像:
图像暗通道:
图像导向滤波:
去雾后的效果: