-
Notifications
You must be signed in to change notification settings - Fork 0
/
scikiImage_generator.py
318 lines (236 loc) · 13.1 KB
/
scikiImage_generator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
import glob
import os
import random
import Augmentor
import cv2
import numpy as np
from matplotlib import pyplot as plt
from PIL import Image
from skimage import img_as_ubyte, io
from skimage import transform as t
from skimage import util
from skimage.filters import threshold_otsu
from skimage.metrics import peak_signal_noise_ratio
from skimage.morphology import closing, disk, opening
def psnr(path_to_original_image,path_to_noisy_image):
'''
This function finds the peak signal to noise ratio for two given images.
:param path_to_original_image : path to original noise-free image
:param path_to_noisy_image : path to noisy image
:returns Float value for the psnr of the two images.
'''
img1 = io.imread(path_to_original_image)
img2 = io.imread(path_to_noisy_image)
psnr = peak_signal_noise_ratio(img1, img2)
return psnr
def one_psnr(path_to_image,axis=None, ddof=0):
'''
This function finds the peak signal to noise ratio for a single image.
:param path_to_image : path to source image
:returns Float value for the psnr of the given image.
'''
a = io.imread(path_to_image)
a = np.asanyarray(a)
m = a.mean(axis)
sd = a.std(axis=axis, ddof=ddof)
return np.where(sd == 0, 0, m/sd) * 100
def simple_artifact_generator(image):
'''
This function generates images with simple square shaped masks placed randomly over the input images.
:paramimage: Input image
'''
height,width = image.shape[0],image.shape[1]
artifact = np.ones((200,200),dtype='uint16') * 255
x0,y0 = np.random.randint(0,width - 200),np.random.randint(0,height - 200)
image[x0:x0+200,y0:y0+200] = artifact
return image
def artificial_artifacts_generator(gt_image_generator,masked_image_generator):
'''
This function generates images with irregular shaped artifacts.
:param gt_image_generator : A ground truth image generator.
:param masked_image_generator : A masked image generator.
'''
for gt_image, masked_image in zip(gt_image_generator, masked_image_generator):
mod_image = cv2.add(gt_image,masked_image)
yield mod_image
def ground_truth_generator(path_to_ground_truth):
'''
This function generates ground truth images which do not contain any artifacts.
:param path_to_ground_truth : Path to ground truth data.
'''
list_of_rows = ['E','F','G','H']
list_of_columns = ['02','03','04','05']
filelist = os.listdir(path_to_ground_truth)
for file in filelist[:]:
#Example : 151130-AY-artifacts-10x-6dapi_E01_s4_w3.tif
if file.endswith(".TIF") and not file[-9:-4] =="Thumb" and file[30:33] !='E03' and file[30:33] != 'G04':
if file[30] in list_of_rows and file[31:33] in list_of_columns:
gt_image = io.imread(os.path.join(path_to_ground_truth, file), plugin='tifffile')
min = gt_image.min()
max = gt_image.max()
gt_image = gt_image.astype('float32')
#MinMax Normalization for better image contrast.
gt_image -= min
gt_image /= (max-min)
yield gt_image
def convert_scale_0_to_255(path_to_ground_truth):
'''
This function converts an image from range [0,1] to range [0,255]
:param path_to_ground_truth : Path to ground truth data.
'''
filelist = os.listdir(path_to_ground_truth)
for file in filelist[:]:
gt_image = io.imread(os.path.join(path_to_ground_truth, file), plugin='tifffile')
min = gt_image.min()
max = gt_image.max()
gt_image = gt_image.astype('float32')
# MinMax Normalization for better image contrast.
gt_image -= min
gt_image /= (max - min)
gt_image *= 255
#io.imsave(os.path.join(path_to_ground_truth, file),gt_image)
def ground_truth_generator_0_to_255(path_to_ground_truth):
'''
This function generates ground truth images which do not contain any artifacts.
:param path_to_ground_truth : Path to ground truth data.
'''
list_of_rows = ['E', 'F', 'G', 'H']
list_of_columns = ['02', '03', '04', '05']
filelist = os.listdir(path_to_ground_truth)
for file in filelist[:]:
# Example : 151130-AY-artifacts-10x-6dapi_E01_s4_w3.tif
if file.endswith(".TIF") and not file[-9:-4] == "Thumb" and file[30:33] != 'E03' and file[30:33] != 'G04':
if file[30] in list_of_rows and file[31:33] in list_of_columns:
gt_image = io.imread(os.path.join(path_to_ground_truth, file), plugin='tifffile')
min = gt_image.min()
max = gt_image.max()
gt_image = gt_image.astype('float32')
# MinMax Normalization for better image contrast.
gt_image -= min
gt_image /= (max - min)
gt_image *= 255
yield file,gt_image
def masked_image_generator(path):
'''
This function implements Otsu thresholding followed by binary open & close operations to generate masks for pre-training.
:param path : Path to the folder containing the images.
'''
filename = ''
count = 0
footprint = disk(1)
list_of_rows = ['B', 'C', 'D','E']
filelist = os.listdir(path)
random.shuffle(filelist)
for file in filelist[:]:
#Example : 151130-AY-artifacts-10x-6cfp_A05_s1_w3.tif
if file.endswith(".TIF") and not file[-9:-4] == "Thumb" and file[29] in list_of_rows :
filename = file.split(".")[0]
raw_image = io.imread(os.path.join(path,file), plugin='tifffile')
threshold = threshold_otsu(raw_image) #Otsu thresholding
if threshold > 200:
binary = raw_image>threshold * 0.7 #Masked image.Multiplied by 0.7 to produce better masks.
binary = img_as_ubyte(binary)
binary_inverted = util.invert(binary) #Invert colorscale of image to make it suitable for morphological operations.
closed = closing(binary_inverted, footprint) #Close operation on binary image.
opened_and_closed = opening(closed,footprint) #Open operation after close operation to reproduce some fine-grained artifacts.
opened_and_closed_inverted = util.invert(opened_and_closed) #Invert intensity scale of final image.(To get black background with white foreground)
opened_and_closed_inverted =opened_and_closed_inverted.astype('float32')
yield opened_and_closed_inverted
def zoom(img, zoom_factor=1.5):
'''
This function generates zoomed images.
:param img : Image to be zoomed.
:param zoom_factor = Zooming factor.
'''
zoomed_image = t.resize((t.rescale(img,zoom_factor,anti_aliasing=True)),(256,256),anti_aliasing=True) # Set size of resulting images to 256 * 256
return zoomed_image
def zoomed_images_generator(image_generator):
'''
This function takes 16-bit raw images as input and generates their corresponding zoomed images using scikit-image.
:param image_generator : Any image genertator.
'''
count = 0
for raw_image in image_generator:
cropping_factor = 12
cropping_height, cropping_width = raw_image.shape[0]//cropping_factor,raw_image.shape[1]//cropping_factor
height_offset = 0 # Used to vertically traverse a single image.
while cropping_height + height_offset <= raw_image.shape[0]:
width_offset = 0 # Used to horizontally traverse a single image.
while cropping_width + width_offset <= raw_image.shape[1]:
cropped_image = raw_image[height_offset:cropping_height + height_offset,width_offset:cropping_width+width_offset]
# width_offset is used to horizontally traverse a single image.
zoomed_and_cropped_image = zoom(cropped_image)
zoomed_and_cropped_image = cv2.normalize(zoomed_and_cropped_image, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
mean = np.mean(zoomed_and_cropped_image)
if 50 > mean > 20 : #Min intensity criteria to avoid blank zoomed images.
io.imsave(f'D:/DeDustProject/data/Pure_Artifacts/{count}.PNG',zoomed_and_cropped_image)
count+=1
if count == 8000 :
return
width_offset += 180 # raw_image.shape[0]/20 = 108. This gives 19 zoomed images.
height_offset += cropping_height #Traverse down the image.
def zoomed_images_generator_from_path(path):
'''
This function takes 16-bit raw images as input and generates their corresponding zoomed images using scikit-image.
:param image_generator : Any image genertator.
'''
for file in os.listdir(path):
count = 0
raw_image = io.imread(os.path.join(path,file),plugin='tifffile')
cropping_factor = 12
cropping_height, cropping_width = raw_image.shape[0] // cropping_factor, raw_image.shape[1] // cropping_factor
height_offset = 0 # Used to vertically traverse a single image.
while cropping_height + height_offset <= raw_image.shape[0]:
width_offset = 0 # Used to horizontally traverse a single image.
while cropping_width + width_offset <= raw_image.shape[1]:
cropped_image = raw_image[height_offset:cropping_height + height_offset,
width_offset:cropping_width + width_offset]
# width_offset is used to horizontally traverse a single image.
zoomed_and_cropped_image = zoom(cropped_image)
max = zoomed_and_cropped_image.max()
mean = zoomed_and_cropped_image.mean()
#if max >= 0.140:
if mean >= 14.0: #Min intensity criteria to avoid blank zoomed images.
io.imsave('D:/DeDustProject/data/zoomed_masked_images_new/{}_{}.PNG'.format(file[:-4],count),zoomed_and_cropped_image)
count += 1
width_offset += 180 # raw_image.shape[0]/20 = 108. This gives 19 zoomed images.
height_offset += cropping_height # Traverse down the image.
def zoomed_images_for_ground_truth(images_generator):
'''
This function takes 16-bit raw images as input and generates their corresponding zoomed images.
:param images_generator:Any image generator.
'''
#path = 'D:/DeDustProject/Artifacts/Artifacts/cfp_6_exp_times'
for filename,gt_image in images_generator:
cropping_factor = 12
cropping_height, cropping_width = gt_image.shape[0]//cropping_factor,gt_image.shape[1]//cropping_factor
height_offset = 0 #Used to vertically traverse a single image.
image_count = 0 #Used to keep track of zoomed images generated from a single ground truth image.
while cropping_height + height_offset <= gt_image.shape[0]:
width_offset = 0 #Used to horizontally traverse a single image.
while cropping_width + width_offset <= gt_image.shape[1]:
cropped_image = gt_image[height_offset:cropping_height + height_offset,width_offset:cropping_width+width_offset]
# width_offset is used to horizontally traverse a single image.
zoomed_and_cropped_image = zoom(cropped_image,1.5)
max = zoomed_and_cropped_image.max()
mean = zoomed_and_cropped_image.mean()
mean_intensity_criteria = (filename[30] =='E' and mean >0.011*255) or (filename[30] =='F' and mean >0.011*255) or (filename[30] =='G' and mean >0.018*255) or (filename[30] =='H' and mean >0.018*255)
if max>=0.140*255:
if mean_intensity_criteria:
io.imsave("D:/DeDustProject/data/final_images_zoomed/gt_images_zoomed_255/{}_{}_zoomed.TIF".format(filename[:-4],image_count), zoomed_and_cropped_image)
image_count += 1
width_offset += 180 # raw_image.shape[0]/12 = 180. This gives 11 zoomed images for each horizontal traversal of the image.
height_offset += cropping_height #Traverse down the image.
def augment_images(path):
'''
This function generates augmented images from a collection of multiple source images.
:param path : Path to source images.
'''
p = Augmentor.Pipeline(path)
#Defining augmentation parameters and generating 36112 samples
p.flip_left_right(0.5)
#p.black_and_white(0.1)
p.rotate(0.3, 10, 10)
p.skew(0.4, 0.5)
p.zoom(probability=0.2, min_factor=1.1, max_factor=1.3)
p.sample(8000)