Skip to content

Commit 899edf4

Browse files
Add files via upload
0 parents  commit 899edf4

7 files changed

+287
-0
lines changed

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# PMS-Net: Robust Haze Removal Based on Patch Map for Single Images
2+
3+
Wei-Ting Chen, Jian-Jiun Ding, Sy-Yen Kuo
4+
5+
The IEEE Conference on Computer Vision and Pattern Recognition (CVPR), 2019, pp. 11681-11689
6+
7+
In this paper, we proposed a novel haze removal algorithm based on a new feature called the patch map. Conventional patch-based haze removal algorithms (e.g. the Dark Channel prior) usually performs dehazing with a fixed patch size. However, it may produce several problems in recovered results such as oversaturation and color distortion. Therefore, in this paper, we designed an adaptive and automatic patch size selection model called the Patch Map Selection Network (PMS-Net) to select the patch size corresponding to each pixel. This network is designed based on the convolutional neural network (CNN), which can generate the patch map from the image to image. Experimental results on both synthesized and real-world hazy images show that, with the combination of the proposed PMS-Net, the performance in haze removal is much better than that of other state-of-the-art algorithms and we can address the problems caused by the fixed patch size.
8+
proposed algorithm performs favorably against the stateof-the-art algorithms.
9+
10+
11+
# Setup and environment
12+
13+
To generate the recovered result you need:
14+
1. Python 3
15+
2. Keras
16+
3. CUDA >= 9.0
17+
4. opencv-python
18+
19+
All the hazy inputs and recovered results are put in the "image" and "result" folder, respectively.
20+
21+
Run the test.py to generate recovered results
22+
23+
```
24+
$ python test.py
25+
```
26+
The pretrained model can be downloaded from: https://drive.google.com/drive/folders/12cKqlfT7ckxwgB-xBdU5TF7Cc5-hssOg?usp=sharing
27+
28+
29+
# Citations
30+
Please cite this paper in your publications if it helps your research:
31+
32+
@inproceedings{chen2019pms,
33+
title={PMS-Net: Robust Haze Removal Based on Patch Map for Single Images},
34+
author={Chen, Wei-Ting and Ding, Jian-Jiun and Kuo, Sy-Yen},
35+
booktitle={Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition},
36+
pages={11681--11689},
37+
year={2019}
38+
}
39+
40+

dehaze_patchMap_dehaze.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import numpy as np
2+
import cv2
3+
from find_atmosphericLight import find_atmosphericLight
4+
from find_darkchannel import find_darkchannel
5+
from matplotlib import pyplot as plt
6+
7+
def dehaze_patchMap(image, omega, patchMap):
8+
9+
m, n = image.shape[0], image.shape[1]
10+
11+
transmissionMap = np.ones((m, n))
12+
darkchannelMap = np.ones((m, n))
13+
14+
patchMap = np.ceil(patchMap)
15+
#patchMap(find(patchMap<1))=1
16+
#patchMap(find(patchMap>120))=120
17+
patchMap[patchMap<1]=1
18+
patchMap[patchMap>120]=120
19+
20+
'''patchMap = guided_filter(rgb2gray(image), patchMap, 15, 0.001)
21+
patchMap = ceil(patchMap)
22+
patchMap(find(patchMap<1))=1
23+
patchMap(find(patchMap>120))=120'''
24+
25+
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)/255
26+
print(type(gray), gray.shape, type(patchMap), patchMap)
27+
patchMap = guidedFilter(gray, patchMap, 15, 0.001).astype(np.uint8)
28+
patchMap[patchMap<1]=1
29+
patchMap[patchMap>120]=120
30+
31+
'''[patch_size, ~, patchIdx] = unique(patchMap)
32+
patchIdx = reshape(patchIdx, m, n)
33+
patch_size_num = size(patch_size)'''
34+
35+
patch_size = np.unique(patchMap)
36+
37+
'''for i = 1: patch_size_num(1)
38+
i
39+
dark_channel = find_darkchannel(image, patch_size(i))
40+
atmosphere = find_atmosphericLight(image, dark_channel)
41+
atmosphere_est = repmat(reshape(atmosphere, [1, 1, 3]), m, n)
42+
est_term = image./atmosphere_est
43+
tx_estimation = 1-omega*find_darkchannel(est_term, patch_size(i))
44+
tx_estimation = reshape(tx_estimation, m, n)
45+
patchIdx = patchMap == patch_size(i)
46+
transmissionMap(patchIdx) = tx_estimation(patchIdx)
47+
darkchannelMap(patchIdx) = dark_channel(patchIdx)
48+
49+
50+
tx_refine = guided_filter(rgb2gray(image), transmissionMap, 15, 0.001)
51+
tx_refine = reshape(tx_refine, m, n)
52+
A_predict = find_atmosphericLight(image, darkchannelMap)
53+
A_predict = repmat(reshape(A_predict, [1, 1, 3]), m, n)
54+
tx = repmat(max(tx_refine, 0.1), [1, 1, 3])
55+
recover_result = ((image - A_predict) ./ tx) + A_predict'''
56+
57+
image = image / 255
58+
for i in range(len(patch_size)):
59+
print(str(i), end= ' ')
60+
dark_channel = find_darkchannel(image, patch_size[i])
61+
62+
atmosphere = find_atmosphericLight(image, dark_channel)
63+
64+
#atmosphere_est = repmat(reshape(atmosphere, [1, 1, 3]), m, n)
65+
#est_term = image./atmosphere_est
66+
67+
'''atmosphere_est = np.zeros((m, n, 3))
68+
atmosphere_est[...,0] = atmosphere[0]
69+
atmosphere_est[...,1] = atmosphere[1]
70+
atmosphere_est[...,2] = atmosphere[2]
71+
est_term = image / atmosphere_est'''
72+
est_term = image / atmosphere
73+
74+
tx_estimation = 1 - omega * find_darkchannel(est_term, patch_size[i])
75+
tx_estimation = np.reshape(tx_estimation, (m, n))
76+
'''patchIdx = patchMap == patch_size(i)
77+
transmissionMap(patchIdx) = tx_estimation(patchIdx)
78+
darkchannelMap(patchIdx) = dark_channel(patchIdx) '''
79+
patchIdx = patchMap==patch_size[i]
80+
transmissionMap[patchIdx] = tx_estimation[patchIdx]
81+
darkchannelMap[patchIdx] = dark_channel[patchIdx]
82+
83+
'''tx_refine = guided_filter(rgb2gray(image), transmissionMap, 15, 0.001)
84+
tx_refine = reshape(tx_refine, m, n)
85+
A_predict = find_atmosphericLight(image, darkchannelMap)
86+
A_predict = repmat(reshape(A_predict, [1, 1, 3]), m, n)
87+
tx = repmat(max(tx_refine, 0.1), [1, 1, 3])
88+
recover_result = ((image - A_predict) ./ tx) + A_predict'''
89+
tx_refine = guidedFilter(gray, transmissionMap, 15, 0.001) #guided_filter(rgb2gray(image), transmissionMap, 15, 0.001)
90+
#tx_refine = reshape(tx_refine, m, n)
91+
A_predict = find_atmosphericLight(image, darkchannelMap)
92+
#A_predict = repmat(reshape(A_predict, [1, 1, 3]), m, n)
93+
#tx = repmat(max(tx_refine, 0.1), [1, 1, 3])
94+
tx = np.reshape(tx_refine,(m,n,1))
95+
tx[tx < 0.1] = 0.1
96+
tx = np.concatenate((tx,tx,tx), axis=2)
97+
recover_result = (image - A_predict) / tx + A_predict
98+
#plt.imshow(recover_result); plt.show()
99+
100+
return recover_result * 255, tx
101+
102+
def guidedFilter(I, p, r, eps):
103+
hei, wid = p.shape
104+
N = cv2.boxFilter(np.ones((hei, wid)), -1, (r,r))
105+
106+
meanI = cv2.boxFilter(I, -1, (r,r)) / N
107+
meanP = cv2.boxFilter(p, -1, (r,r)) / N
108+
corrI = cv2.boxFilter(I * I, -1, (r,r)) / N
109+
corrIp = cv2.boxFilter(I * p, -1, (r,r)) / N
110+
111+
varI = corrI - meanI * meanI
112+
covIp = corrIp - meanI * meanP
113+
114+
a = covIp / (varI + eps)
115+
b = meanP - a * meanI
116+
117+
meanA = cv2.boxFilter(a, -1, (r,r)) / N
118+
meanB = cv2.boxFilter(b, -1, (r,r)) / N
119+
120+
q = meanA * I + meanB
121+
return q

find_atmosphericLight.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import numpy as np
2+
3+
def find_atmosphericLight(image, dark_channel):
4+
5+
m, n = image.shape[0], image.shape[1]
6+
7+
search_A_pixel = np.floor(m*n*0.01)
8+
image_save = np.reshape(image, (m*n, 3))
9+
darkchannel_save = np.reshape(dark_channel, m*n)
10+
11+
saver = np.zeros((1, 3))
12+
idx = np.argsort(-darkchannel_save)
13+
14+
for pixel_idx in range(int(search_A_pixel)):
15+
saver = saver + image_save[ idx[pixel_idx], :]
16+
17+
A = saver / search_A_pixel
18+
return A

find_darkchannel.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import cv2
2+
3+
def find_darkchannel(image, patch_win_size):
4+
5+
patch_win_size = int(patch_win_size)
6+
b,g,r = cv2.split(image)
7+
dc = cv2.min(cv2.min(r,g),b)
8+
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(patch_win_size,patch_win_size))
9+
dark_channel = cv2.erode(dc,kernel)
10+
11+
return dark_channel

patchMap_predict.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import numpy as np
2+
import cv2
3+
from keras.models import load_model
4+
import scipy.io as sio
5+
6+
7+
8+
9+
10+
base_path_hazyImg = 'image/'
11+
base_path_result = 'patchMap/'
12+
imgname = 'waterfall.tif'
13+
modelDir = 'PMS-Net.h5'
14+
15+
16+
print ("Process image: ", imgname)
17+
18+
19+
20+
hazy_sample = cv2.imread(base_path_hazyImg + imgname)
21+
hazy_sample = cv2.resize(hazy_sample,(640,480))
22+
hazy_input = np.reshape(hazy_sample,(1, 480, 640, 3))
23+
model = load_model(modelDir)
24+
patchMap = model.predict(hazy_input, verbose = 1)
25+
patchMap = np.reshape(patchMap,(-1,1))
26+
patchMap = np.reshape(patchMap,(480, 640))
27+
patchMap = np.float64(patchMap)
28+
29+
30+
imgname = imgname.replace('.tif','')
31+
32+
33+
print('saveDir:',base_path_result + imgname + '.mat')
34+
35+
sio.savemat(base_path_result + imgname + '.mat',{"patchMap":patchMap})
36+
37+
38+
39+

recover.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import cv2
2+
import scipy.io as sio
3+
import numpy as np
4+
from dehaze_patchMap_dehaze import dehaze_patchMap
5+
6+
hazy_img_dir = 'image/'
7+
patchMap_dir = 'patchMap/'
8+
save_dir = 'result/'
9+
imgname= 'girls.tif'
10+
11+
12+
image = cv2.imread(hazy_img_dir + imgname)
13+
if image.shape[0] != 480 or image.shape[1] != 640:
14+
print('resize image tp 640*480')
15+
image = cv2.resize(image,(640,480))
16+
17+
print(imgname)
18+
patchMapname = imgname[:-4] + '.mat'
19+
20+
patchMap = sio.loadmat(patchMap_dir + patchMapname)
21+
patchMap = np.array(patchMap['patchMap'])
22+
23+
recover_result, tx = dehaze_patchMap(image, 0.95, patchMap)
24+
25+
savename_result = save_dir + 'py_recover_' + imgname
26+
27+
cv2.imwrite(savename_result, recover_result)
28+
29+
30+

test.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import numpy as np
2+
import cv2
3+
from keras.models import load_model
4+
#import scipy.io as sio
5+
from dehaze_patchMap_dehaze import dehaze_patchMap
6+
7+
base_path_hazyImg = 'image/'
8+
base_path_result = 'patchMap/'
9+
imgname = 'waterfall.tif'
10+
save_dir = 'result/'
11+
modelDir = 'PMS-Net.h5'
12+
13+
print ("Process image: ", imgname)
14+
15+
image = cv2.imread(base_path_hazyImg + imgname)
16+
if image.shape[0] != 480 or image.shape[1] != 640:
17+
print('resize image tp 640*480')
18+
image = cv2.resize(image,(640,480))
19+
hazy_input = np.reshape(image,(1, 480, 640, 3))
20+
model = load_model(modelDir)
21+
patchMap = model.predict(hazy_input, verbose = 1)
22+
patchMap = np.reshape(patchMap,(480, 640))
23+
24+
recover_result, tx = dehaze_patchMap(image, 0.95, patchMap)
25+
26+
savename_result = save_dir + 'py_recover_' + imgname
27+
28+
cv2.imwrite(savename_result, recover_result)

0 commit comments

Comments
 (0)