Diff of /utils/libs.py [000000] .. [4df946]

Switch to unified view

a b/utils/libs.py
1
import glob
2
import numpy as np
3
import cv2
4
from PIL import Image
5
from utils import config
6
7
8
def write(filename, content, class_num=2, color_map=True):
9
    """
10
    Save image array to a specified path.
11
    The image will be automatically recolored via the class number.
12
    :param filename: The specified path.
13
    :param content: Numpy array containing the image.
14
    :param class_num: Total class number.
15
    :param color_map: Whether change the probability into gray grade.
16
    """
17
    if class_num <= 1:
18
        raise Exception('ERROR: Class number should be >= 2.')
19
    color_stage = 255. / (class_num - 1) if color_map else 1.0
20
    new_image = Image.fromarray(np.uint8(content * color_stage))
21
    new_image.save(filename, "PNG")
22
23
24
def generate_effective_regions(size):
25
    """
26
    This function is used to generate effective regions for inference according to the given slide size.
27
    :param size: Given slide size, should be in the form of [w, h].
28
    """
29
    width = size[0]
30
    height = size[1]
31
    x_step = int(width / config.CENTER_SIZE)
32
    y_step = int(height / config.CENTER_SIZE)
33
    regions = []
34
    for x in range(0, x_step):
35
        for y in range(0, y_step):
36
            regions.append([x * config.CENTER_SIZE, y * config.CENTER_SIZE, 0, 0,
37
                            config.CENTER_SIZE - 1, config.CENTER_SIZE - 1])
38
    if not height % config.CENTER_SIZE == 0:
39
        for x in range(0, x_step):
40
            regions.append([x * config.CENTER_SIZE, height - config.CENTER_SIZE,
41
                                0, (y_step + 1) * config.CENTER_SIZE - height,
42
                            config.CENTER_SIZE - 1, config.CENTER_SIZE - 1])
43
    if not width % config.CENTER_SIZE == 0:
44
        for y in range(0, y_step):
45
            regions.append([width - config.CENTER_SIZE, y * config.CENTER_SIZE,
46
                                (x_step + 1) * config.CENTER_SIZE - width, 0,
47
                            config.CENTER_SIZE - 1, config.CENTER_SIZE - 1])
48
    if not (height % config.CENTER_SIZE == 0 or width % config.CENTER_SIZE == 0):
49
        regions.append([width - config.CENTER_SIZE, height - config.CENTER_SIZE,
50
                                (x_step + 1) * config.CENTER_SIZE - width, (y_step + 1) * config.CENTER_SIZE - height,
51
                        config.CENTER_SIZE - 1, config.CENTER_SIZE - 1])
52
    return regions
53
54
55
def generate_overlap_tile(region, dimensions):
56
    """
57
    This function is used to process border patches.
58
    """
59
    shifted_region_x = region[0] - config.BORDER_SIZE
60
    shifted_region_y = region[1] - config.BORDER_SIZE
61
    clip_region_x = config.BORDER_SIZE
62
    clip_region_y = config.BORDER_SIZE
63
    if region[0] == 0:
64
        shifted_region_x = shifted_region_x + config.BORDER_SIZE
65
        clip_region_x = 0
66
    if region[1] == 0:
67
        shifted_region_y = shifted_region_y + config.BORDER_SIZE
68
        clip_region_y = 0
69
    if region[0] == dimensions[0] - config.CENTER_SIZE:
70
        shifted_region_x = shifted_region_x - config.BORDER_SIZE
71
        clip_region_x = 2 * config.BORDER_SIZE
72
    if region[1] == dimensions[1] - config.CENTER_SIZE:
73
        shifted_region_y = shifted_region_y - config.BORDER_SIZE
74
        clip_region_y = 2 * config.BORDER_SIZE
75
    return [shifted_region_x, shifted_region_y], [clip_region_x, clip_region_y]
76
77
78
def image_to_array(input_image):
79
    """
80
    Loads image into numpy array.
81
    """
82
    im_array = np.array(input_image.getdata(), dtype=np.uint8)
83
    im_array = im_array.reshape((input_image.size[0], input_image.size[1]))
84
    return im_array
85
86
87
def post_processing(image_patch):
88
    """
89
    Remove small noisy points.
90
    """
91
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (config.FILTER_KERNEL, config.FILTER_KERNEL))
92
    open_patch = cv2.morphologyEx(image_patch, cv2.MORPH_OPEN, kernel)
93
    close_patch = cv2.morphologyEx(open_patch, cv2.MORPH_CLOSE, kernel)
94
    return close_patch
95
96
97
def concat_patches(temp_dir, image_name):
98
    """
99
    Concatenate the predicted patches into a thumbnail result.
100
    """
101
    prediction_list = glob.glob(temp_dir + image_name + '*_prediction.png')
102
    patch_list = []
103
    for prediction_image in prediction_list:
104
        name_parts = prediction_image.split('/')[-1].split('_')
105
        pos_x, pos_y = int(name_parts[-3]), int(name_parts[-2])
106
        patch_list.append([pos_x, pos_y])
107
    image_patches = []
108
    patch_list.sort()
109
    last_x = -1
110
    row_patch = []
111
    for position in patch_list:
112
        pos_x = position[0]
113
        pos_y = position[1]
114
        image = Image.open(temp_dir + '_'.join([image_name, str(pos_x), str(pos_y), 'prediction']) + '.png')
115
        original_width, original_height = image.size
116
        if original_width < config.THUMBNAIL_RATIO or original_height < config.THUMBNAIL_RATIO:
117
            continue
118
        image = image.resize(
119
            (int(original_width / config.THUMBNAIL_RATIO),
120
             int(original_height / config.THUMBNAIL_RATIO)), Image.NEAREST)
121
        image_patch = image_to_array(image)
122
        if not pos_x == last_x:
123
            last_x = pos_x
124
            if len(row_patch) == 0:
125
                row_patch = image_patch
126
            else:
127
                if not len(image_patches) == 0:
128
                    image_patches = np.column_stack((image_patches, row_patch))
129
                else:
130
                    image_patches = row_patch
131
                row_patch = image_patch
132
        else:
133
            row_patch = np.row_stack((row_patch, image_patch))
134
    prediction = np.column_stack((image_patches, row_patch))
135
    return prediction