Diff of /utils.py [000000] .. [4f54f1]

Switch to unified view

a b/utils.py
1
import os
2
import cv2
3
import math
4
import imutils
5
6
import numpy as np
7
import pandas as pd
8
import matplotlib.pyplot as plt
9
import config
10
11
12
def resize(image, 
13
           x=config.IMAGE_PXL_SIZE_X,
14
           y=config.IMAGE_PXL_SIZE_Y):
15
    if not len(image):
16
        return np.array([])
17
18
    return np.stack([cv2.resize(scan, (x, y)) 
19
                     for scan in image])
20
21
22
def normalize(image):
23
    image = ((image - config.MIN_BOUND) / 
24
             (config.MAX_BOUND - config.MIN_BOUND))
25
    image[image>1] = 1.
26
    image[image<0] = 0.
27
    return image
28
29
30
def chunks(l, n):
31
    """Yield successive n-sized chunks from l."""
32
    for i in range(0, len(l), n):
33
        yield l[i:i + n]
34
35
36
def mean(l):
37
    if len(l):
38
        return sum(l) / len(l)
39
    return np.full(l.shape, config.OUT_SCAN, l.dtype)
40
41
42
def get_mean_chunk_slices(slices):
43
    if len(slices) < config.SLICES:
44
        print("New slices are less then required after getting mean images, adding padding.")
45
        return trim_and_pad(np.array(slices), config.SLICES) 
46
47
    new_slices = []
48
    for slice_chunk in np.array_split(slices, config.SLICES):
49
        slice_chunk = list(map(mean, zip(*slice_chunk)))
50
        new_slices.append(slice_chunk)
51
52
    return np.stack(new_slices)
53
54
55
def read_csv(input_file):
56
    return pd.read_csv(input_file, index_col=0)
57
58
59
def read_csv_column(input_file, columns=[0]):
60
    return pd.read_csv(input_file, usecols=columns).values.flatten()
61
62
63
def store_to_csv(patients, labels, csv_file_path):
64
    index = pd.Index(data=patients, name=config.ID_COLUMN_NAME)
65
    df = pd.DataFrame(data={config.COLUMN_NAME: labels}, 
66
                      columns=[config.COLUMN_NAME],
67
                      index=index)
68
    df.to_csv(csv_file_path)
69
70
71
def trim_and_pad(patient_img, slice_count, normalize_pad=True):
72
    slices, size_x, size_y = patient_img.shape
73
74
    if slices == slice_count:
75
        return patient_img
76
77
    if slices > slice_count:
78
        return patient_img[:slice_count]
79
80
    padding = np.full((slice_count-slices, size_x, size_y), 
81
        config.OUT_SCAN, patient_img.dtype)
82
    if normalize_pad:
83
        padding = normalize(padding)
84
85
    return np.vstack([patient_img, padding])
86
87
88
def trim_pad_slices(scans, pad_with_existing=True,
89
                    padding_value=config.BACKGROUND):
90
    slices, x, y = scans.shape
91
92
    if slices == config.SLICES:
93
        return scans
94
95
    if slices < config.SLICES:
96
        pad = config.SLICES - slices
97
        new_scans = []
98
        if pad > slices:
99
            # Double the size, scans are already ordered by slice location
100
            for scan in scans:
101
                new_scans.append(scan) 
102
                new_scans.append(scan)
103
104
            del scans
105
            scans = new_scans
106
            pad = config.SLICES - len(scans)
107
    
108
        if pad_with_existing:
109
            padding = []
110
            for slice_chunk in np.array_split(scans, pad):
111
                padding.extend(slice_chunk)
112
                padding.append(slice_chunk[-1])
113
114
            #contains originals also, doubles the last slice in the chunk
115
            return np.stack(padding)
116
        else:
117
            padding = np.full((pad, x, y), padding_value, scans.dtype)
118
            return np.vstack([scans, padding])
119
120
    trim = slices - config.SLICES
121
    trimmed = []
122
    for slice_chunk in np.array_split(scans, trim):
123
        trimmed.append(slice_chunk[1:])
124
125
    return np.vstack(trimmed)
126
127
128
def count_background_rows(image, background=config.BACKGROUND):
129
    return np.sum(np.all(image == background, axis=1))
130
131
132
def remove_background_rows(image, background=config.BACKGROUND):
133
    return image[40:image.shape[0]-40, 20:image.shape[1]-20]
134
135
136
def rotate_scans(scans, angle=10):
137
    return np.stack([imutils.rotate(scan, angle) for scan in scans])
138
139
140
def remove_background_rows_3d(scans, background=config.BACKGROUND):
141
    transformed = []
142
    for scan in scans:
143
        removed = remove_background_rows(scan, background)
144
        tr_scan = cv2.resize(removed, 
145
            (config.IMAGE_PXL_SIZE_X, config.IMAGE_PXL_SIZE_Y))
146
        transformed.append(tr_scan)
147
148
    return np.stack(transformed)
149
150
151
def store_patient_image(image_dir, image, patient_id):
152
    """
153
    Serializes the patient image.
154
155
    Image is a 3D numpy array - array from patient slices.
156
    If not existing image_dir is created.
157
    """
158
    if not os.path.exists(image_dir):
159
        os.makedirs(image_dir)
160
161
    np.savez_compressed(os.path.join(image_dir, patient_id), image)
162
163
164
def load_patient_image(image_dir, patient_id):
165
    """
166
    Load the serialized patient image.
167
168
    Image is a 3D array - array of patient slices, metadata,
169
    contained in the dicom format, is removed.
170
    """
171
    if '.npz' not in patient_id:
172
        patient_id += '.npz'
173
    with np.load(os.path.join(image_dir, patient_id)) as data:
174
        return data['arr_0']