|
a |
|
b/segmentation/singleprobjump.py |
|
|
1 |
""" |
|
|
2 |
Created by: Rishav Raj and Qie Shang Pua, University of New South Wales |
|
|
3 |
This program performs image processing to obtain multiple segments of a patient's spine. |
|
|
4 |
Input: Ultrasound scans of the patient's back (in png format) |
|
|
5 |
Output: 1. Processed Spine Images |
|
|
6 |
2. A csv file that will be fed into registration.py |
|
|
7 |
""" |
|
|
8 |
|
|
|
9 |
# Import Packages |
|
|
10 |
import os |
|
|
11 |
import cv2 |
|
|
12 |
import glob |
|
|
13 |
import math |
|
|
14 |
import pandas as pd |
|
|
15 |
import cv2 |
|
|
16 |
import numpy as np |
|
|
17 |
import scipy.ndimage |
|
|
18 |
import statistics |
|
|
19 |
from skimage import data, color |
|
|
20 |
import matplotlib.pyplot as plt |
|
|
21 |
from skimage.color import rgb2gray |
|
|
22 |
from skimage.transform import rescale, resize, downscale_local_mean |
|
|
23 |
from timeit import default_timer as timer |
|
|
24 |
import sys |
|
|
25 |
from skimage.io import imread |
|
|
26 |
|
|
|
27 |
|
|
|
28 |
# Python Migration of "find_best_path_jumping.m" of MATLAB |
|
|
29 |
# Applies Dynamic Programming to calculate the path of least cost. |
|
|
30 |
def find_best_path_jumping(curr): |
|
|
31 |
x = 151 # these are hardcoded - should be determined instead. |
|
|
32 |
y = 289 |
|
|
33 |
|
|
|
34 |
# if at end |
|
|
35 |
if curr[1] == y: |
|
|
36 |
curr_cost = 0 |
|
|
37 |
cost[int(curr[0]), int(curr[1])] = curr_cost # Casted into int to access array index |
|
|
38 |
nexts[int(curr[0]), int(curr[1])] = 0 |
|
|
39 |
return |
|
|
40 |
|
|
|
41 |
max_jump = 50 |
|
|
42 |
no_cells = max_jump * 2 + 1 |
|
|
43 |
|
|
|
44 |
min_next = [0, 0] |
|
|
45 |
min_cost = math.inf # inf gives the largest num in float |
|
|
46 |
# print(curr) |
|
|
47 |
# print(int(curr[0])) |
|
|
48 |
|
|
|
49 |
# calc costs |
|
|
50 |
for i in range(no_cells): |
|
|
51 |
|
|
|
52 |
# cell no |
|
|
53 |
next = [0, 0] |
|
|
54 |
next[0] = curr[0] + i - max_jump - 1 |
|
|
55 |
next[1] = curr[1] + 1 |
|
|
56 |
# print(next) |
|
|
57 |
|
|
|
58 |
# out of bounds |
|
|
59 |
if next[0] < 1 or next[0] > x: |
|
|
60 |
next_cost = math.inf |
|
|
61 |
|
|
|
62 |
# already calculated |
|
|
63 |
elif cost[int(next[0]), int(next[1])] != math.inf: |
|
|
64 |
next_cost = cost[int(next[0]), int(next[1])] |
|
|
65 |
|
|
|
66 |
# need to recursively calculate |
|
|
67 |
else: |
|
|
68 |
next_cost = find_best_path_jumping(next) |
|
|
69 |
|
|
|
70 |
# print(next_cost) |
|
|
71 |
# add penalty if needed |
|
|
72 |
if abs(curr[0] - next[0]) > 2: |
|
|
73 |
if next_cost == None: |
|
|
74 |
next_cost = 0 |
|
|
75 |
next_cost = next_cost + 0.2 |
|
|
76 |
|
|
|
77 |
# calculate running min |
|
|
78 |
if next_cost != None and next_cost < min_cost: |
|
|
79 |
min_cost = next_cost |
|
|
80 |
min_next = next[0] |
|
|
81 |
|
|
|
82 |
# set results |
|
|
83 |
|
|
|
84 |
# print([int(curr[0]), int(curr[1])]) |
|
|
85 |
curr_cost = inv_prob[int(curr[0]), int(curr[1])] + min_cost |
|
|
86 |
cost[int(curr[0]), int(curr[1])] = curr_cost |
|
|
87 |
nexts[int(curr[0]), int(curr[1])] = min_next |
|
|
88 |
|
|
|
89 |
return curr_cost |
|
|
90 |
|
|
|
91 |
# Python Migration of "get_prob_map.m" of MATLAB |
|
|
92 |
# Produces processed image in black and white |
|
|
93 |
def get_prob_map(grayscale): |
|
|
94 |
|
|
|
95 |
# Start prob map as simple intensity |
|
|
96 |
intensity_map = rescale(grayscale, .5, anti_aliasing=False) |
|
|
97 |
intensity_map = np.asarray(intensity_map) |
|
|
98 |
prob_map = intensity_map * 0.5 |
|
|
99 |
# print(np.shape(prob_map)) |
|
|
100 |
|
|
|
101 |
# Create probablity map from intensity after gaussian filtering |
|
|
102 |
gausian = cv2.GaussianBlur(prob_map, (5, 5), 5) |
|
|
103 |
gausian = np.asarray(gausian) |
|
|
104 |
# print(np.shape(gausian)) |
|
|
105 |
|
|
|
106 |
num = np.multiply(gausian, prob_map) |
|
|
107 |
den = num + np.multiply((1 - gausian), (1 - prob_map)) |
|
|
108 |
prob_map = np.divide(num, den) |
|
|
109 |
|
|
|
110 |
kernel1 = np.ones((3, 3), np.float32) / 9 |
|
|
111 |
kernel1[1][1] = 0.8888889 |
|
|
112 |
|
|
|
113 |
y = 1 |
|
|
114 |
x = 1 |
|
|
115 |
shadow = np.ones((y, x)) * 0.2 |
|
|
116 |
overall_mean = np.mean(np.mean(intensity_map)) |
|
|
117 |
|
|
|
118 |
for i in range(1, x): |
|
|
119 |
j = y |
|
|
120 |
while (j > 0 and ( |
|
|
121 |
gausian[j, i] < overall_mean * 1.5 or np.mean(gausian[j - 10:j - 1, i]) < overall_mean * 1.5)): |
|
|
122 |
shadow[j, i] = 0.1 |
|
|
123 |
j = j - 1 |
|
|
124 |
while (j > 0 and (gausian[j, i] > overall_mean * 1.5) or j > 5 and np.mean( |
|
|
125 |
gausian[j - 5:j - 1, i]) > overall_mean * 1.5): |
|
|
126 |
shadow[j, i] = intensity_map(j, i) |
|
|
127 |
j = j - 1 |
|
|
128 |
shadow = cv2.GaussianBlur(shadow, (5, 5), 5) |
|
|
129 |
prob_map = (shadow * prob_map) / (shadow * prob_map + (1 - shadow) * (1 - prob_map)) |
|
|
130 |
|
|
|
131 |
return prob_map |
|
|
132 |
|
|
|
133 |
k = cv2.waitKey(0) & 0xFF |
|
|
134 |
if k == 27: # wait for ESC key to exit |
|
|
135 |
cv2.destroyAllWindows() |
|
|
136 |
elif k == ord('s'): # wait for 's' key to save and exit |
|
|
137 |
cv2.imwrite('prob map of a single scan.png', prob_map) |
|
|
138 |
cv2.destroyAllWindows() |
|
|
139 |
|
|
|
140 |
|
|
|
141 |
# Main File |
|
|
142 |
# Similar to single_line_path.m of MATLAB |
|
|
143 |
def main(): |
|
|
144 |
|
|
|
145 |
points = [] |
|
|
146 |
images = glob.glob('/Users/puaqieshang/Desktop/Taste of Research/MATLAB code/everything/phantom_images/phantom_3/scan_2/*.png') |
|
|
147 |
images.sort() |
|
|
148 |
|
|
|
149 |
count = 0 |
|
|
150 |
startTime = timer() |
|
|
151 |
for fname in images: |
|
|
152 |
print(f"Image No.{count+1}") |
|
|
153 |
img = cv2.imread(fname) |
|
|
154 |
# im = plt.imread(fname) |
|
|
155 |
# implot = plt.imshow(im) |
|
|
156 |
count = count + 1 |
|
|
157 |
|
|
|
158 |
us_img = img[80:400, 270:850] |
|
|
159 |
gray = cv2.cvtColor(us_img, cv2.COLOR_BGR2GRAY) |
|
|
160 |
# cv2.imshow('gray_image',gray) |
|
|
161 |
# [x, y] = np.shape(gray) |
|
|
162 |
# print(x) |
|
|
163 |
# print(y) |
|
|
164 |
prob_map = get_prob_map(gray) |
|
|
165 |
highlyLikely = 0.05*np.max(prob_map) |
|
|
166 |
np.savetxt("prob_map.csv", prob_map, delimiter=",") |
|
|
167 |
# print(np.shape(prob_map)) |
|
|
168 |
|
|
|
169 |
""" |
|
|
170 |
Dynamic Programming Section |
|
|
171 |
global variables are defined below |
|
|
172 |
""" |
|
|
173 |
global inv_prob |
|
|
174 |
inv_prob = 0.5 - prob_map |
|
|
175 |
[a, b] = np.shape(prob_map) |
|
|
176 |
start = [np.floor(a/2), 1] |
|
|
177 |
global cost |
|
|
178 |
cost = np.ones([a, b]) * np.Inf |
|
|
179 |
global nexts |
|
|
180 |
nexts = np.ones([a, b]) * -1 |
|
|
181 |
find_best_path_jumping(start) |
|
|
182 |
|
|
|
183 |
# get points on this scan |
|
|
184 |
point_scan = np.zeros([1, b]) |
|
|
185 |
|
|
|
186 |
implot = plt.imshow(prob_map) |
|
|
187 |
# print(start[0]) |
|
|
188 |
curr_x = start[0] |
|
|
189 |
for curr_y in range(b): |
|
|
190 |
point_scan[0, curr_y] = curr_x |
|
|
191 |
|
|
|
192 |
if prob_map[int(curr_x), int(curr_y)] > highlyLikely: #NEED TO CHANGE TO HIGHLY LIKELY!!!!! |
|
|
193 |
# print("helloooooo") |
|
|
194 |
# cv2.circle(gray, (int(curr_y), int(curr_x)), 1, (0, 0, 255), 1) |
|
|
195 |
# append coloured points |
|
|
196 |
plt.scatter(curr_x, curr_y, c='r', s=20) |
|
|
197 |
coloured_pt = [curr_x, curr_y, count * 0.2] |
|
|
198 |
# points = np.concatenate((points, coloured_pt), axis=1) |
|
|
199 |
points.append(coloured_pt) |
|
|
200 |
|
|
|
201 |
else: |
|
|
202 |
# cv2.circle(gray, (int(curr_y), int(curr_x)), 1, (255, 0, 0), 1) |
|
|
203 |
plt.scatter(curr_x, curr_y, c='b', s=20) |
|
|
204 |
|
|
|
205 |
curr_x = nexts[int(curr_x), int(curr_y)] |
|
|
206 |
|
|
|
207 |
plt.show() |
|
|
208 |
|
|
|
209 |
endTime = timer() |
|
|
210 |
# print(str(endTime - startTime) + " seconds") |
|
|
211 |
print(f"The time taken is {endTime - startTime} seconds") |
|
|
212 |
|
|
|
213 |
np.savetxt("pls-work.csv", [*zip(*points)], delimiter=",") # Transpose points data and save into csv format |
|
|
214 |
|
|
|
215 |
key = cv2.waitKey(0) & 0xFF |
|
|
216 |
if key == ord("q"): |
|
|
217 |
cv2.destroyAllWindows() |
|
|
218 |
|
|
|
219 |
|
|
|
220 |
main() |