|
a |
|
b/combinedDeepLearningActiveContour/functions/calc_dist.m |
|
|
1 |
function varargout = calc_dist(target_xy,reference_xy,para) |
|
|
2 |
%calc perpendicular distance between target and reference contours |
|
|
3 |
|
|
|
4 |
|
|
|
5 |
%check closed contours |
|
|
6 |
if target_xy(1,1) == target_xy(end,1) && target_xy(1,2) == target_xy(end,2) |
|
|
7 |
target_xy = target_xy(1:end-1,:); |
|
|
8 |
end |
|
|
9 |
if reference_xy(1,1) == reference_xy(end,1) && reference_xy(1,2) == reference_xy(end,2) |
|
|
10 |
reference_xy = reference_xy(1:end-1,:); |
|
|
11 |
end |
|
|
12 |
|
|
|
13 |
%for finding a subset of reference that correspond to the current target |
|
|
14 |
target_mask = poly2mask (target_xy(:,1),target_xy(:,2),double(para.width),double(para.height)); |
|
|
15 |
reference_mask = poly2mask (reference_xy(:,1),reference_xy(:,2),double(para.width),double(para.height)); |
|
|
16 |
|
|
|
17 |
%centroid of refernece mask |
|
|
18 |
reference_cen = regionprops(logical(reference_mask),'Centroid'); |
|
|
19 |
reference_cen_x = round(reference_cen.Centroid(1)); |
|
|
20 |
reference_cen_y = round(reference_cen.Centroid(2)); |
|
|
21 |
|
|
|
22 |
%check if target mask's centroid is in refernece's mask |
|
|
23 |
if target_mask(reference_cen_y,reference_cen_x) ==1 |
|
|
24 |
target_cen = reference_cen; |
|
|
25 |
else |
|
|
26 |
%target_mask=clean_segs(target_mask); |
|
|
27 |
target_cen = regionprops(logical(target_mask),'Centroid'); |
|
|
28 |
|
|
|
29 |
end |
|
|
30 |
|
|
|
31 |
%calc degrees between contours points and centroid |
|
|
32 |
target_degree = atan2( target_xy(:,2)-target_cen.Centroid(2),target_xy(:,1)-target_cen.Centroid(1))*180/pi; |
|
|
33 |
reference_degree = atan2( reference_xy(:,2)-reference_cen.Centroid(2),reference_xy(:,1)-reference_cen.Centroid(1))*180/pi; |
|
|
34 |
|
|
|
35 |
%initialize |
|
|
36 |
distance=zeros(size(target_xy,1),1); |
|
|
37 |
|
|
|
38 |
for idx = 1: size(target_xy,1) |
|
|
39 |
%Get 3 points,[left current right] |
|
|
40 |
if idx == 1 |
|
|
41 |
target_xy_3 = [target_xy(end,:); target_xy(idx:idx+1,:)]; |
|
|
42 |
elseif (idx == size(target_xy,1)) |
|
|
43 |
target_xy_3 = [target_xy(end-1:end,:); target_xy(1,:)]; |
|
|
44 |
else |
|
|
45 |
target_xy_3 = target_xy(idx-1:idx+1,:); |
|
|
46 |
end |
|
|
47 |
|
|
|
48 |
%current target to reference distance |
|
|
49 |
target_curr_x = target_xy_3(2,1); |
|
|
50 |
target_curr_y = target_xy_3(2,2); |
|
|
51 |
|
|
|
52 |
%find a subset of reference that correspond to the current target |
|
|
53 |
if ( abs(target_degree(idx)) >= 150 ) |
|
|
54 |
reference_xy_subset = reference_xy(find(abs(reference_degree)>=130),:); |
|
|
55 |
else |
|
|
56 |
reference_xy_subset = reference_xy(find(abs(reference_degree-target_degree(idx))<50),:); |
|
|
57 |
end |
|
|
58 |
|
|
|
59 |
%plot reference_xy_subset |
|
|
60 |
%hold on; plot(reference_xy_subset(:,1)-min_showbox_x(1)+showbox_offset, reference_xy_subset(:,2)-min_showbox_y(1)+showbox_offset ,'r*') |
|
|
61 |
|
|
|
62 |
%fit line |
|
|
63 |
target_X = target_xy_3(:,1); |
|
|
64 |
target_Y = target_xy_3(:,2); |
|
|
65 |
|
|
|
66 |
%3 points are the same |
|
|
67 |
if ( sum(abs(target_X - target_X(2))) + sum(abs(target_Y - target_Y(2))) == 0 ) |
|
|
68 |
continue; |
|
|
69 |
end |
|
|
70 |
|
|
|
71 |
target_LINE = [target_X ones(size(target_X))] \ target_Y; %left division-least squares, %y=LINE(1)*x+LINE(2) |
|
|
72 |
target_LINE_inv = [target_Y ones(size(target_Y))] \ target_X; %left division-least squares, %x=LINE(1)*y+LINE(2) Reverse the coordinates. |
|
|
73 |
|
|
|
74 |
%if the line is very close to parallel with the Y axis, and the residuals for the fit |
|
|
75 |
%improve by reversing the coordinates, then use the line found by |
|
|
76 |
%reversing the coordinates. |
|
|
77 |
if ( abs(target_LINE_inv(1))< 0.1 && sum(abs([target_Y ones(size(target_Y))] * target_LINE_inv - target_X)) < sum(abs([target_X ones(size(target_X))] * target_LINE - target_Y))) |
|
|
78 |
target_LINE = 1./(target_LINE_inv + 0.00001) ; |
|
|
79 |
%hold on; plot(target_X- min_showbox_x(1) + showbox_offset,target_Y - min_showbox_y(1) + showbox_offset,'Y*') |
|
|
80 |
end |
|
|
81 |
|
|
|
82 |
%Determine the line normal to the above tangent line (target_LINE). |
|
|
83 |
%Normal line: Ax+By+C=0; |
|
|
84 |
if abs(target_LINE(1)) < 0.01 %fit line parallel to X axis, normal parallel to Y axis |
|
|
85 |
A_N = 1; |
|
|
86 |
B_N = 0; |
|
|
87 |
C_N = -target_curr_x; |
|
|
88 |
reference_xy_subset_to_normal_distance = abs(reference_xy_subset(:,1)- target_curr_x); |
|
|
89 |
elseif abs(target_LINE(1)) > 100 %fit line parallel to Y axis, normal parallel to X axis |
|
|
90 |
A_N = 0; |
|
|
91 |
B_N = 1; |
|
|
92 |
C_N = -target_curr_y; |
|
|
93 |
reference_xy_subset_to_normal_distance = abs(reference_xy_subset(:,2)- target_curr_y); |
|
|
94 |
else |
|
|
95 |
A_N = -1/target_LINE(1); |
|
|
96 |
B_N = -1; |
|
|
97 |
C_N = target_curr_y - A_N * target_curr_x; |
|
|
98 |
reference_xy_subset_to_normal_distance = abs( (A_N*reference_xy_subset(:,1) + B_N*reference_xy_subset(:,2) + C_N))/sqrt(A_N^2 + B_N^2);%normal: y=N(1)*x+N(2); |
|
|
99 |
end |
|
|
100 |
|
|
|
101 |
%find reference point most close to normal |
|
|
102 |
[min_dist_subset, min_idx_subset] = min(reference_xy_subset_to_normal_distance); |
|
|
103 |
|
|
|
104 |
%if there are more than one min distance points, choose the one most close to current target |
|
|
105 |
min_idx_subset_1= find(reference_xy_subset_to_normal_distance <= 0.5); |
|
|
106 |
|
|
|
107 |
if (length(min_idx_subset_1)>=2) |
|
|
108 |
min_dist_subset_to_target_curr_distance = sqrt((target_curr_x - reference_xy_subset(min_idx_subset_1,1)).^2 + (target_curr_y - reference_xy_subset(min_idx_subset_1,2)).^2); |
|
|
109 |
[min_dist_subset, min_idx_subset_2] = min(min_dist_subset_to_target_curr_distance); |
|
|
110 |
reference_to_min_dist_subset_distance = sqrt((reference_xy(:,1) - reference_xy_subset(min_idx_subset_1(min_idx_subset_2),1)).^2 + (reference_xy(:,2) - reference_xy_subset(min_idx_subset_1(min_idx_subset_2),2)).^2); |
|
|
111 |
else |
|
|
112 |
reference_to_min_dist_subset_distance = sqrt((reference_xy(:,1) - reference_xy_subset(min_idx_subset,1)).^2 + (reference_xy(:,2) - reference_xy_subset(min_idx_subset,2)).^2); |
|
|
113 |
end |
|
|
114 |
|
|
|
115 |
min_idx_temp = find(reference_to_min_dist_subset_distance == 0); |
|
|
116 |
min_idx = min_idx_temp(1); |
|
|
117 |
|
|
|
118 |
%Get 3 points of reference,[left most-close-to-normal right] |
|
|
119 |
if min_idx == 1 |
|
|
120 |
reference_xy_3 = [reference_xy(end,:); reference_xy(min_idx:min_idx+1,:)]; |
|
|
121 |
elseif (min_idx == size(reference_xy,1)) |
|
|
122 |
reference_xy_3 = [reference_xy(end-1:end,:); reference_xy(1,:)]; |
|
|
123 |
else |
|
|
124 |
reference_xy_3 = reference_xy(min_idx-1:min_idx+1,:); |
|
|
125 |
end |
|
|
126 |
|
|
|
127 |
%fit reference line: Ax+By+C=0; |
|
|
128 |
reference_X = reference_xy_3(:,1); |
|
|
129 |
reference_Y = reference_xy_3(:,2); |
|
|
130 |
reference_LINE = [reference_X ones(size(reference_X))] \ reference_Y; %left division-least squares, %y=LINE(1)*x+LINE(2) |
|
|
131 |
|
|
|
132 |
reference_LINE_inv = [reference_Y ones(size(reference_Y))] \ reference_X; %left division-least squares, %y=LINE(1)*x+LINE(2) |
|
|
133 |
|
|
|
134 |
%fit line parallel to Y axis, |
|
|
135 |
if ( abs(reference_LINE_inv(1))< 0.1 && sum(abs([reference_Y ones(size(reference_Y))] * reference_LINE_inv - reference_X)) < sum(abs([reference_X ones(size(reference_X))] * reference_LINE - reference_Y))) |
|
|
136 |
reference_LINE = 1./(reference_LINE_inv + 0.00001) ; |
|
|
137 |
%hold on; plot(target_X- min_showbox_x(1) + showbox_offset,target_Y - min_showbox_y(1) + showbox_offset,'Y*') |
|
|
138 |
end |
|
|
139 |
|
|
|
140 |
if abs(reference_LINE(1)) < 0.01 % reference line parallel to X axis |
|
|
141 |
A_R = 0; |
|
|
142 |
B_R = 1; |
|
|
143 |
C_R = -reference_Y(2); |
|
|
144 |
elseif abs(reference_LINE(1)) >100 % reference line parallel to Y axis |
|
|
145 |
A_R = 1; |
|
|
146 |
B_R = 0; |
|
|
147 |
C_R = -reference_X(2); |
|
|
148 |
else |
|
|
149 |
A_R = reference_LINE(1); |
|
|
150 |
B_R = -1; |
|
|
151 |
C_R = reference_Y(2) - A_R * reference_X(2); |
|
|
152 |
end |
|
|
153 |
|
|
|
154 |
%intersection of normal and reference line |
|
|
155 |
AA=[A_N B_N; A_R B_R]; |
|
|
156 |
BB =[-C_N; -C_R]; |
|
|
157 |
XX =AA\BB; % AA is a square matrix, AA\BB is roughly the same as inv(AA)*BB |
|
|
158 |
|
|
|
159 |
%validate intersection point |
|
|
160 |
XX_reference_distance = sqrt((XX(1) - reference_xy_subset(:,1)).^2 + (XX(2) - reference_xy_subset(:,2)).^2 ); |
|
|
161 |
if min(XX_reference_distance)<1.5 |
|
|
162 |
%distance |
|
|
163 |
distance(idx) = sqrt((target_curr_x - XX(1))^2 + (target_curr_y - XX(2))^2); |
|
|
164 |
|
|
|
165 |
else |
|
|
166 |
distance(idx) = -999; |
|
|
167 |
end |
|
|
168 |
end |
|
|
169 |
|
|
|
170 |
%in mm |
|
|
171 |
distance = distance * para.pixel_spacing(1); |
|
|
172 |
distance_effective = distance(distance>0); |
|
|
173 |
varargout{1} =mean(distance_effective); |
|
|
174 |
|
|
|
175 |
end |