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()