Skip to content

unwrap: phase unwrapping

moraine.api.unwrap (source). Every name is also moraine.<name> (import moraine as mr) except delaunay_halfedges, delaunay, imported from the module.

delaunay: 2D Delaunay triangulation (sweep-hull), used by the phase unwrapping of point clouds

delaunay_halfedges

delaunay_halfedges(x, y)

Delaunay triangulation of unique points as half-edges.

Parameters:

Name Type Description Default
x ndarray

x coordinates, shape (n,)

required
y ndarray

y coordinates, shape (n,)

required

Returns:

Name Type Description
tri ndarray

start vertex of every half-edge, shape (3 * n_tri,), np.int32; triangles are clockwise

half ndarray

twin half-edge, shape (3 * n_tri,), np.int32; -1 on the convex hull

delaunay

delaunay(x, y)

Delaunay triangulation of unique points in the format of scipy.spatial.Delaunay.

Parameters:

Name Type Description Default
x ndarray

x coordinates, shape (n,)

required
y ndarray

y coordinates, shape (n,)

required

Returns:

Name Type Description
simplices ndarray

vertices of the triangles, counter clockwise, shape (n_tri, 3)

neighbors ndarray

neighbors[t, k] is the triangle opposite vertex k of triangle t, -1 on the hull, shape (n_tri, 3)

mcf: minimum cost flow unwrapping of point clouds

mcf_pc

mcf_pc(pc_x: ndarray, pc_y: ndarray, ph: ndarray, earth_cost: int = 1, spatial_cost: str = 'constant') -> ndarray

Minimum cost flow phase unwrapping of a point cloud interferogram.

Parameters:

Name Type Description Default
pc_x ndarray

x coordinate, shape (N,); the coordinates must be unique and not all collinear

required
pc_y ndarray

y coordinate, shape (N,)

required
ph ndarray

wrapped phase (complex), shape (N,)

required
earth_cost int

cost of a phase jump across the convex hull of the points, relative to 1 inside; a larger value discourages discharging residues through the border

1
spatial_cost str

where phase jumps are placed first: 'constant' (anywhere alike) or 'length' (long connections between points)

'constant'

Returns:

Type Description
ndarray

unwrapped phase, shape (N,), np.float64; the first point keeps its wrapped phase

emcf: extended minimum cost flow (EMCF) unwrapping of point cloud interferogram networks

emcf_pc

emcf_pc(pc_x: ndarray, pc_y: ndarray, ph: ndarray, t: ndarray = None, image_pairs: ndarray = None, weight: ndarray = None, earth_cost: int = 1, temporal_cost: str = 'constant', spatial_cost: str = 'constant', n_workers: int = None)

Extended minimum cost flow (EMCF) phase unwrapping of point cloud interferograms.

The interferograms of a network of image pairs are unwrapped together: the redundancy of the network (image pairs that close loops, e.g. (a, b), (b, c) and (a, c)) is used against unwrapping errors.

Parameters:

Name Type Description Default
pc_x ndarray

x coordinate, shape (n_points,), e.g. in meters; the coordinates must be unique and not all collinear

required
pc_y ndarray

y coordinate, shape (n_points,), in the same unit as pc_x

required
ph ndarray

wrapped phase history (complex), shape (n_points, nimages)

required
t ndarray

acquisition time of the images, e.g. in days, shape (nimages,); needed by temporal_cost 'length'

None
image_pairs ndarray

the interferograms: (reference, secondary) image indices, shape (n_pairs, 2), int; the interferogram is reference * conj(secondary). By default every image is paired with the next three. Without any loop in the network every interferogram is unwrapped alone (a warning is given)

None
weight ndarray

quality of the points from 0 (unreliable) to 1, e.g. the temporal coherence, shape (n_points,); used by spatial_cost 'weight'

None
earth_cost int

cost of a phase jump across the border of the network of points, relative to 1 inside; a larger value discourages discharging residues through the border

1
temporal_cost str

which interferograms are corrected first where the interferograms of a loop of image pairs disagree: 'constant' (all alike) or 'length' (the longest in time)

'constant'
spatial_cost str

where phase jumps are placed first in every interferogram: 'constant' (anywhere alike), 'length' (long connections between points), 'weight' (points of low weight) or 'length+weight'

'constant'
n_workers int

number of interferograms unwrapped at the same time, each needing about 200 bytes per point; by default as many as the available cores and half of the available memory allow

None

Returns:

Name Type Description
unw ndarray

unwrapped phase of the interferograms in radians, shape (n_points, n_pairs), np.float32; at the first point it is the difference of the wrapped phases of the two images. Loops of image pairs may still not add up to zero at some points: see unwrap_correct_closure_pc

image_pairs ndarray

the interferograms (reference, secondary), as given or the default network, shape (n_pairs, 2), np.int32

closure: correction of unwrapping errors of point cloud interferogram networks by phase closure

unwrap_correct_closure_pc

unwrap_correct_closure_pc(pc_x: ndarray, pc_y: ndarray, ph: ndarray, unw: ndarray, image_pairs: ndarray, ref: int = 0, max_edge_factor: float = 4.0, min_region_points: int = 30)

Correction of unwrapping errors of point cloud interferograms by phase closure, to the unwrapped phase of every image.

The unwrapped phases of every loop of image pairs should add up to zero, e.g. unw(a, b) + unw(b, c) = unw(a, c). Where they do not, the interferograms are corrected by whole cycles, changing as few interferograms as possible, by the same amount for all points of a region: the points connected by edges of the point network no longer than max_edge_factor times the median edge length. Points of smaller regions than min_region_points are corrected one by one. The correction assumes that most interferograms of a region are right: where most are wrong, it makes them worse. Where a point still does not fit the loops after the correction of its region, the interferograms fitting most of its loops are kept. The result is the unwrapped phase of every image, whose differences close every loop. Errors that close every loop (e.g. the same whole cycles in every interferogram of one image) are neither corrected nor reported.

Parameters:

Name Type Description Default
pc_x ndarray

x coordinate, shape (n_points,), e.g. in meters; the coordinates must be unique and not all collinear

required
pc_y ndarray

y coordinate, shape (n_points,), in the same unit as pc_x

required
ph ndarray

wrapped phase history (complex), shape (n_points, nimages)

required
unw ndarray

unwrapped phase of the interferograms in radians, shape (n_points, n_pairs), e.g. from mcf_pc or emcf_pc; rewrapped, it must be the phase of ph[:, reference] * conj(ph[:, secondary])

required
image_pairs ndarray

the interferograms: (reference, secondary) image indices of the columns of unw, shape (n_pairs, 2), int; the pairs must connect all images; the network needs loops (e.g. every image paired with the next three) to correct anything, otherwise only the image phases are computed (a warning is given)

required
ref int

index of the reference image, 0 .. nimages - 1: the image phases are relative to it

0
max_edge_factor float

edges of the point network longer than this times the median edge length do not connect a region, e.g. edges across water or decorrelated areas; larger than 1

4.0
min_region_points int

in regions of fewer points every point is corrected by its own loops alone, which is less reliable

30

Returns:

Name Type Description
ts ndarray

unwrapped phase of every image relative to image ref in radians, shape (n_points, nimages), np.float32; ts[:, ref] is 0; rewrapped, ts[:, j] is the phase of ph[:, j] * conj(ph[:, ref]); the corrected interferogram (a, b) is ts[:, a] - ts[:, b]

misclosure_fraction ndarray

fraction of the interferograms of every point that do not fit the loops before the correction, shape (n_points,), np.float32, 0..1; 0 where every loop closes

change_fraction ndarray

fraction of the interferograms of every point whose whole cycles in the result differ from unw, shape (n_points,), np.float32, 0..1; 0 where unw was kept; large values mark points whose input unwrapping was poor (e.g. to be masked)

region ndarray

region of every point, shape (n_points,), np.int32: 0 .. n_regions - 1, or -1 for the points of regions smaller than min_region_points, corrected one by one (e.g. to be masked)

gamma: GAMMA's point cloud unwrapping

gamma_mcf_pt

gamma_mcf_pt(pc_x: ndarray, pc_y: ndarray, ph: ndarray, ph_weight: ndarray = None, ref_point: int = 0) -> ndarray

A simple wrapper for mcf_pt in GAMMA software, only work if you have access to mcf_pt.

Parameters:

Name Type Description Default
pc_x ndarray

x coordinate, shape of (N,)

required
pc_y ndarray

y coordinate, shape of (N,)

required
ph ndarray

wrapped phase, shape of (N,) or (N,M)

required
ph_weight ndarray

point weight, shape of (N,) or (N,M), optional

None
ref_point int

index of the reference point (from 0), the first point by default

0

Returns:

Type Description
ndarray

unwrapped phase, shape of (N,) or (N,M)

Examples

Run when this manual is built; the output follows each snippet.

import numpy as np
import moraine as mr
from moraine.api.unwrap.delaunay_ import delaunay

rng = np.random.default_rng(0)
n = 400
x, y = rng.uniform(0, 1000, n), rng.uniform(0, 1000, n)         # point coordinates in meters, unique
simplices, neighbors = delaunay(x, y)                            # Delaunay triangulation (scipy.spatial.Delaunay format)
print(simplices.shape, neighbors.shape)

phi = 0.004 * x + 0.006 * y                                      # a phase ramp of a few cycles (less than pi between neighbours)
ph = np.exp(1j * phi).astype(np.complex64)                       # the wrapped interferogram
unw = mr.mcf_pc(x, y, ph)                                        # minimum cost flow unwrapping, (n,)
err = (unw - unw[0]) - (phi - phi[0])
print('max error [rad]', np.abs(err).max().round(6))
(781, 3) (781, 3)
max error [rad] 0.0
nimages = 4
phis = np.stack([k * phi / 3 for k in range(nimages)], axis=1)   # a phase history growing with time
phs = np.exp(1j * phis).astype(np.complex64)                     # (n_points, nimages)
unw, pairs = mr.emcf_pc(x, y, phs, image_pairs=mr.TempNet.from_bandwidth(nimages, bandwidth=2).image_pairs)
print(unw.shape, pairs.shape)
truth = phis[:, pairs[:, 0]] - phis[:, pairs[:, 1]]
err = (unw - unw[:1]) - (truth - truth[:1])
print('max error [rad]', np.abs(err).max().round(6))
(400, 5) (5, 2)
max error [rad] 0.0

unwrap_correct_closure_pc corrects the interferograms of a network where loops do not close and gives the unwrapped phase of every image; gamma_mcf_pt wraps GAMMA's mcf_pt for comparison.