Diff of /data/dataset.py [000000] .. [bd7f9c]

Switch to unified view

a b/data/dataset.py
1
import os
2
import numpy as np
3
import torch
4
import pandas as pd
5
from torch.utils.data import Dataset, DataLoader
6
from torchvision import transforms
7
from skimage import transform
8
from utils.Config import opt
9
import matplotlib.pylab as plt
10
from sklearn.model_selection import train_test_split
11
import utils.array_tool as at
12
import matplotlib.patches as patches
13
from data.data_utils import read_image
14
15
DSB_BBOX_LABEL_NAMES = ('p')  # Pneumonia
16
17
18
def inverse_normalize(img):
19
    if opt.caffe_pretrain:
20
        img = img + (np.array([122.7717, 115.9465, 102.9801]).reshape(3, 1, 1))
21
        return img[::-1, :, :].clip(min=0, max=255)
22
    # approximate un-normalize for visualize
23
    return (img * 0.225 + 0.45).clip(min=0, max=1) * 255
24
25
"""Transforms:
26
Data augmentation
27
"""
28
class Transform(object):
29
    def __init__(self, img_size):
30
        self.img_size = img_size
31
32
    def __call__(self, in_data):
33
        img_id, img, mask = in_data['img_id'], in_data['image'], in_data['mask']
34
        _, H, W = img.shape
35
        img, mask = preprocess(img, mask, self.img_size)
36
37
        return {'img_id': img_id, 'image': img.copy(), 'mask': mask.copy()}
38
39
40
def preprocess(img, mask, img_size):
41
    C, H, W = img.shape
42
    img = img / 255.
43
    img = transform.resize(img, (C, img_size, img_size), mode='reflect')
44
    mask = mask.astype(np.float32)
45
    mask = transform.resize(mask, (1, img_size, img_size), mode='reflect')
46
    # both the longer and shorter should be less than
47
    # max_size and min_size
48
    if opt.caffe_pretrain:
49
        normalize = caffe_normalize
50
    else:
51
        normalize = pytorch_normalze
52
53
    img = normalize(img)
54
55
    return img, mask
56
57
def pytorch_normalze(img):
58
    """
59
    https://discuss.pytorch.org/t/how-to-preprocess-input-for-pre-trained-networks/683
60
    https://github.com/pytorch/vision/issues/223
61
    return appr -1~1 RGB
62
    """
63
    normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],
64
                                std=[0.229, 0.224, 0.225])
65
    img = normalize(torch.from_numpy(img))
66
    return img.numpy()
67
68
69
def caffe_normalize(img):
70
    """
71
    return appr -125-125 BGR
72
    """
73
    img = img[[2, 1, 0], :, :]  # RGB-BGR
74
    img = img * 255
75
    mean = np.array([122.7717, 115.9465, 102.9801]).reshape(3, 1, 1)
76
    img = (img - mean).astype(np.float32, copy=True)
77
    return img
78
79
class RSNADataset(Dataset):
80
    def __init__(self, root_dir, img_id, mask_id, transform=True):
81
        """
82
        Args:
83
        :param root_dir (string): Directory with all the images
84
        :param img_id (list): lists of image id
85
        :param train: if equals true, then read training set, so the output is image, mask and imgId
86
                      if equals false, then read testing set, so the output is image and imgId
87
        :param transform (callable, optional): Optional transform to be applied on a sample
88
        """
89
        self.root_dir = root_dir
90
        self.img_id = img_id
91
        self.mask_id = mask_id
92
        self.transform = transform
93
        self.tsf = Transform(opt.img_size)
94
95
    def __len__(self):
96
        return len(self.img_id)
97
98
    def __getitem__(self, idx):
99
        img_path = os.path.join(self.root_dir, 'images', self.img_id[idx].split('.')[0], 'image.png')
100
        mask_path = os.path.join(self.root_dir, 'masks', self.mask_id[idx])
101
        image = read_image(img_path, np.float32, False)
102
        mask = read_image(mask_path, np.uint8, False)
103
104
        sample = {'img_id': self.img_id[idx], 'image':image.copy(), 'mask':mask.copy()}
105
106
        if self.transform:
107
            sample = self.tsf(sample)
108
109
        return sample
110
111
112
class RSNADatasetTest(Dataset):
113
    def __init__(self, root_dir, transform=True):
114
        """
115
        Args:
116
        :param root_dir (string): Directory with all the images
117
        :param img_id (list): lists of image id
118
        :param train: if equals true, then read training set, so the output is image, mask and imgId
119
                      if equals false, then read testing set, so the output is image and imgId
120
        :param transform (callable, optional): Optional transform to be applied on a sample
121
        """
122
        self.root_dir = root_dir
123
        self.img_id = os.listdir(root_dir)
124
        self.transform = transform
125
        self.tsf = Transform(opt.img_size)
126
127
    def __len__(self):
128
        return len(self.img_id)
129
130
    def __getitem__(self, idx):
131
        img_path = os.path.join(self.root_dir, self.img_id[idx], 'image.png')
132
        image = read_image(img_path, np.float32, False)
133
134
        C, H, W = image.shape
135
        image = image / 255.
136
        image = transform.resize(image, (C, opt.img_size, opt.img_size), mode='reflect')
137
        if opt.caffe_pretrain:
138
            normalize = caffe_normalize
139
        else:
140
            normalize = pytorch_normalze
141
142
        image = normalize(image)
143
144
        sample = {'img_id': self.img_id[idx], 'image': image.copy()}
145
146
        return sample
147
148
def get_train_loader(root_dir, batch_size=16, shuffle=False, num_workers=4, pin_memory=False):
149
150
    """Utility function for loading and returning training and validation Dataloader
151
    :param root_dir: the root directory of data set
152
    :param batch_size: batch size of training and validation set
153
    :param split: if split data set to training set and validation set
154
    :param shuffle: if shuffle the image in training and validation set
155
    :param num_workers: number of workers loading the data, when using CUDA, set to 1
156
    :param val_ratio: ratio of validation set size
157
    :param pin_memory: store data in CPU pin buffer rather than memory. when using CUDA, set to True
158
    :return:
159
        - train_loader: Dataloader for training
160
    """
161
    img_ids = os.listdir(root_dir)
162
    img_ids.sort()
163
    transformed_dataset = RSNADataset(root_dir=root_dir, img_id=img_ids, transform=True)
164
    dataloader = DataLoader(transformed_dataset, batch_size=batch_size,
165
                            shuffle=shuffle, num_workers=num_workers, pin_memory=pin_memory)
166
    return dataloader
167
168
def get_train_val_loader(root_dir, batch_size=16, val_ratio=0.2, shuffle=False, num_workers=4, pin_memory=False):
169
170
    """Utility function for loading and returning training and validation Dataloader
171
    :param root_dir: the root directory of data set
172
    :param batch_size: batch size of training and validation set
173
    :param split: if split data set to training set and validation set
174
    :param shuffle: if shuffle the image in training and validation set
175
    :param num_workers: number of workers loading the data, when using CUDA, set to 1
176
    :param val_ratio: ratio of validation set size
177
    :param pin_memory: store data in CPU pin buffer rather than memory. when using CUDA, set to True
178
    :return:
179
        - train_loader: Dataloader for training
180
        - valid_loader: Dataloader for validation
181
    """
182
    df = pd.read_csv(os.path.join(opt.root_dir, 'train.csv'))
183
    img_id, mask_id = list(df['image']), list(df['label'])
184
    train_img_id, val_img_id, train_mask_id, val_mask_id = train_test_split(img_id, mask_id, random_state=42, test_size=val_ratio, shuffle=False)
185
186
    train_dataset = RSNADataset(root_dir=root_dir, img_id=train_img_id, mask_id=train_mask_id, transform=True)
187
    train_loader = DataLoader(train_dataset, batch_size=batch_size,
188
                            shuffle=shuffle, num_workers=num_workers, pin_memory=pin_memory)
189
    val_dataset = RSNADataset(root_dir=root_dir, img_id=val_img_id, mask_id=val_mask_id, transform=True)
190
    val_loader = DataLoader(val_dataset, batch_size=batch_size,
191
                             shuffle=shuffle, num_workers=num_workers, pin_memory=pin_memory)
192
193
    return train_loader, val_loader
194
195
def get_test_loader(batch_size=16, shuffle=False, num_workers=4, pin_memory=False):
196
197
    """Utility function for loading and returning training and validation Dataloader
198
    :param root_dir: the root directory of data set
199
    :param batch_size: batch size of training and validation set
200
    :param shuffle: if shuffle the image in training and validation set
201
    :param num_workers: number of workers loading the data, when using CUDA, set to 1
202
    :param pin_memory: store data in CPU pin buffer rather than memory. when using CUDA, set to True
203
    :return:
204
        - testloader: Dataloader of all the test set
205
    """
206
    transformed_dataset = RSNADatasetTest(root_dir=opt.test_root)
207
    testloader = DataLoader(transformed_dataset, batch_size=batch_size,
208
                            shuffle=shuffle, num_workers=num_workers, pin_memory=pin_memory)
209
    return testloader
210
211
def show_batch_train(sample_batched):
212
    """
213
    Visualize one training image and its corresponding bbox
214
    """
215
    img_id, image, mask = sample_batched['img_id'], sample_batched['image'], sample_batched['mask']
216
    image, mask = np.squeeze(at.tonumpy(image)), np.squeeze(at.tonumpy(mask))
217
218
    image = inverse_normalize(image)
219
220
    combined = np.multiply(image, mask)
221
    ax1 = plt.subplot(121)
222
    ax1.imshow(image / 255.)
223
    ax1.set_title(img_id[0])
224
    ax2 = plt.subplot(122)
225
    ax2.imshow(combined / 255.)
226
    ax2.set_title(img_id[0])
227
    plt.show()
228
229
def show_batch_test(sample_batch):
230
    img_id, image = sample_batch['img_id'], sample_batch['image']
231
    image = inverse_normalize(np.squeeze(at.tonumpy(image[0])))
232
    plt.figure()
233
    plt.imshow(image/255)
234
    plt.show()
235
236
237
if __name__ == '__main__':
238
239
    # Load training & validation set
240
    # train_loader, val_loader = get_train_val_loader(opt.root_dir, batch_size=1, val_ratio=0.2,
241
    #                                                 shuffle=False, num_workers=opt.num_workers,
242
    #                                                 pin_memory=opt.pin_memory)
243
    # for i_batch, sample in enumerate(val_loader):
244
    #     print(sample['img_id'], ', ', sample['image'].shape, ', ', sample['mask'].shape)
245
    #     show_batch_train(sample)
246
247
    test_loader = get_test_loader(batch_size=1, shuffle=False,
248
                                                num_workers=opt.num_workers,
249
                                                pin_memory=opt.pin_memory)
250
    for i_batch, sample in enumerate(test_loader):
251
        print(sample['img_id'], ', ', sample['image'].shape)
252
        show_batch_test(sample)