Skip to content

Commit 00cc7fb

Browse files
committed
first commit
0 parents  commit 00cc7fb

13 files changed

+2295
-0
lines changed

.DS_Store

6 KB
Binary file not shown.

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Predicting post-surgical recurrence of hepatocellular carcinoma from digital histopathologic images using deep learning
2+
3+
![method_outline](method_outline.png)
4+
5+
This repository contains the code to quantify risk scores for recurrence in patients with hepatocellular carcinoma from H&E-stained FFPE histopathology images.
6+
7+
The code is written in python.
8+
9+
## Citation
10+
Predicting post-surgical recurrence of hepatocellular carcinoma from digital histopathologic images using deep learning
11+
12+
Rikiya Yamashita, Jin Long, Atif Saleem, Daniel Rubin, Jeanne Shen.

method_outline.png

241 KB
Loading

preprocess.py

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
# ------------------------------------------------------------------------
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# ------------------------------------------------------------------------
16+
17+
import math
18+
import numpy as np
19+
from PIL import Image
20+
import skimage.morphology as sk_morphology
21+
22+
def open_image(filename):
23+
image = Image.open(filename)
24+
return image
25+
26+
def pil_to_np_rgb(pil_img):
27+
rgb = np.asarray(pil_img)
28+
return rgb
29+
30+
def mask_percent(np_img):
31+
if (len(np_img.shape) == 3) and (np_img.shape[2] == 3):
32+
np_sum = np_img[:, :, 0] + np_img[:, :, 1] + np_img[:, :, 2]
33+
mask_percentage = 100 - np.count_nonzero(np_sum) / np_sum.size * 100 #(np_img.shape[0]*np_img.shape[1])
34+
else:
35+
mask_percentage = 100 - np.count_nonzero(np_img) / np_img.size * 100
36+
return mask_percentage
37+
38+
def tissue_percent(np_img):
39+
return 100 - mask_percent(np_img)
40+
41+
def filter_green_channel(np_img, green_thresh=200, avoid_overmask=True, overmask_thresh=90, output_type="bool"):
42+
g = np_img[:, :, 1]
43+
gr_ch_mask = (g < green_thresh) & (g > 0)
44+
mask_percentage = mask_percent(gr_ch_mask)
45+
if (mask_percentage >= overmask_thresh) and (green_thresh < 255) and (avoid_overmask is True):
46+
new_green_thresh = math.ceil((255 - green_thresh) / 2 + green_thresh)
47+
print("Mask percentage %3.2f%% >= overmask threshold %3.2f%% for Remove Green Channel green_thresh=%d, so try %d" % (
48+
mask_percentage, overmask_thresh, green_thresh, new_green_thresh))
49+
gr_ch_mask = filter_green_channel(np_img, new_green_thresh, avoid_overmask, overmask_thresh, output_type)
50+
np_img = gr_ch_mask
51+
if output_type == "bool":
52+
pass
53+
elif output_type == "float":
54+
np_img = np_img.astype(float)
55+
else:
56+
np_img = np_img.astype("uint8") * 255
57+
return np_img
58+
59+
def filter_grays(rgb, tolerance=15, output_type="bool"):
60+
(h, w, c) = rgb.shape
61+
rgb = rgb.astype(np.int)
62+
rg_diff = abs(rgb[:, :, 0] - rgb[:, :, 1]) <= tolerance
63+
rb_diff = abs(rgb[:, :, 0] - rgb[:, :, 2]) <= tolerance
64+
gb_diff = abs(rgb[:, :, 1] - rgb[:, :, 2]) <= tolerance
65+
result = ~(rg_diff & rb_diff & gb_diff)
66+
if output_type == "bool":
67+
pass
68+
elif output_type == "float":
69+
result = result.astype(float)
70+
else:
71+
result = result.astype("uint8") * 255
72+
return result
73+
74+
def filter_red(rgb, red_lower_thresh, green_upper_thresh, blue_upper_thresh, output_type="bool"):
75+
r = rgb[:, :, 0] > red_lower_thresh
76+
g = rgb[:, :, 1] < green_upper_thresh
77+
b = rgb[:, :, 2] < blue_upper_thresh
78+
result = ~(r & g & b)
79+
if output_type == "bool":
80+
pass
81+
elif output_type == "float":
82+
result = result.astype(float)
83+
else:
84+
result = result.astype("uint8") * 255
85+
return result
86+
87+
def filter_red_pen(rgb, output_type="bool"):
88+
result = filter_red(rgb, red_lower_thresh=150, green_upper_thresh=80, blue_upper_thresh=90) & \
89+
filter_red(rgb, red_lower_thresh=110, green_upper_thresh=20, blue_upper_thresh=30) & \
90+
filter_red(rgb, red_lower_thresh=185, green_upper_thresh=65, blue_upper_thresh=105) & \
91+
filter_red(rgb, red_lower_thresh=195, green_upper_thresh=85, blue_upper_thresh=125) & \
92+
filter_red(rgb, red_lower_thresh=220, green_upper_thresh=115, blue_upper_thresh=145) & \
93+
filter_red(rgb, red_lower_thresh=125, green_upper_thresh=40, blue_upper_thresh=70) & \
94+
filter_red(rgb, red_lower_thresh=200, green_upper_thresh=120, blue_upper_thresh=150) & \
95+
filter_red(rgb, red_lower_thresh=100, green_upper_thresh=50, blue_upper_thresh=65) & \
96+
filter_red(rgb, red_lower_thresh=85, green_upper_thresh=25, blue_upper_thresh=45)
97+
if output_type == "bool":
98+
pass
99+
elif output_type == "float":
100+
result = result.astype(float)
101+
else:
102+
result = result.astype("uint8") * 255
103+
return result
104+
105+
def filter_green(rgb, red_upper_thresh, green_lower_thresh, blue_lower_thresh, output_type="bool"):
106+
r = rgb[:, :, 0] < red_upper_thresh
107+
g = rgb[:, :, 1] > green_lower_thresh
108+
b = rgb[:, :, 2] > blue_lower_thresh
109+
result = ~(r & g & b)
110+
if output_type == "bool":
111+
pass
112+
elif output_type == "float":
113+
result = result.astype(float)
114+
else:
115+
result = result.astype("uint8") * 255
116+
return result
117+
118+
def filter_green_pen(rgb, output_type="bool"):
119+
result = filter_green(rgb, red_upper_thresh=150, green_lower_thresh=160, blue_lower_thresh=140) & \
120+
filter_green(rgb, red_upper_thresh=70, green_lower_thresh=110, blue_lower_thresh=110) & \
121+
filter_green(rgb, red_upper_thresh=45, green_lower_thresh=115, blue_lower_thresh=100) & \
122+
filter_green(rgb, red_upper_thresh=30, green_lower_thresh=75, blue_lower_thresh=60) & \
123+
filter_green(rgb, red_upper_thresh=195, green_lower_thresh=220, blue_lower_thresh=210) & \
124+
filter_green(rgb, red_upper_thresh=225, green_lower_thresh=230, blue_lower_thresh=225) & \
125+
filter_green(rgb, red_upper_thresh=170, green_lower_thresh=210, blue_lower_thresh=200) & \
126+
filter_green(rgb, red_upper_thresh=20, green_lower_thresh=30, blue_lower_thresh=20) & \
127+
filter_green(rgb, red_upper_thresh=50, green_lower_thresh=60, blue_lower_thresh=40) & \
128+
filter_green(rgb, red_upper_thresh=30, green_lower_thresh=50, blue_lower_thresh=35) & \
129+
filter_green(rgb, red_upper_thresh=65, green_lower_thresh=70, blue_lower_thresh=60) & \
130+
filter_green(rgb, red_upper_thresh=100, green_lower_thresh=110, blue_lower_thresh=105) & \
131+
filter_green(rgb, red_upper_thresh=165, green_lower_thresh=180, blue_lower_thresh=180) & \
132+
filter_green(rgb, red_upper_thresh=140, green_lower_thresh=140, blue_lower_thresh=150) & \
133+
filter_green(rgb, red_upper_thresh=185, green_lower_thresh=195, blue_lower_thresh=195)
134+
if output_type == "bool":
135+
pass
136+
elif output_type == "float":
137+
result = result.astype(float)
138+
else:
139+
result = result.astype("uint8") * 255
140+
return result
141+
142+
def filter_blue(rgb, red_upper_thresh, green_upper_thresh, blue_lower_thresh, output_type="bool"):
143+
r = rgb[:, :, 0] < red_upper_thresh
144+
g = rgb[:, :, 1] < green_upper_thresh
145+
b = rgb[:, :, 2] > blue_lower_thresh
146+
result = ~(r & g & b)
147+
if output_type == "bool":
148+
pass
149+
elif output_type == "float":
150+
result = result.astype(float)
151+
else:
152+
result = result.astype("uint8") * 255
153+
return result
154+
155+
def filter_blue_pen(rgb, output_type="bool"):
156+
result = filter_blue(rgb, red_upper_thresh=60, green_upper_thresh=120, blue_lower_thresh=190) & \
157+
filter_blue(rgb, red_upper_thresh=120, green_upper_thresh=170, blue_lower_thresh=200) & \
158+
filter_blue(rgb, red_upper_thresh=175, green_upper_thresh=210, blue_lower_thresh=230) & \
159+
filter_blue(rgb, red_upper_thresh=145, green_upper_thresh=180, blue_lower_thresh=210) & \
160+
filter_blue(rgb, red_upper_thresh=37, green_upper_thresh=95, blue_lower_thresh=160) & \
161+
filter_blue(rgb, red_upper_thresh=30, green_upper_thresh=65, blue_lower_thresh=130) & \
162+
filter_blue(rgb, red_upper_thresh=130, green_upper_thresh=155, blue_lower_thresh=180) & \
163+
filter_blue(rgb, red_upper_thresh=40, green_upper_thresh=35, blue_lower_thresh=85) & \
164+
filter_blue(rgb, red_upper_thresh=30, green_upper_thresh=20, blue_lower_thresh=65) & \
165+
filter_blue(rgb, red_upper_thresh=90, green_upper_thresh=90, blue_lower_thresh=140) & \
166+
filter_blue(rgb, red_upper_thresh=60, green_upper_thresh=60, blue_lower_thresh=120) & \
167+
filter_blue(rgb, red_upper_thresh=110, green_upper_thresh=110, blue_lower_thresh=175)
168+
if output_type == "bool":
169+
pass
170+
elif output_type == "float":
171+
result = result.astype(float)
172+
else:
173+
result = result.astype("uint8") * 255
174+
return result
175+
176+
def filter_remove_small_objects(np_img, min_size=500, avoid_overmask=True, overmask_thresh=95, output_type="uint8"):
177+
rem_sm = np_img.astype(bool) # make sure mask is boolean
178+
rem_sm = sk_morphology.remove_small_objects(rem_sm, min_size=min_size)
179+
mask_percentage = mask_percent(rem_sm)
180+
if (mask_percentage >= overmask_thresh) and (min_size >= 1) and (avoid_overmask is True):
181+
new_min_size = min_size / 2
182+
print("Mask percentage %3.2f%% >= overmask threshold %3.2f%% for Remove Small Objs size %d, so try %d" % (
183+
mask_percentage, overmask_thresh, min_size, new_min_size))
184+
rem_sm = filter_remove_small_objects(np_img, new_min_size, avoid_overmask, overmask_thresh, output_type)
185+
np_img = rem_sm
186+
if output_type == "bool":
187+
pass
188+
elif output_type == "float":
189+
np_img = np_img.astype(float)
190+
else:
191+
np_img = np_img.astype("uint8") * 255
192+
return np_img
193+
194+
def mask_rgb(rgb, mask):
195+
result = rgb * np.dstack([mask, mask, mask])
196+
return result
197+
198+
def apply_image_filters(np_img):
199+
rgb = np_img
200+
mask_not_green = filter_green_channel(rgb)
201+
mask_not_gray = filter_grays(rgb)
202+
mask_no_red_pen = filter_red_pen(rgb)
203+
mask_no_green_pen = filter_green_pen(rgb)
204+
rgb_no_green_pen = mask_rgb(rgb, mask_no_green_pen)
205+
mask_no_blue_pen = filter_blue_pen(rgb)
206+
mask_gray_green_pens = mask_not_gray & mask_not_green & mask_no_red_pen & mask_no_green_pen & mask_no_blue_pen
207+
mask_remove_small = filter_remove_small_objects(mask_gray_green_pens, min_size=500, output_type="bool")
208+
rgb_remove_small = mask_rgb(rgb, mask_remove_small)
209+
img = rgb_remove_small
210+
return img

0 commit comments

Comments
 (0)