Source code for autocnet.transformation.decompose

import numpy as np
from scipy.stats import pearsonr


def cart2polar(x, y):
    theta = np.arctan2(y, x)
    return -theta

[docs]def index_coords(data, origin=None): """Creates x & y coords for the indicies in a numpy array "data". "origin" defaults to the center of the image. Specify origin=(0,0) to set the origin to the lower left corner of the image.""" ny, nx = data.shape[:2] if origin is None: origin_x, origin_y = nx // 2, ny // 2 else: origin_x, origin_y = origin x, y = np.meshgrid(np.arange(nx), np.arange(ny)) x -= origin_x y -= origin_y return x, y
[docs]def reproject_image_into_polar(data, origin=None): """Reprojects a 3D numpy array ("data") into a polar coordinate system. "origin" is a tuple of (x0, y0) and defaults to the center of the image.""" ny, nx = data.shape[:2] if origin is None: origin = (nx//2, ny//2) # Determine that the min and max r and theta coords will be... x, y = index_coords(data, origin=origin) theta = cart2polar(x, y) theta[theta < 0] += 2 * np.pi return theta
[docs]def coupled_decomposition(sdata, ddata, sorigin=(), dorigin=(), M=4, theta_steps=720, theta=None): """ Apply coupled decomposition to two 2d images. sdata : ndarray (n,m) array of values to decompose ddata : ndarray (j,k) array of values to decompose sorigin : tuple in the form (x,y) dorigin : tuple in the form (x,y) """ soriginx, soriginy = sorigin doriginx, doriginy = dorigin # Create membership arrays for each input image smembership = np.ones(sdata.shape) dmembership = np.ones(ddata.shape) # Project the image into a polar coordinate system centered on p_{1} stheta = reproject_image_into_polar(sdata, origin=(int(soriginx), int(soriginy))) dtheta = reproject_image_into_polar(ddata, origin=(int(doriginx), int(doriginy))) if theta == None: # Compute the mean profiles for each radial slice smean = np.empty(theta_steps) dmean = np.empty(theta_steps) radial_step = 2 * np.pi / theta_steps # 0.5 deg thetas = np.arange(0, 2 * np.pi, radial_step) for i, t in enumerate(thetas): smean[i] = np.nanmean(sdata[(stheta >= t) & (stheta <= t + radial_step)]) dmean[i] = np.nanmean(ddata[(dtheta >= t) & (dtheta <= t + radial_step)]) # Rotate the second image around the origin and compute the correlation coeff. for each 0.5 degree rotation. maxp = -1 maxidx = 0 dsearch=np.empty(theta_steps) for j in range(theta_steps): dsearch = np.concatenate((dmean[j:], dmean[:j])) r, _ = pearsonr(smean, dsearch) if r >= maxp: maxp = r maxidx = j # Maximum correlation (theta) defines the angle of rotation for the destination image theta = thetas[maxidx] # Classify the sub-images based on the decomposition size (M) and theta smembership[(stheta >= 0) & (stheta <= np.pi/2)] = 0 smembership[(stheta >= np.pi/2) & (stheta <= np.pi)] = 1 smembership[(stheta >=np.pi) & (stheta <= 3 * np.pi/2)] = 2 smembership[(stheta >= 3 * np.pi/2) & (stheta <= 2 * np.pi)] = 3 if 0 <= theta <= np.pi / 2: order = [0,1,2,3] elif np.pi/2 <= theta <= np.pi: order = [1,2,3,0] elif np.pi <= theta <= 3*np.pi/2: order = [2,3,0,1] elif 3*np.pi/2 <= theta <= 2*np.pi: order = [3,0,1,2] def wrap(v): return v % (2 * np.pi) def classify(start, stop, classid): start = wrap(start) stop = wrap(stop) if start > stop: dmembership[(dtheta >=start) & (dtheta <= 2*np.pi)] = classid dmembership[(dtheta >=0) & (dtheta <= stop)] = classid else: dmembership[(dtheta >= start) & (dtheta <= stop)] = classid classify(theta, theta + np.pi/2, 0) classify(theta + np.pi/2, theta + np.pi, 1) classify(theta + np.pi, theta + 3*np.pi/2,2) classify(theta + 3*np.pi/2, theta + 2*np.pi, 3) return smembership, dmembership