|
a |
|
b/seg_crop_pad_scale.py |
|
|
1 |
#!/usr/bin/env python3 |
|
|
2 |
""" |
|
|
3 |
Author : briancottle <briancottle@localhost> |
|
|
4 |
Date : 2023-01-02 |
|
|
5 |
Purpose: Cropping, padding, and scaling segmentations in preparation for 3D modeling |
|
|
6 |
""" |
|
|
7 |
|
|
|
8 |
import argparse |
|
|
9 |
from typing import NamedTuple |
|
|
10 |
import numpy as np |
|
|
11 |
import cv2 as cv |
|
|
12 |
import os |
|
|
13 |
import matplotlib.pyplot as plt |
|
|
14 |
import tqdm |
|
|
15 |
from natsort import natsorted |
|
|
16 |
from glob import glob |
|
|
17 |
import magic |
|
|
18 |
import re |
|
|
19 |
from PIL import Image |
|
|
20 |
|
|
|
21 |
class Args(NamedTuple): |
|
|
22 |
""" Command-line arguments """ |
|
|
23 |
tissue_chainID: str |
|
|
24 |
cropping: bool |
|
|
25 |
old_files: bool |
|
|
26 |
|
|
|
27 |
fid_seg: bool |
|
|
28 |
node_seg: bool |
|
|
29 |
unet_seg: bool |
|
|
30 |
high_res_seg: bool |
|
|
31 |
|
|
|
32 |
node_white: bool |
|
|
33 |
fid_white: bool |
|
|
34 |
|
|
|
35 |
reduction_size: int |
|
|
36 |
|
|
|
37 |
|
|
|
38 |
# -------------------------------------------------- |
|
|
39 |
def get_args() -> Args: |
|
|
40 |
""" Get command-line arguments """ |
|
|
41 |
|
|
|
42 |
parser = argparse.ArgumentParser( |
|
|
43 |
description='Cropping, padding, and scaling segmentations in preparation for 3D modeling', |
|
|
44 |
formatter_class=argparse.ArgumentDefaultsHelpFormatter) |
|
|
45 |
|
|
|
46 |
parser.add_argument('-t_id', |
|
|
47 |
'--tissue_chainID', |
|
|
48 |
type=str, |
|
|
49 |
metavar='chainID', |
|
|
50 |
help='ID used to identify where the tissue files are stored') |
|
|
51 |
|
|
|
52 |
parser.add_argument('-c', |
|
|
53 |
'--cropping', |
|
|
54 |
help='Boolean: Do you need to crop the uNet dataset first?', |
|
|
55 |
action='store_true') |
|
|
56 |
|
|
|
57 |
parser.add_argument('-o', |
|
|
58 |
'--old_files', |
|
|
59 |
help='Is the dataset of interest from the old set?', |
|
|
60 |
action='store_true') |
|
|
61 |
|
|
|
62 |
parser.add_argument('-f', |
|
|
63 |
'--fid_seg', |
|
|
64 |
help='Do you want to process the fiduciary segmentations?', |
|
|
65 |
action='store_true') |
|
|
66 |
|
|
|
67 |
parser.add_argument('-n', |
|
|
68 |
'--node_seg', |
|
|
69 |
help='Do you want to process the nodal segmentations?', |
|
|
70 |
action='store_true') |
|
|
71 |
|
|
|
72 |
parser.add_argument('-u', |
|
|
73 |
'--unet_seg', |
|
|
74 |
help='Do you want to process the uNet segmentations?', |
|
|
75 |
action='store_true') |
|
|
76 |
|
|
|
77 |
parser.add_argument('-d', |
|
|
78 |
'--high_res_seg', |
|
|
79 |
help='Do you want to process the high_res segmentations?', |
|
|
80 |
action='store_true') |
|
|
81 |
|
|
|
82 |
parser.add_argument('-i', |
|
|
83 |
'--node_white', |
|
|
84 |
help='Is the segmentation for the node inverted?', |
|
|
85 |
action='store_true') |
|
|
86 |
|
|
|
87 |
parser.add_argument('-j', |
|
|
88 |
'--fid_white', |
|
|
89 |
help='Is the segmentation for the fiduciary inverted?', |
|
|
90 |
action='store_true') |
|
|
91 |
|
|
|
92 |
parser.add_argument('-r', |
|
|
93 |
'--reduction_size', |
|
|
94 |
help='what scalar to use for reducing the size(4 or 8), default is 4', |
|
|
95 |
metavar='int', |
|
|
96 |
type=int, |
|
|
97 |
default=4) |
|
|
98 |
|
|
|
99 |
|
|
|
100 |
|
|
|
101 |
args = parser.parse_args() |
|
|
102 |
|
|
|
103 |
return Args(args.tissue_chainID, |
|
|
104 |
args.cropping, |
|
|
105 |
args.old_files, |
|
|
106 |
args.fid_seg, |
|
|
107 |
args.node_seg, |
|
|
108 |
args.unet_seg, |
|
|
109 |
args.high_res_seg, |
|
|
110 |
args.node_white, |
|
|
111 |
args.fid_white, |
|
|
112 |
args.reduction_size) |
|
|
113 |
|
|
|
114 |
|
|
|
115 |
# -------------------------------------------------- |
|
|
116 |
def main() -> None: |
|
|
117 |
""" Make a jazz noise here """ |
|
|
118 |
|
|
|
119 |
args = get_args() |
|
|
120 |
|
|
|
121 |
TissueChainID = args.tissue_chainID |
|
|
122 |
cropping = args.cropping |
|
|
123 |
old_files = args.old_files |
|
|
124 |
fiduciary_files = args.fid_seg |
|
|
125 |
nodal_files = args.node_seg |
|
|
126 |
seg_files = args.unet_seg |
|
|
127 |
high_res_files = args.high_res_seg |
|
|
128 |
nodal_white = args.node_white |
|
|
129 |
fiduciary_white = args.fid_white |
|
|
130 |
reduction_size = args.reduction_size |
|
|
131 |
|
|
|
132 |
if reduction_size == 4: |
|
|
133 |
reduction_name = 'QuarterScale' |
|
|
134 |
|
|
|
135 |
if reduction_size == 8: |
|
|
136 |
reduction_name = 'EighthScale' |
|
|
137 |
|
|
|
138 |
|
|
|
139 |
base_directory = '/var/confocaldata/HumanNodal/HeartData/'+ TissueChainID |
|
|
140 |
JPG_directory = '/var/confocaldata/HumanNodal/HeartData/'+ TissueChainID +'JPG/' |
|
|
141 |
jpg_file_names = glob(JPG_directory + '*.jpg') |
|
|
142 |
|
|
|
143 |
|
|
|
144 |
if old_files: |
|
|
145 |
ML_directory = '/var/confocaldata/HumanNodal/HeartData/'+ TissueChainID +'uNet_Segmentations/' |
|
|
146 |
Nodal_Seg_directory = '/var/confocaldata/HumanNodal/HeartData/'+ TissueChainID +'Segmentations/Nodal Segmentation FullScale_NoPad/' |
|
|
147 |
if fiduciary_files: |
|
|
148 |
Fiduciary_Seg_directory = '/var/confocaldata/HumanNodal/HeartData/'+ TissueChainID +'Segmentations/Fiduciary Segmentation FullScale_NoPad/' |
|
|
149 |
else: |
|
|
150 |
ML_directory = '/var/confocaldata/HumanNodal/HeartData/'+ TissueChainID +'uNet_Segmentations/' |
|
|
151 |
Nodal_Seg_directory = '/var/confocaldata/HumanNodal/HeartData/'+ TissueChainID +'Segmentations/Nodal Segmentation/' |
|
|
152 |
if fiduciary_files: |
|
|
153 |
Fiduciary_Seg_directory = '/var/confocaldata/HumanNodal/HeartData/'+ TissueChainID +'Segmentations/Fiduciary Segmentation/' |
|
|
154 |
|
|
|
155 |
high_res_directory = '/var/confocaldata/HumanNodal/HeartData/'+ TissueChainID +'HighResSeg/' |
|
|
156 |
|
|
|
157 |
os.chdir(ML_directory) |
|
|
158 |
jpg_file_names = natsorted(jpg_file_names) |
|
|
159 |
padding_size = 4000 # + 1536 |
|
|
160 |
|
|
|
161 |
# %% USE THIS SECTION FOR CROPPING THE SEGMENTATIONS AFTER THE UNET HAS AT IT |
|
|
162 |
if cropping: |
|
|
163 |
for idx in tqdm.tqdm(range(len(jpg_file_names))): |
|
|
164 |
|
|
|
165 |
out_directory = './../Cropped_uNet_Segmentations/' |
|
|
166 |
|
|
|
167 |
# create the directory for saving if it doesn't already exist |
|
|
168 |
if not os.path.isdir(out_directory): |
|
|
169 |
os.mkdir(out_directory) |
|
|
170 |
|
|
|
171 |
os.chdir(out_directory) |
|
|
172 |
|
|
|
173 |
jpg_file = jpg_file_names[idx] |
|
|
174 |
id = jpg_file.split('/')[-1].split('.')[0] |
|
|
175 |
id = id.split('_')[0] + '_' + id.split('_')[1] + '_' + id.split('_')[2] |
|
|
176 |
ml_file = glob(ML_directory + f'{id}_*.png')[0] |
|
|
177 |
|
|
|
178 |
jpg_image1 = cv.imread(jpg_file) |
|
|
179 |
ml_image1 = cv.imread(ml_file)[:,:,0] |
|
|
180 |
[x,y,z] = jpg_image1.shape |
|
|
181 |
|
|
|
182 |
cropped_ml1 = ml_image1[padding_size:padding_size+x, |
|
|
183 |
padding_size:padding_size+y] |
|
|
184 |
|
|
|
185 |
cv.imwrite( |
|
|
186 |
id + |
|
|
187 |
f'_CroppedSeg.png', |
|
|
188 |
cropped_ml1 |
|
|
189 |
) |
|
|
190 |
|
|
|
191 |
# %% |
|
|
192 |
ML_directory = '/var/confocaldata/HumanNodal/HeartData/'+ TissueChainID +'Cropped_uNet_Segmentations/' |
|
|
193 |
ml_file_names = glob(ML_directory + '*.png') |
|
|
194 |
all_image_sizes = [] |
|
|
195 |
for file_name in ml_file_names: |
|
|
196 |
header = magic.from_file(file_name) |
|
|
197 |
size = re.search('(\d+) x (\d+)',header).groups() |
|
|
198 |
sizes = [int(a) for a in size] |
|
|
199 |
all_image_sizes.append(sizes) |
|
|
200 |
|
|
|
201 |
max_width = np.max(np.asarray(all_image_sizes)[:,0]) |
|
|
202 |
max_height = np.max(np.asarray(all_image_sizes)[:,1]) |
|
|
203 |
|
|
|
204 |
idx = 200 |
|
|
205 |
additional_padding = 4000 |
|
|
206 |
os.chdir(JPG_directory) |
|
|
207 |
out_big_directory = base_directory + 'Padded_Images/' |
|
|
208 |
out_small_directory = base_directory + 'Padded_Images_' + reduction_name + '/' |
|
|
209 |
out_parent_list = [out_big_directory,out_small_directory] |
|
|
210 |
out_list = [] |
|
|
211 |
if not os.path.isdir(out_big_directory): |
|
|
212 |
os.mkdir(out_big_directory) |
|
|
213 |
|
|
|
214 |
if not os.path.isdir(out_small_directory): |
|
|
215 |
os.mkdir(out_small_directory) |
|
|
216 |
|
|
|
217 |
for idx, out_directory in enumerate(out_parent_list): |
|
|
218 |
jpg_out = out_directory + 'JPG' |
|
|
219 |
seg_out = out_directory + 'Seg' |
|
|
220 |
nodal_out = out_directory + 'Nodal' |
|
|
221 |
fiduciary_out = out_directory + 'Fiduciary' |
|
|
222 |
high_res_out = out_directory + 'HighRes' |
|
|
223 |
out_list.append([jpg_out,seg_out,nodal_out,high_res_out,fiduciary_out]) |
|
|
224 |
|
|
|
225 |
for directory in out_list[idx]: |
|
|
226 |
if not os.path.isdir(directory): |
|
|
227 |
os.mkdir(directory) |
|
|
228 |
|
|
|
229 |
|
|
|
230 |
|
|
|
231 |
for idx in tqdm.tqdm(range(len(jpg_file_names))): |
|
|
232 |
|
|
|
233 |
jpg_file = jpg_file_names[idx] |
|
|
234 |
id = jpg_file.split('/')[-1].split('.')[0] |
|
|
235 |
id = id.split('_')[0] + '_' + id.split('_')[1] + '_' + id.split('_')[2] |
|
|
236 |
|
|
|
237 |
|
|
|
238 |
|
|
|
239 |
# Create a separate section for the nodal tissue stuff, as it looks like |
|
|
240 |
# nodal segmentation will actually happen after the registration using the |
|
|
241 |
# segmentations |
|
|
242 |
# change this to _*.png if you are not using the FullScale_NoPad segmentations |
|
|
243 |
# will need to scale the segmentations for newer segmentations that haven't been |
|
|
244 |
# performed using previously padded images. This section is below, starting with |
|
|
245 |
|
|
|
246 |
|
|
|
247 |
jpg_image = cv.imread(jpg_file) |
|
|
248 |
[height,width,z] = jpg_image.shape |
|
|
249 |
|
|
|
250 |
height_diff = max_height - height |
|
|
251 |
width_diff = max_width - width |
|
|
252 |
|
|
|
253 |
if height_diff%2 == 1: |
|
|
254 |
pad_top = np.floor(height_diff/2) + additional_padding |
|
|
255 |
pad_bottom = np.floor(height_diff/2) + additional_padding |
|
|
256 |
pad_bottom += 1 |
|
|
257 |
else: |
|
|
258 |
pad_top = np.floor(height_diff/2) + additional_padding |
|
|
259 |
pad_bottom = np.floor(height_diff/2) + additional_padding |
|
|
260 |
|
|
|
261 |
if width_diff%2 == 1: |
|
|
262 |
pad_left = np.floor(width_diff/2) + additional_padding |
|
|
263 |
pad_right = np.floor(width_diff/2) + additional_padding |
|
|
264 |
pad_right += 1 |
|
|
265 |
else: |
|
|
266 |
pad_left = np.floor(width_diff/2) + additional_padding |
|
|
267 |
pad_right = np.floor(width_diff/2) + additional_padding |
|
|
268 |
|
|
|
269 |
padded_jpg = cv.copyMakeBorder(jpg_image, |
|
|
270 |
int(pad_top), |
|
|
271 |
int(pad_bottom), |
|
|
272 |
int(pad_left), |
|
|
273 |
int(pad_right), |
|
|
274 |
borderType=cv.cv2.BORDER_CONSTANT, |
|
|
275 |
value=[255,255,255]) |
|
|
276 |
|
|
|
277 |
os.chdir(out_list[0][0]) |
|
|
278 |
cv.imwrite( |
|
|
279 |
id + |
|
|
280 |
f'_Padded.png', |
|
|
281 |
padded_jpg |
|
|
282 |
) |
|
|
283 |
|
|
|
284 |
[pad_height,pad_width,z] = padded_jpg.shape |
|
|
285 |
|
|
|
286 |
|
|
|
287 |
width_small = int(pad_width/reduction_size) |
|
|
288 |
height_small = int(pad_height/reduction_size) |
|
|
289 |
jpg_small = cv.resize(padded_jpg,[width_small,height_small],cv.INTER_AREA) |
|
|
290 |
|
|
|
291 |
os.chdir(out_list[1][0]) |
|
|
292 |
cv.imwrite( |
|
|
293 |
id + |
|
|
294 |
f'_Padded_' + reduction_name + '.png', |
|
|
295 |
jpg_small |
|
|
296 |
) |
|
|
297 |
|
|
|
298 |
|
|
|
299 |
if seg_files: |
|
|
300 |
ml_file = glob(ML_directory + f'{id}_*.png')[0] |
|
|
301 |
ml_image = cv.imread(ml_file)[:,:,0] |
|
|
302 |
padded_seg = cv.copyMakeBorder(ml_image, |
|
|
303 |
int(pad_top), |
|
|
304 |
int(pad_bottom), |
|
|
305 |
int(pad_left), |
|
|
306 |
int(pad_right), |
|
|
307 |
borderType=cv.cv2.BORDER_CONSTANT, |
|
|
308 |
value=[0,0,0]) |
|
|
309 |
os.chdir(out_list[0][1]) |
|
|
310 |
cv.imwrite( |
|
|
311 |
id + |
|
|
312 |
f'_Padded_Seg.png', |
|
|
313 |
padded_seg |
|
|
314 |
) |
|
|
315 |
|
|
|
316 |
seg_small = np.array(Image.fromarray(padded_seg).resize((width_small,height_small), Image.NEAREST)) |
|
|
317 |
os.chdir(out_list[1][1]) |
|
|
318 |
cv.imwrite( |
|
|
319 |
id + |
|
|
320 |
f'_Padded_Seg_' + reduction_name + '.png', |
|
|
321 |
seg_small |
|
|
322 |
) |
|
|
323 |
|
|
|
324 |
|
|
|
325 |
if nodal_files: |
|
|
326 |
|
|
|
327 |
if old_files: |
|
|
328 |
nodal_file = glob(Nodal_Seg_directory + f'{id}-*.png')[0] |
|
|
329 |
else: |
|
|
330 |
nodal_file = glob(Nodal_Seg_directory + f'{id}_*.png')[0] |
|
|
331 |
|
|
|
332 |
nodal_image = cv.imread(nodal_file)[:,:,0] |
|
|
333 |
# be warry of this, you may need to use this later, though I'm not sure what |
|
|
334 |
# it was originally used for. |
|
|
335 |
if nodal_white: |
|
|
336 |
if sum(sum(nodal_image)) > 0: |
|
|
337 |
nodal_image = ~nodal_image |
|
|
338 |
# This accounts for the nodal segmentation images being a quarter the |
|
|
339 |
# original size, but you should make sure that you haven't already done the |
|
|
340 |
# fullscale noPad stuff yet |
|
|
341 |
if ~old_files: |
|
|
342 |
nodal_image = np.array(Image.fromarray(nodal_image).resize((width,height), Image.NEAREST)) |
|
|
343 |
|
|
|
344 |
padded_nodal = cv.copyMakeBorder(nodal_image, |
|
|
345 |
int(pad_top), |
|
|
346 |
int(pad_bottom), |
|
|
347 |
int(pad_left), |
|
|
348 |
int(pad_right), |
|
|
349 |
borderType=cv.cv2.BORDER_CONSTANT, |
|
|
350 |
value=[0,0,0]) |
|
|
351 |
|
|
|
352 |
os.chdir(out_list[0][2]) |
|
|
353 |
cv.imwrite( |
|
|
354 |
id + |
|
|
355 |
f'_Padded_Nodal.png', |
|
|
356 |
padded_nodal |
|
|
357 |
) |
|
|
358 |
|
|
|
359 |
nodal_small = np.array(Image.fromarray(padded_nodal).resize((width_small,height_small), Image.NEAREST)) |
|
|
360 |
os.chdir(out_list[1][2]) |
|
|
361 |
cv.imwrite( |
|
|
362 |
id + |
|
|
363 |
f'_Padded_Nodal_' + reduction_name + '.png', |
|
|
364 |
nodal_small |
|
|
365 |
) |
|
|
366 |
|
|
|
367 |
|
|
|
368 |
|
|
|
369 |
|
|
|
370 |
|
|
|
371 |
if high_res_files: |
|
|
372 |
high_res_file = glob(high_res_directory + f'{id}_*.png')[0] |
|
|
373 |
high_res_image = cv.imread(high_res_file)[:,:,0] |
|
|
374 |
|
|
|
375 |
padded_high_res = cv.copyMakeBorder(high_res_image, |
|
|
376 |
int(pad_top), |
|
|
377 |
int(pad_bottom), |
|
|
378 |
int(pad_left), |
|
|
379 |
int(pad_right), |
|
|
380 |
borderType=cv.cv2.BORDER_CONSTANT, |
|
|
381 |
value=[0,0,0]) |
|
|
382 |
|
|
|
383 |
|
|
|
384 |
os.chdir(out_list[0][3]) |
|
|
385 |
cv.imwrite( |
|
|
386 |
id + |
|
|
387 |
f'_Padded_HighRes.png', |
|
|
388 |
padded_high_res |
|
|
389 |
) |
|
|
390 |
|
|
|
391 |
high_res_small = np.array(Image.fromarray(padded_high_res).resize((width_small,height_small), Image.NEAREST)) |
|
|
392 |
os.chdir(out_list[1][3]) |
|
|
393 |
cv.imwrite( |
|
|
394 |
id + |
|
|
395 |
f'_Padded_HighRes_' + reduction_name + '.png', |
|
|
396 |
high_res_small |
|
|
397 |
) |
|
|
398 |
|
|
|
399 |
|
|
|
400 |
|
|
|
401 |
|
|
|
402 |
|
|
|
403 |
if fiduciary_files: |
|
|
404 |
if old_files: |
|
|
405 |
fiduciary_file = glob(Fiduciary_Seg_directory + f'{id}-*.png')[0] |
|
|
406 |
else: |
|
|
407 |
fiduciary_file = glob(Fiduciary_Seg_directory + f'{id}_*.png')[0] |
|
|
408 |
|
|
|
409 |
fiduciary_image = cv.imread(fiduciary_file)[:,:,0] |
|
|
410 |
|
|
|
411 |
if fiduciary_white: |
|
|
412 |
if sum(sum(fiduciary_image)) > 0: |
|
|
413 |
fiduciary_image = ~fiduciary_image |
|
|
414 |
|
|
|
415 |
if ~old_files: |
|
|
416 |
fiduciary_image = np.array(Image.fromarray(fiduciary_image).resize((width,height), Image.NEAREST)) |
|
|
417 |
|
|
|
418 |
padded_fiduciary = cv.copyMakeBorder(fiduciary_image, |
|
|
419 |
int(pad_top), |
|
|
420 |
int(pad_bottom), |
|
|
421 |
int(pad_left), |
|
|
422 |
int(pad_right), |
|
|
423 |
borderType=cv.cv2.BORDER_CONSTANT, |
|
|
424 |
value=[0,0,0]) |
|
|
425 |
os.chdir(out_list[0][4]) |
|
|
426 |
cv.imwrite( |
|
|
427 |
id + |
|
|
428 |
f'_Padded_Fiduciary.png', |
|
|
429 |
padded_fiduciary |
|
|
430 |
) |
|
|
431 |
|
|
|
432 |
fiduciary_small = np.array(Image.fromarray(padded_fiduciary).resize((width_small,height_small), Image.NEAREST)) |
|
|
433 |
os.chdir(out_list[1][4]) |
|
|
434 |
cv.imwrite( |
|
|
435 |
id + |
|
|
436 |
f'_Padded_Fiduciary_' + reduction_name + '.png', |
|
|
437 |
fiduciary_small |
|
|
438 |
) |
|
|
439 |
|
|
|
440 |
# %% |
|
|
441 |
|
|
|
442 |
|
|
|
443 |
# -------------------------------------------------- |
|
|
444 |
if __name__ == '__main__': |
|
|
445 |
main() |