File size: 5,101 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
#!/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


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

def get_dict(dict_path):
    """
    get dictionary in NAS/public_info
    :param : dict_path(string) location of the dictionary
    :return: dictionary in pandas format
    """
    if dict_path == 'default':
        dictionary = pd.read_excel(r'/home/ana/NAS_database/public_info/RT_dictionary.xlsx',  engine='openpyxl')
    else:
        dictionary = pd.read_excel(dict_path, engine='openpyxl')
    
    return dictionary

      
def set_header_info(nii_file, voxelsize, image_position_patient, contours_exist = None):
    nii_file.header['pixdim'][1] = voxelsize[0]
    nii_file.header['pixdim'][2] = voxelsize[1]
    nii_file.header['pixdim'][3] = voxelsize[2]
    
    #affine - voxelsize
    nii_file.affine[0][0] = voxelsize[0]
    nii_file.affine[1][1] = voxelsize[1]
    nii_file.affine[2][2] = voxelsize[2]
    #affine - imagecorner
    nii_file.affine[0][3] = image_position_patient[0]
    nii_file.affine[1][3] = image_position_patient[1]
    nii_file.affine[2][3] = image_position_patient[2]
    if contours_exist is not None:
        nii_file.header.extensions.append(nib.nifti1.Nifti1Extension(0, bytearray(contours_exist)))
    return nii_file


def get_struct_and_contoursexist(roi,arrayshape):
    struct = np.zeros((arrayshape[0],arrayshape[1],arrayshape[2]))
    roi_names = list(roi.keys())   
    contoursexist = []
    
    for i in range(len(roi_names)):
        if(not(roi[roi_names[i]] is None)):
            contoursexist.append(1)
            struct += (2**i)*roi[roi_names[i]]
        else:
            contoursexist.append(0)
    return struct, contoursexist


def save_images(dst_dir, voxelsize, image_position_patient, image, image_type, roi=None, dose=None, bdoses=None, prior_knowledge = None, spotmap = None):
    
    # encode in nii  and save at dst_dir
    # IMPORTANT WE NEED TO CONFIRM THE SIGNS OF THE ENTRIES IN THE AFFINE, 
    # ALTHOUGH MAYBE AT THE END THE IMPORTANCE IS HOW WE WILL USE THIS DATA .... 
    # also instead of changing field by field, the pixdim and affine can be encoded
    # using the set_sform method --> info here: https://nipy.org/nibabel/nifti_images.html
    
    # IMAGE (CT, MR ...)
    image_shape = image.shape
    image_nii = nib.Nifti1Image(image, affine=np.eye(4)) # for Nifti1 header, change for a Nifti2 type of header
    # Update header fields
    image_nii = set_header_info(image_nii, voxelsize, image_position_patient)
    # Save  nii 
    nib.save(image_nii, os.path.join(dst_dir,image_type.lower()+'.nii.gz'))
    
    # DOSE
    if dose is not None:
        dose_nii = nib.Nifti1Image(dose, affine=np.eye(4)) # for Nifti1 header, change for a Nifti2 type of header
        # Update header fields
        dose_nii = set_header_info(dose_nii, voxelsize, image_position_patient)
        # Save nii 
        nib.save(dose_nii, os.path.join(dst_dir,'dose.nii.gz'))

    # BDOSES
    if bdoses is not None:
        for b in range(len(bdoses)):
            bdose_nii = nib.Nifti1Image(bdoses[b].Image, affine=np.eye(4)) # for Nifti1 header, change for a Nifti2 type of header
            # Update header fields
            bdose_nii = set_header_info(bdose_nii, voxelsize, image_position_patient)
            # Save nii
            nib.save(bdose_nii, os.path.join(dst_dir,'dose_b{}.nii.gz'.format(b+1)))

    # PRIOR KNOWLEDGE 
    if prior_knowledge is not None:
        for charact, pk in prior_knowledge.items():
            prior_knowledge_nii = nib.Nifti1Image(pk, affine=np.eye(4)) # for Nifti1 header, change for a Nifti2 type of header
            # Update header fields
            prior_knowledge_nii = set_header_info(prior_knowledge_nii, voxelsize, image_position_patient)
            # Save nii 
            nib.save(prior_knowledge_nii, os.path.join(dst_dir,'prior_knowledge_{}.nii.gz'.format(charact.lower())))

    # RTSTRUCT
    if roi is not None:
        struct_compressed, contours_exist = get_struct_and_contoursexist(roi, image_shape)

        struct_nii_compressed = nib.Nifti1Image(struct_compressed, affine=np.eye(4)) # for Nifti1 header, change for a Nifti2 type of header
        # struct_nii_compressed.set_data_dtype('smallest')
        # Update header fields
        struct_nii_compressed = set_header_info(struct_nii_compressed, voxelsize, image_position_patient, contours_exist=contours_exist)
        # Save nii 
        nib.save(struct_nii_compressed, os.path.join(dst_dir,'struct.nii.gz'))