File size: 5,174 Bytes
b51cd04
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Sat Sep  5 20:34:46 2020

@author: ana
"""


# import general libraries
import os
import numpy as np
import pandas as pd
import scipy
import nibabel as nib
import pydicom
import glob
import warnings
from copy import deepcopy
from scipy.ndimage import find_objects
from scipy.ndimage.morphology import binary_fill_holes
from skimage import measure
from matplotlib.patches import Polygon
from libraries.utils_nii_dicom import set_header_info


###############################################################################
###################################   FUNCTIONS   #############################
###############################################################################

def delete_all(obj):
    for i in vars(obj):
        del obj.i

def overwrite_ct_threshold(ct_image, body = None, artefact = None, contrast = None):
    # Change the HU out of the body to air: -1000    
    if body is not None:
        # Change the HU outside the body to -1000
        ct_image[body==0]=-1000
    if artefact is not None:
        # Change the HU to muscle: 14
        ct_image[artefact==1]=14
    if contrast is not None:
        # Change the HU to water: 0 Houndsfield Unit: CT unit
        ct_image[contrast==1]=0
    # Threshold above 1560HU
    ct_image[ct_image > 1560] = 1560
    return ct_image

def remove_dose_outside_mask(dose, mask = None):
    # Put dose = 0 outside the mask (typically the body)   
    if mask is not None:
        dose[mask==0]=0
    return dose

def get_and_save_tv(roi, nib_header, tv_names, dst_dir):
    tv = np.zeros(nib_header['dim'][1:4])
    roi_names = list(roi.keys())
    if tv_names is not None:
        for c in tv_names:
            if c in roi_names:
                tv[roi[c]>0]=int(c.split('_')[1])/100
                
    # create nii, update header and save
    save_nii_image(tv, nib_header,dst_dir, 'struct_tv')

    return tv

def get_and_save_oars(roi, nib_header, oar_names, dst_dir):
    oars = np.zeros(nib_header['dim'][1:4])
    
    roi_names = list(roi.keys())
    contoursexist = []
    
    if oar_names is not None:
        for i in range(len(oar_names)):
            if oar_names[i] in roi_names:
                if roi[oar_names[i]] is not None:
                    contoursexist.append(1)
                    oars += (2**i)*roi[oar_names[i]]
                else:
                    contoursexist.append(0)        
                    
    # create nii, update header and save 
    save_nii_image(oars, nib_header,dst_dir, 'struct_oar', contours_exist = contoursexist)

        
def get_and_save_sample_probability(tv,dst_dir):
    # get sample probability for patch-based training
    bufftv=np.zeros_like(tv)
    bufftv[tv!=0]=1
    m=bufftv.sum(axis=0).sum(axis=0).sum()/1000
    sample_probability_slc=(bufftv.sum(axis=0).sum(axis=0)+m)/(bufftv.sum(axis=0).sum(axis=0)+m).sum()
    sample_probability_row=(bufftv.sum(axis=1).sum(axis=1)+m)/(bufftv.sum(axis=1).sum(axis=1)+m).sum()
    sample_probability_col=(bufftv.sum(axis=0).sum(axis=-1)+m)/(bufftv.sum(axis=0).sum(axis=-1)+m).sum()
    
    np.savez_compressed(os.path.join(dst_dir,'sample_probability_row.npz'),sample_probability_row)
    np.savez_compressed(os.path.join(dst_dir,'sample_probability_col.npz'),sample_probability_col)
    np.savez_compressed(os.path.join(dst_dir,'sample_probability_slc.npz'),sample_probability_slc)
    

def decompress_struct(struct_nib,struct_list):
    
    struct_data = struct_nib.get_fdata()
    roi = dict.fromkeys(struct_list, None) 
    # get contourexists from header
    contoursexist = list(struct_nib.header.extensions[0].get_content())
    for i in range(len(contoursexist)):
        if contoursexist[i] == 1:
            roi[struct_list[i]] = np.bitwise_and(struct_data.astype(int), 2 ** i).astype(bool)

    return roi

def binary_to_integers(struct,select_list):
        
    roi_names = list(struct.keys())
    # get shape
    for k in roi_names:
        if struct[k] is not None:
            struct_shape = struct[k].shape
    # initialize roi
    roi = np.zeros(struct_shape)     
    
    # initialize label
    label = 0
    for i in range(len(select_list)):
        label = label + 1
        if select_list[i] in roi_names:
            if struct[select_list[i]] is not None:
                # populate roi matrix with selected rois in select_list
                roi[struct[select_list[i]]] = label
        
    return roi

def save_nii_image(nib_img, nib_header,dst_dir, image_name, contours_exist = None):
    
    image_nii = nib.Nifti1Image(nib_img, affine=np.eye(4)) # for Nifti1 header, change for a Nifti2 type of header
    # Update header fields
    if contours_exist is not None:
        image_nii = set_header_info(image_nii, nib_header['pixdim'][1:4], [nib_header['qoffset_x'],nib_header['qoffset_y'],nib_header['qoffset_z']], contours_exist = contours_exist)
    else:
        image_nii = set_header_info(image_nii, nib_header['pixdim'][1:4], [nib_header['qoffset_x'],nib_header['qoffset_y'],nib_header['qoffset_z']])
    # Save  nii 
    nib.save(image_nii, os.path.join(dst_dir,image_name +'.nii.gz'))