208 lines
7.9 KiB
Python
208 lines
7.9 KiB
Python
import sys,os
|
||
import caffe
|
||
import numpy as np
|
||
import cv2
|
||
import math
|
||
|
||
def EditFcnProto(templateFile, height, width):
|
||
with open(templateFile, 'r') as ft:
|
||
template = ft.read()
|
||
outFile = 'DehazeNetFcn.prototxt'
|
||
with open(outFile, 'w') as fd:
|
||
fd.write(template.format(height_15=height+15, width_15=width+15,
|
||
height_11=height+11, width_11=width+11))
|
||
|
||
def TransmissionEstimate(im_path, height, width):
|
||
caffe.set_mode_cpu()
|
||
|
||
# Define a safe tile size to prevent INT_MAX overflow (approx 512x512 is safe)
|
||
SAFE_TILE_SIZE = 512
|
||
|
||
# Use tiling if the image is larger than the safe size
|
||
if height > SAFE_TILE_SIZE or width > SAFE_TILE_SIZE:
|
||
print(f"Image size ({width}x{height}) is large. Using tiling to avoid memory overflow...")
|
||
|
||
# Determine effective tile size (cannot be larger than image)
|
||
tile_h = min(height, SAFE_TILE_SIZE)
|
||
tile_w = min(width, SAFE_TILE_SIZE)
|
||
|
||
# Generate prototxt for the TILE size, not the full image size
|
||
EditFcnProto('DehazeFcnTemplate.prototxt', tile_h, tile_w)
|
||
|
||
# Load networks
|
||
net = caffe.Net('DehazeNet.prototxt', 'DehazeNet.caffemodel', caffe.TEST)
|
||
net_full_conv = caffe.Net('DehazeNetFcn.prototxt', 'DehazeNet.caffemodel', caffe.TEST)
|
||
net_full_conv.params['ip1-conv'][0].data.flat = net.params['ip1'][0].data.flat
|
||
net_full_conv.params['ip1-conv'][1].data[...] = net.params['ip1'][1].data
|
||
|
||
# Load and pad image
|
||
im = caffe.io.load_image(im_path)
|
||
npad = ((7,8), (7,8), (0,0))
|
||
im_padded = np.pad(im, npad, 'symmetric')
|
||
|
||
transmission = np.zeros((height, width))
|
||
|
||
# Setup transformer for the tile size
|
||
transformers = caffe.io.Transformer({'data': net_full_conv.blobs['data'].data.shape})
|
||
transformers.set_transpose('data', (2,0,1))
|
||
transformers.set_channel_swap('data', (2,1,0))
|
||
|
||
# Process in tiles
|
||
for h in range(0, height, tile_h):
|
||
for w in range(0, width, tile_w):
|
||
# Calculate start/end to handle edges/overlap
|
||
# If we are at the end, shift back to ensure we feed a full tile
|
||
h_start = min(h, height - tile_h)
|
||
w_start = min(w, width - tile_w)
|
||
|
||
# Extract patch from PADDED image
|
||
# Network expects input size of (Tile + 15), so we slice accordingly
|
||
patch = im_padded[h_start : h_start + tile_h + 15, w_start : w_start + tile_w + 15, :]
|
||
|
||
# Forward pass
|
||
out = net_full_conv.forward_all(data=np.array([transformers.preprocess('data', patch-0.2)]))
|
||
|
||
# Reshape output
|
||
block_trans = np.reshape(out['ip1-conv'], (tile_h, tile_w))
|
||
|
||
# Assign to result buffer
|
||
transmission[h_start : h_start + tile_h, w_start : w_start + tile_w] = block_trans
|
||
|
||
return transmission
|
||
|
||
else:
|
||
# Original logic for small images
|
||
EditFcnProto('DehazeFcnTemplate.prototxt', height, width)
|
||
net = caffe.Net('DehazeNet.prototxt', 'DehazeNet.caffemodel', caffe.TEST)
|
||
net_full_conv = caffe.Net('DehazeNetFcn.prototxt', 'DehazeNet.caffemodel', caffe.TEST)
|
||
net_full_conv.params['ip1-conv'][0].data.flat = net.params['ip1'][0].data.flat
|
||
net_full_conv.params['ip1-conv'][1].data[...] = net.params['ip1'][1].data
|
||
im = caffe.io.load_image(im_path)
|
||
npad = ((7,8), (7,8), (0,0))
|
||
im = np.pad(im, npad, 'symmetric')
|
||
transformers = caffe.io.Transformer({'data': net_full_conv.blobs['data'].data.shape})
|
||
transformers.set_transpose('data', (2,0,1))
|
||
transformers.set_channel_swap('data', (2,1,0))
|
||
out = net_full_conv.forward_all(data=np.array([transformers.preprocess('data', im-0.2)]))
|
||
transmission = np.reshape(out['ip1-conv'], (height,width))
|
||
return transmission
|
||
|
||
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 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
|
||
|
||
def getFileList(dir,Filelist, ext=None):
|
||
"""
|
||
获取文件夹及其子文件夹中文件列表
|
||
输入 dir:文件夹根目录
|
||
输入 ext: 扩展名
|
||
返回: 文件路径列表
|
||
"""
|
||
newDir = dir
|
||
if os.path.isfile(dir):
|
||
if ext is None:
|
||
Filelist.append(dir)
|
||
else:
|
||
if ext in dir[-3:]:
|
||
Filelist.append(dir)
|
||
|
||
elif os.path.isdir(dir):
|
||
for s in os.listdir(dir):
|
||
newDir=os.path.join(dir,s)
|
||
getFileList(newDir, Filelist, ext)
|
||
|
||
return Filelist
|
||
|
||
if __name__ == '__main__':
|
||
if not len(sys.argv) == 2:
|
||
print ('Usage: python DeHazeNet.py haze_img_path')
|
||
exit()
|
||
else:
|
||
im_path = sys.argv[1]
|
||
|
||
# 检索文件
|
||
src_img_folder = os.path.join(im_path, 'src')
|
||
imglist = getFileList(src_img_folder, [], '')
|
||
print('本次执行检索到 '+str(len(imglist))+' 张图像\n')
|
||
for img_path in imglist:
|
||
imgname= os.path.splitext(os.path.basename(img_path))[0]
|
||
src = cv2.imread(img_path)
|
||
|
||
height = src.shape[0]
|
||
width = src.shape[1]
|
||
|
||
# Note: EditFcnProto is also called inside TransmissionEstimate if tiling is used
|
||
# We call it here for initialization but it may be overwritten.
|
||
templateFile = 'DehazeFcnTemplate.prototxt'
|
||
EditFcnProto(templateFile, height, width)
|
||
print("-"*5, ' 完成EditFcnProto ',"-"*5)
|
||
|
||
I = src/255.0
|
||
dark = DarkChannel(I,15)
|
||
A = AtmLight(I,dark)
|
||
|
||
te = TransmissionEstimate(img_path, height, width)
|
||
t = TransmissionRefine(src,te)
|
||
J = Recover(I,t,A,0.1)
|
||
|
||
print("Finsh All the operation")
|
||
Trans_Esti_imgdir = os.path.join(im_path, 'Trans_Esti/')
|
||
if not os.path.exists(Trans_Esti_imgdir): os.makedirs(Trans_Esti_imgdir)
|
||
print(Trans_Esti_imgdir + imgname + "_Trans_Esti.png")
|
||
cv2.imwrite(Trans_Esti_imgdir + imgname + "_Trans_Esti.png",te*255);
|
||
|
||
Trans_Refine_imgdir = os.path.join(im_path, 'Trans_Refine/')
|
||
if not os.path.exists(Trans_Refine_imgdir): os.makedirs(Trans_Refine_imgdir)
|
||
print(Trans_Refine_imgdir + imgname + "_Trans_Refine.png")
|
||
cv2.imwrite(Trans_Refine_imgdir + imgname + "_Trans_Refine.png",t*255);
|
||
|
||
result_imgdir = os.path.join(im_path, 'result/')
|
||
if not os.path.exists(result_imgdir): os.makedirs(result_imgdir)
|
||
print(result_imgdir + imgname + "_result.png")
|
||
cv2.imwrite(result_imgdir + imgname + "_result.png",J*255); |