File size: 4,454 Bytes
2ef318a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import cv2

import matplotlib.pyplot as plt
import numpy as np


def _pad_to_square(image, long_side=None, border=0):
    h, w, _ = image.shape

    if long_side == None: long_side = max(h, w)

    l_pad = (long_side - w) // 2 + border
    r_pad = (long_side - w) // 2 + border
    t_pad = (long_side - h) // 2 + border
    b_pad = (long_side - h) // 2 + border
    if w % 2 != 0: r_pad = r_pad + 1
    if h % 2 != 0: b_pad = b_pad + 1

    image = np.pad(
        image,
        ((t_pad, b_pad),
         (l_pad, r_pad),
         (0, 0)),
        'constant')

    return image


def _get_retina_bb(image):

    # make image greyscale and normalise
    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    image = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX)

    # calculate threshold perform threshold
    threshold = np.mean(image)/3-7
    ret, thresh = cv2.threshold(image, max(0, threshold), 255, cv2.THRESH_BINARY)

    # median filter, erode and dilate to remove noise and holes
    thresh = cv2.medianBlur(thresh, 25)
    thresh = cv2.erode(thresh, None, iterations=2)
    thresh = cv2.dilate(thresh, None, iterations=2)

    # find mask contour
    cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    c = max(cnts, key=cv2.contourArea)

    # Get bounding box from mask contour
    x, y, w, h = cv2.boundingRect(c)

    # Get mask from contour
    mask = np.zeros_like(image)
    cv2.drawContours(mask, [c], -1, (255, 255, 255), -1)

    return x, y, w, h, mask


def _get_retina_bb2(image, skips=4):
    '''
    Experimental Retina Bounding Box detector based on Convexity Defect Points
    '''

    # make image greyscale and normalise
    image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    image = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX)

    # calculate threshold perform threshold
    threshold = np.mean(image)/3-7
    ret, thresh = cv2.threshold(image, max(0, threshold), 255, cv2.THRESH_BINARY)

    # median filter, erode and dilate to remove noise and holes
    thresh = cv2.medianBlur(thresh, 25)
    thresh = cv2.erode(thresh, None, iterations=2)
    thresh = cv2.dilate(thresh, None, iterations=2)

    # Find contours
    contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

    # Find the index of the largest contour
    areas = [cv2.contourArea(c) for c in contours]
    max_index = np.argmax(areas)
    cnt = contours[max_index]

    # Get convexity defect points
    hull = cv2.convexHull(cnt, returnPoints=False)
    hull[::-1].sort(axis=0)
    defects = cv2.convexityDefects(cnt, hull)

    ConvexityDefectPoint = []
    for i in range(0, defects.shape[0], skips):
        s, e, f, d = defects[i, 0]
        ConvexityDefectPoint.append(tuple(cnt[f][0]))

    # Get minimum enclosing circle as retina estimate
    (x, y), radius = cv2.minEnclosingCircle(np.array(ConvexityDefectPoint))

    # Get mask from contour
    mask = np.zeros_like(image)
    cv2.circle(mask, (x, y), radius, (255, 255, 255), -1)

    # return (x, y, w, h) bounding box
    return int(x - radius), int(y - radius), int(2 * radius - 1), int(2 * radius - 1), mask


def rgb_clahe(image, clipLimit=2.0, tileGridSize=(16, 16)):
    lab = cv2.cvtColor(image, cv2.COLOR_RGB2LAB)
    clahe = cv2.createCLAHE(clipLimit=clipLimit, tileGridSize=tileGridSize)
    lab[..., 0] = clahe.apply(lab[..., 0])
    return cv2.cvtColor(lab, cv2.COLOR_LAB2RGB)


if __name__ == '__main__':

    # image_file = '/vol/biomedic3/bh1511/retina/IDRID/segmentation/0_Original_Images/IDRiD_65.jpg'
    # image_file = '/vol/biomedic3/bh1511/retina/CHASE_DB1/images/Image_08R.jpg'
    # image_file = '/vol/vipdata/data/retina/kaggle-diabetic-retinopathy-detection/train/16_right.jpeg'
    # image_file = '/vol/vipdata/data/retina/IDRID/a_segmentation/images/train/IDRiD_01.jpg'
    image_file = 'preprocessing/Image_10L.png'

    # Load Image
    image = cv2.imread(image_file)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    plt.imshow(image); plt.show()

    # Localise and center retina image
    x, y, w, h, _ = _get_retina_bb(image)
    image = image[y:y + h, x:x + w, :]
    image = _pad_to_square(image, border=0)
    image = cv2.resize(image, (1024, 1024))

    # Apply CLAHE pre-processing
    image = rgb_clahe(image)

    # Display or save image
    plt.imshow(image); plt.show()
    # cv2.imwrite('processed_image.png', image)