Skip to content

Commit fc23371

Browse files
committed
Finished
1 parent e6f33ac commit fc23371

17 files changed

+132
-201
lines changed

Checkpoints/weights-epoch-6loss-0.005/checkpoint

Lines changed: 0 additions & 6 deletions
This file was deleted.
Binary file not shown.
Binary file not shown.

README.md

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
## Denoising Autoencoder
22
Implementation of a denoising autoencoder trained on the RENOIR dataset(MI 3 images).
3+
[Model Architecture](https://github.com/titu1994/Image-Super-Resolution/blob/master/architectures/Denoise.png)
34

45
## Setting up locally
56

67
pip install -r requirements.txt
78

8-
99
## Dataset
10-
50x50px patches were taken from the reference and noisy images in the dataset. I've serialised these into TFRecords, which can be downloaded using,
10+
33x33px patches were taken from the reference and noisy images in the dataset. I've serialised these into TFRecords, which can be downloaded using,
1111

1212
python download_data.py
1313

@@ -16,30 +16,27 @@ This will download the train and validation records required for training.
1616
## Training and inference
1717
1. For training you can run,
1818

19-
python train.py -e <num_of_epochs> -c <checkpoint_after> -v <validation_enabled, 1 or 0>
20-
Example:
21-
22-
python train.py -e 50 -c 5 -v 1
23-
Default values are training for 10 epochs, checkpointing every 1 epoch with validation enabled
19+
python train.py -e <num_of_epochs>
2420

2521
2. For inference,
2622

2723
python predict.py -i <input_file> -o <output_file>
2824

25+
The model doesn't have a fixed input shape so for smaller images(<400x400px), the entire image vector is feed into the model. For larger images, I've used a window of size 33x33px for generating the output image.
2926

3027
## Results
31-
I've trained the model for only 6 epochs(which is a very very small fraction of what a lot of papers recommend), so the results aren't particularly good.
28+
The model was trained for 25 epochs on Google colab's GPU(NVIDIA Tesla k8).
3229

3330
1. Reference:
3431
![Reference Image](https://github.com/Aftaab99/DenoisingAutoencoder/blob/master/images/reference.bmp "Reference Image")
3532

3633
2. Noisy
37-
![Noisy Image](https://github.com/Aftaab99/DenoisingAutoencoder/blob/master/images/noisy.png "Noisy Image")
34+
![Noisy Image](https://github.com/Aftaab99/DenoisingAutoencoder/blob/master/images/noisy.bmp "Noisy Image")
3835

3936
3. Denoised
4037

41-
![Denoised Image](https://github.com/Aftaab99/DenoisingAutoencoder/blob/master/images/denoised.png "Denoised Image")
38+
![Denoised Image](https://github.com/Aftaab99/DenoisingAutoencoder/blob/master/images/denoised.bmp "Denoised Image")
4239

4340
### References
4441
1. J. Anaya, A. Barbu. RENOIR - A Dataset for Real Low-Light Image Noise Reduction.([arxiv](https://arxiv.org/abs/1409.8230))
45-
42+
2. Image Restoration Using ConvolutionalAuto-encoders with Symmetric Skip Connections-Xiao-Jiao Mao, Chunhua Shen, Yu-Bin Yang([code](https://github.com/titu1994/Image-Super-Resolution/))

create_datasets.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ def _bytes_feature(value):
1313

1414
def extract_patches(ref, noisy):
1515
patch_list = []
16-
for x in range(50, 3000, 50):
17-
for y in range(50, 3000, 50):
18-
patch_ref = ref[x - 50:x, y - 50:y, :]
19-
patch_noisy = noisy[x - 50:x, y - 50:y, :]
20-
if patch_ref.shape[0] != 50 or patch_ref.shape[1] != 50:
16+
for x in range(33, 3000, 33):
17+
for y in range(33, 3000, 33):
18+
patch_ref = ref[x - 33:x, y - 33:y, :]
19+
patch_noisy = noisy[x - 33:x, y - 33:y, :]
20+
if patch_ref.shape[0] != 33 or patch_ref.shape[1] != 33:
2121
continue
2222
patch_list.append({'ref': patch_ref, 'noisy': patch_noisy})
2323
return patch_list
19.4 MB
Binary file not shown.

download_data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,4 @@ def save_response_content(response, destination):
4747
download_file_from_google_drive(train_file_id, train_file_dest)
4848

4949
print('Downloading validation records...')
50-
download_file_from_google_drive(val_file_id, val_file_dest)
50+
download_file_from_google_drive(val_file_id, val_file_dest)

images/denoised.png

-4.63 MB
Binary file not shown.

model.py

Lines changed: 0 additions & 155 deletions
This file was deleted.

model_keras.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import tensorflow as tf
2+
from tensorflow.python.keras.layers import Convolution2D, Convolution2DTranspose, merge, Input
3+
from tensorflow.python.keras.models import Model
4+
from PIL import Image
5+
import numpy as np
6+
7+
8+
class DAE:
9+
10+
def __init__(self):
11+
input_1 = Input(shape=(None, None, 3))
12+
conv_1 = Convolution2D(64, kernel_size=(3, 3), padding='same', activation='relu')(input_1)
13+
conv_2 = Convolution2D(64, kernel_size=(5, 5), padding='same', activation='relu')(conv_1)
14+
dconv_1 = Convolution2DTranspose(64, kernel_size=(3, 3), padding='same', activation='relu')(conv_2)
15+
merge_1 = merge.maximum([dconv_1, conv_2])
16+
dconv_2 = Convolution2DTranspose(64, kernel_size=(3, 3), padding="same", activation='relu')(merge_1)
17+
merge_2 = merge.maximum([dconv_2, conv_1])
18+
conv3 = Convolution2D(3, (5, 5), padding="same", activation='relu')(merge_2)
19+
20+
self.model = Model(inputs=input_1, outputs=conv3)
21+
self.model.compile(optimizer='adam', loss='mean_squared_error', metrics=['acc'])
22+
self.model.summary()
23+
self.batch_size = 128
24+
25+
def load_model_weights(self, save_path):
26+
self.model.load_weights(save_path)
27+
28+
def save_model(self, save_path):
29+
self.model.save(save_path)
30+
31+
def train(self, epochs):
32+
n_records = 0
33+
for _ in tf.python_io.tf_record_iterator('Data/train.tfrecords'):
34+
n_records += 1
35+
x, y = self.input_fn('Data/train.tfrecords')
36+
self.model.fit(x, y, epochs=epochs, steps_per_epoch=n_records // self.batch_size)
37+
38+
def denoise_patch(self, image_patch):
39+
image_patch = image_patch[np.newaxis, ...]
40+
output_t = self.model.predict(image_patch)
41+
output_t = np.array(output_t)
42+
output_t = np.clip(output_t, 0, 255)
43+
return output_t
44+
45+
def denoise(self, image_array):
46+
dim = image_array.shape
47+
img_h = dim[0]
48+
img_w = dim[1]
49+
d_image = image_array
50+
51+
if img_w * img_h < 400 * 400:
52+
image_array = image_array[np.newaxis, ...]
53+
a = np.clip(self.model.predict(image_array), 0, 255).astype('uint8')
54+
a = a.squeeze(0)
55+
img1 = Image.fromarray(a)
56+
return img1
57+
58+
for y in range(0, img_w, 33):
59+
for x in range(0, img_h, 33):
60+
patch = image_array[x:x + 33, y:y + 33, :]
61+
if patch.shape[0] == 33 and patch.shape[1] == 33:
62+
patch = self.denoise_patch(patch)
63+
d_image[x:x + 33, y:y + 33, :] = patch
64+
65+
elif patch.shape[0] < 33 and patch.shape[1] < 33:
66+
patch = self.denoise_patch(patch)
67+
d_image[x:, y:, :] = patch
68+
69+
elif patch.shape[1] < 33 and patch.shape[0] == 33:
70+
l = patch.shape[1]
71+
patch = self.denoise_patch(patch)
72+
d_image[x:x + 33, y:y + l, :] = patch
73+
74+
elif patch.shape[0] < 33 and patch.shape[1] == 33:
75+
l = patch.shape[0]
76+
patch = self.denoise_patch(patch)
77+
d_image[x:x + l, y:y + 33, :] = patch[0:l, :, :]
78+
79+
d_image = Image.fromarray(d_image.astype('uint8'))
80+
return d_image
81+
82+
def parser(self, record):
83+
keys_to_feature = {
84+
"reference": tf.FixedLenFeature([], tf.string),
85+
"noisy": tf.FixedLenFeature([], tf.string)
86+
}
87+
parsed = tf.parse_single_example(record, keys_to_feature)
88+
target_image = tf.decode_raw(parsed['reference'], tf.uint8)
89+
target_image = tf.cast(target_image, tf.float32)
90+
91+
target_image = tf.reshape(target_image, shape=[33, 33, 3])
92+
noisy_image = tf.decode_raw(parsed['noisy'], tf.uint8)
93+
noisy_image = tf.cast(noisy_image, tf.float32)
94+
noisy_image = tf.reshape(noisy_image, shape=[33, 33, 3])
95+
return noisy_image, target_image
96+
97+
def input_fn(self, filename):
98+
dataset = tf.data.TFRecordDataset(filename)
99+
dataset = dataset.map(self.parser)
100+
dataset = dataset.repeat()
101+
102+
dataset = dataset.batch(self.batch_size)
103+
iterator = dataset.make_one_shot_iterator()
104+
noisy_batch, target_batch = iterator.get_next()
105+
return noisy_batch, target_batch

model_weights.hdf5

737 KB
Binary file not shown.

noisy.bmp

25.7 MB
Binary file not shown.

predict.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import tensorflow as tf
21
import numpy as np
32
from PIL import Image
43
import sys
54
import getopt
6-
from model import DenoisingAutoEncoder
5+
from model_keras import DAE
76

87

98
def main(argv):
@@ -29,13 +28,12 @@ def main(argv):
2928
elif opt in ('-o', '--ofile'):
3029
output_file = arg
3130

32-
input_image = Image.open(input_file).convert('RGB').resize([3000, 3000])
33-
input_image_array = np.array(input_image).reshape(3000, 3000, 3)
34-
input_image_array = input_image_array / 255.0
35-
d = DenoisingAutoEncoder((50, 50, 3), (None, 50, 50, 3), tf.train.AdamOptimizer(), False)
36-
31+
input_image = Image.open(input_file).convert('RGB')
32+
input_image_array = np.array(input_image)
33+
d = DAE()
34+
d.load_model_weights('model_weights.hdf5')
3735
output_image = d.denoise(input_image_array)
38-
output_image.save(output_file, format='PNG')
36+
output_image.save(output_file, format='BMP')
3937

4038

4139
if __name__ == '__main__':
File renamed without changes.

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ sklearn
33
tensorflow
44
pillow
55
requests
6+
keras

0 commit comments

Comments
 (0)