forked from mfkasim1/unwrap_phase
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathunwrap_phase.m
153 lines (132 loc) · 6.18 KB
/
unwrap_phase.m
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Fast unwrapping 2D phase image using the algorithm given in: %
% M. A. Herráez, D. R. Burton, M. J. Lalor, and M. A. Gdeisat, %
% "Fast two-dimensional phase-unwrapping algorithm based on sorting by %
% reliability following a noncontinuous path", Applied Optics, Vol. 41, %
% Issue 35, pp. 7437-7444 (2002). %
% %
% If using this code for publication, please kindly cite the following: %
% * M. A. Herraez, D. R. Burton, M. J. Lalor, and M. A. Gdeisat, "Fast %
% two-dimensional phase-unwrapping algorithm based on sorting by reliability %
% following a noncontinuous path", Applied Optics, Vol. 41, Issue 35, %
% pp. 7437-7444 (2002). %
% * M. F. Kasim, "Fast 2D phase unwrapping implementation in MATLAB", %
% https://github.com/mfkasim91/unwrap_phase/ (2017). %
% %
% Input: %
% * img: The wrapped phase image either from -pi to pi or from 0 to 2*pi. %
% If there are unwanted regions, it should be filled with NaNs. %
% %
% Output: %
% * res_img: The unwrapped phase with arbitrary offset. %
% %
% Author: %
% Muhammad F. Kasim, University of Oxford (2017) %
% Email: [email protected] %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function res_img = unwrap_phase(img)
[Ny, Nx] = size(img);
% get the reliability
reliability = get_reliability(img); % (Ny,Nx)
% get the edges
[h_edges, v_edges] = get_edges(reliability); % (Ny,Nx) and (Ny,Nx)
% combine all edges and sort it
edges = [h_edges(:); v_edges(:)];
edge_bound_idx = Ny * Nx; % if i <= edge_bound_idx, it is h_edges
[~, edge_sort_idx] = sort(edges, 'descend');
% get the indices of pixels adjacent to the edges
idxs1 = mod(edge_sort_idx - 1, edge_bound_idx) + 1;
idxs2 = idxs1 + 1 + (Ny - 1) .* (edge_sort_idx <= edge_bound_idx);
% label the group
group = reshape([1:numel(img)], Ny*Nx, 1);
is_grouped = zeros(Ny*Nx,1);
group_members = cell(Ny*Nx,1);
for i = 1:size(is_grouped,1)
group_members{i} = i;
end
num_members_group = ones(Ny*Nx,1);
% propagate the unwrapping
res_img = img;
num_nan = sum(isnan(edges)); % count how many nan-s and skip them
for i = num_nan+1 : length(edge_sort_idx)
% get the indices of the adjacent pixels
idx1 = idxs1(i);
idx2 = idxs2(i);
% skip if they belong to the same group
if (group(idx1) == group(idx2)) continue; end
% idx1 should be ungrouped (swap if idx2 ungrouped and idx1 grouped)
% otherwise, activate the flag all_grouped.
% The group in idx1 must be smaller than in idx2. If initially
% group(idx1) is larger than group(idx2), then swap it.
all_grouped = 0;
if is_grouped(idx1)
if ~is_grouped(idx2)
idxt = idx1;
idx1 = idx2;
idx2 = idxt;
elseif num_members_group(group(idx1)) > num_members_group(group(idx2))
idxt = idx1;
idx1 = idx2;
idx2 = idxt;
all_grouped = 1;
else
all_grouped = 1;
end
end
% calculate how much we should add to the idx1 and group
dval = floor((res_img(idx2) - res_img(idx1) + pi) / (2*pi)) * 2*pi;
% which pixel should be changed
g1 = group(idx1);
g2 = group(idx2);
if all_grouped
pix_idxs = group_members{g1};
else
pix_idxs = idx1;
end
% add the pixel value
if dval ~= 0
res_img(pix_idxs) = res_img(pix_idxs) + dval;
end
% change the group
len_g1 = num_members_group(g1);
len_g2 = num_members_group(g2);
group_members{g2}(len_g2+1:len_g2+len_g1) = pix_idxs;
group(pix_idxs) = g2; % assign the pixels to the new group
num_members_group(g2) = num_members_group(g2) + len_g1;
% mark idx1 and idx2 as already being grouped
is_grouped(idx1) = 1;
is_grouped(idx2) = 1;
end
end
function rel = get_reliability(img)
rel = zeros(size(img));
% get the shifted images (N-2, N-2)
img_im1_jm1 = img(1:end-2, 1:end-2);
img_i_jm1 = img(2:end-1, 1:end-2);
img_ip1_jm1 = img(3:end , 1:end-2);
img_im1_j = img(1:end-2, 2:end-1);
img_i_j = img(2:end-1, 2:end-1);
img_ip1_j = img(3:end , 2:end-1);
img_im1_jp1 = img(1:end-2, 3:end );
img_i_jp1 = img(2:end-1, 3:end );
img_ip1_jp1 = img(3:end , 3:end );
% calculate the difference
gamma = @(x) sign(x) .* mod(abs(x), pi);
H = gamma(img_im1_j - img_i_j) - gamma(img_i_j - img_ip1_j );
V = gamma(img_i_jm1 - img_i_j) - gamma(img_i_j - img_i_jp1 );
D1 = gamma(img_im1_jm1 - img_i_j) - gamma(img_i_j - img_ip1_jp1);
D2 = gamma(img_im1_jp1 - img_i_j) - gamma(img_i_j - img_ip1_jm1);
% calculate the second derivative
D = sqrt(H.*H + V.*V + D1.*D1 + D2.*D2);
% assign the reliability as 1 / D
rel(2:end-1, 2:end-1) = 1./D;
% assign all nan's in rel with non-nan in img to 0
% also assign the nan's in img to nan
rel(isnan(rel) & ~isnan(img)) = 0;
rel(isnan(img)) = nan;
end
function [h_edges, v_edges] = get_edges(rel)
[Ny, Nx] = size(rel);
h_edges = [rel(1:end, 2:end) + rel(1:end, 1:end-1), nan(Ny, 1)];
v_edges = [rel(2:end, 1:end) + rel(1:end-1, 1:end); nan(1, Nx)];
end