pytorch (numpy) calculation about the closest pixels to points - python

I am trying to solve a complicated problem.
For example, I have a batch of 2D predicted images (softmax output, value between 0 and 1) with size: Batch x H x W and ground truth Batch x H x W
The light gray color pixels are the background with value 0, and the dark gray color pixels are the foreground with value 1. I try to compute the mass center coordinates using scipy.ndimage.center_of_mass on each ground truth image. Then I get the center location point C (red color) for each ground truth. The C points set is Batch x 1.
Now, for each pixel A (yellow color) in the predicted images, I want to get three pixels B1, B2, B3 (blue color) which are the closest to A on the line AC (here C is corresponding location of mass center in ground truth).
I used following code to get the three closest points B1, B2, B3.
def connect(ends, m=3):
d0, d1 = np.abs(np.diff(ends, axis=0))[0]
if d0 > d1:
return np.c_[np.linspace(ends[0, 0], ends[1, 0], m + 1, dtype=np.int32),
np.round(np.linspace(ends[0, 1], ends[1, 1], m + 1))
.astype(np.int32)]
else:
return np.c_[np.round(np.linspace(ends[0, 0], ends[1, 0], m + 1))
.astype(np.int32),
np.linspace(ends[0, 1], ends[1, 1], m + 1, dtype=np.int32)]
So the B points set is Batch x 3 x H x W.
Then, I want to compute like this: |Value(A)-Value(B1)|+|Value(A)-Value(B2)|+|Value(A)-Value(B3)|. The size of the result should be Batch x H x W.
Is there any numpy vectorization tricks that can be used to update the value of each pixel in predicted images? Or can this be solved using pytorch functions? I need to find a method to update the whole image. The predicted image is the softmax output. I cannot use for loop to compute each single value since it will become non-differentiable. Thanks a lot.

As suggested by #Matin, you could consider Bresenham's algorithm to get your points on the AC line.
A simplistic PyTorch implementation could be as follows (directly adapted from the pseudo-code here ; could be optimized):
import torch
def get_points_from_low(x0, y0, x1, y1, num_points=3):
dx = x1 - x0
dy = y1 - y0
xi = torch.sign(dx)
yi = torch.sign(dy)
dy = dy * yi
D = 2 * dy - dx
y = y0
x = x0
points = []
for n in range(num_points):
x = x + xi
is_D_gt_0 = (D > 0).long()
y = y + is_D_gt_0 * yi
D = D + 2 * dy - is_D_gt_0 * 2 * dx
points.append(torch.stack((x, y), dim=-1))
return torch.stack(points, dim=len(x0.shape))
def get_points_from_high(x0, y0, x1, y1, num_points=3):
dx = x1 - x0
dy = y1 - y0
xi = torch.sign(dx)
yi = torch.sign(dy)
dx = dx * xi
D = 2 * dx - dy
y = y0
x = x0
points = []
for n in range(num_points):
y = y + yi
is_D_gt_0 = (D > 0).long()
x = x + is_D_gt_0 * xi
D = D + 2 * dx - is_D_gt_0 * 2 * dy
points.append(torch.stack((x, y), dim=-1))
return torch.stack(points, dim=len(x0.shape))
def get_points_from(x0, y0, x1, y1, num_points=3):
is_dy_lt_dx = (torch.abs(y1 - y0) < torch.abs(x1 - x0)).long()
is_x0_gt_x1 = (x0 > x1).long()
is_y0_gt_y1 = (y0 > y1).long()
sign = 1 - 2 * is_x0_gt_x1
x0_comp, x1_comp, y0_comp, y1_comp = x0 * sign, x1 * sign, y0 * sign, y1 * sign
points_low = get_points_from_low(x0_comp, y0_comp, x1_comp, y1_comp, num_points=num_points)
points_low *= sign.view(-1, 1, 1).expand_as(points_low)
sign = 1 - 2 * is_y0_gt_y1
x0_comp, x1_comp, y0_comp, y1_comp = x0 * sign, x1 * sign, y0 * sign, y1 * sign
points_high = get_points_from_high(x0_comp, y0_comp, x1_comp, y1_comp, num_points=num_points) * sign
points_high *= sign.view(-1, 1, 1).expand_as(points_high)
is_dy_lt_dx = is_dy_lt_dx.view(-1, 1, 1).expand(-1, num_points, 2)
points = points_low * is_dy_lt_dx + points_high * (1 - is_dy_lt_dx)
return points
# Inputs:
# (#todo: extend A to cover all points in maps):
A = torch.LongTensor([[0, 1], [8, 6]])
C = torch.LongTensor([[6, 4], [2, 3]])
num_points = 3
# Getting points between A and C:
# (#todo: what if there's less than `num_points` between A-C?)
Bs = get_points_from(A[:, 0], A[:, 1], C[:, 0], C[:, 1], num_points=num_points)
print(Bs)
# tensor([[[1, 1],
# [2, 2],
# [3, 2]],
# [[7, 6],
# [6, 5],
# [5, 5]]])
Once you have your points, you could retrieve their "values" (Value(A), Value(B1), etc.) using torch.index_select() (note that as of now, this method only accept 1D indices, so you need to unravel your data). All things put together, this would look like something such as the following (extending A from shape (Batch, 2) to (Batch, H, W, 2) is left for exercise...)
# Inputs:
# (#todo: extend A to cover all points in maps):
A = torch.LongTensor([[0, 1], [8, 6]])
C = torch.LongTensor([[6, 4], [2, 3]])
batch_size = A.shape[0]
num_points = 3
map_size = (9, 9)
map_num_elements = map_size[0] * map_size[1]
map_values = torch.stack((torch.arange(0, map_num_elements).view(*map_size),
torch.arange(0, -map_num_elements, -1).view(*map_size)))
# Getting points between A and C:
# (#todo: what if there's less than `num_points` between A-C?)
Bs = get_points_from(A[:, 0], A[:, 1], C[:, 0], C[:, 1], num_points=num_points)
# Get map values in positions A:
A_unravel = torch.arange(0, batch_size) * map_num_elements
A_unravel = A_unravel + A[:, 0] * map_size[1] + A[:, 1]
values_A = torch.index_select(map_values.view(-1), dim=0, index=A_unravel)
print(values_A)
# tensor([ 1, -4])
# Get map values in positions A:
A_unravel = torch.arange(0, batch_size) * map_num_elements
A_unravel = A_unravel + A[:, 0] * map_size[1] + A[:, 1]
values_A = torch.index_select(map_values.view(-1), dim=0, index=A_unravel)
print(values_A)
# tensor([ 1, -78])
# Get map values in positions B:
Bs_flatten = Bs.view(-1, 2)
Bs_unravel = (torch.arange(0, batch_size)
.unsqueeze(1)
.repeat(1, num_points)
.view(num_points * batch_size) * map_num_elements)
Bs_unravel = Bs_unravel + Bs_flatten[:, 0] * map_size[1] + Bs_flatten[:, 1]
values_B = torch.index_select(map_values.view(-1), dim=0, index=Bs_unravel)
values_B = values_B.view(batch_size, num_points)
print(values_B)
# tensor([[ 10, 20, 29],
# [-69, -59, -50]])
# Compute result:
res = torch.abs(values_A.unsqueeze(-1).expand_as(values_B) - values_B)
print(res)
# tensor([[ 9, 19, 28],
# [ 9, 19, 28]])
res = torch.sum(res, dim=1)
print(res)
# tensor([56, 56])

Related

Measure integral between 2 curves (linear func & arbitrary curve)

In the img. below my goal is to locate the integral in area 1 / 2 / 3.
In that way that I know how much area below the linear line (area 1 / 3),
and how much area that are above the linear line (area 2)
Im not looking for the exact integral, just an approximately value to measure on. an approx that would work in the same fashion for other version of the curves I have represented.
y1: The blue line is a linear function y= -0.148x + 1301.35
y2:The yellow line is a arbitrary curve
Both curves share the same x axis.
image of curves linear & arbitrary curve
I have tried several methods, found here on stackoverflow, mainly theese 2 methods cought my attention:
https://stackoverflow.com/a/57827807
&
https://stackoverflow.com/a/25447819
They give me the exact same output for the whole area, my issue is to seperate it above / below.
Example of my best try:
(Modified version of https://stackoverflow.com/a/25447819/20441461)
y1 / y2 / x - is the data used for the curves in the img. above
y1 = [1298.54771845, 1298.40019417, 1298.2526699, 1298.10514563,
1297.95762136,1297.81009709, 1297.66257282, 1297.51504854]
y2 = [1298.59, 1297.31, 1296.04, 1297.31, 1296.95, 1299.18, 1297.05, 1297.45]
x = np.arange(len(y1))
z = y1-y2
dx = x[1:] - x[:-1]
cross_test = np.sign(z[:-1] * z[1:])
x_intersect = x[:-1] - dx / (z[1:] - z[:-1]) * z[:-1]
dx_intersect = - dx / (z[1:] - z[:-1]) * z[:-1]
areas_pos = abs(z[:-1] + z[1:]) * 0.5 * dx # signs of both z are same
areas_neg = 0.5 * dx_intersect * abs(z[:-1]) + 0.5 * (dx - dx_intersect) * abs(z[1:])
negatives = np.where(cross_test < 0)
negative_sum = np.sum(x_intersect[negatives])
positives = np.where(cross_test >= 0)
positive_sum = np.sum(x_intersect[positives])`
is give me this result:
Negative integral = 10.15
Positive integral = 9.97
Just from looking at the picture, I can tell that can not be the correct value. ( there is alot more area below the linear line than above.)
I have spend loads of time now on this, and are quite stuck - any advise or suggestion are welcome.
Here is a little bit of code that calculates exactly all the areas, and does so in a vectorized way (fast):
def areas(x, y1, y2, details=None):
dy = y1 - y2
b0 = dy[:-1]
b1 = dy[1:]
b = np.c_[b0, b1]
r = np.abs(b0) / (np.abs(b0) + np.abs(b1))
rr = np.c_[r, 1-r]
dx = np.diff(x)
h = rr * dx[:, None]
br = (b * rr[:, ::-1]).sum(1)
a = (b + br[:, None]) * h / 2
result = np.sum(a[a > 0]), np.sum(a[a < 0])
if details is not None:
details.update(locals()) # for debugging
return result
Example:
x = np.array([0,1,2])
y1 = np.array([1,0,3])
y2 = np.array([0,3,4])
>>> areas(x, y1, y2)
(0.125, -3.125)
Your original example:
y1 = np.array([
1298.54771845, 1298.40019417, 1298.2526699, 1298.10514563,
1297.95762136,1297.81009709, 1297.66257282, 1297.51504854])
y2 = np.array([1298.59, 1297.31, 1296.04, 1297.31, 1296.95, 1299.18, 1297.05, 1297.45])
x = np.arange(len(y1))
>>> areas(x, y1, y2)
(5.228440802728334, -0.8687563377282332)
Explanation
To understand how it works, let us consider the quadrilateral of four points: [a, b, c, d], where a and b are at the same x position, and so are c and d. It can be "straight" if none of the edges intersect, or "twisted" otherwise. In both cases, we consider the x-position of the intersection where the twisted version would intersect, and the actual vertical section of the quadrilateral at that position (0 if twisted, or the weighted average of the vertical sides if straight).
Say we call the vertical distances b0 and b1. They are oriented (positive if y1 > y2). The intersection is at x-coordinate x + r * dx, where r = |b0| / (|b0| + |b1|) and is a factor between 0 and 1.
For a twisted quad, the left (triangular) area is b0*r*dx/2 and the right one is b1*(1-r)*dx/2.
For a straight quad, the left area (trapeze) is (b0 + br)/2 * r * dx and the right is (b1 + br) / 2 * (1 - r) * dx, where br is the height at the r horizontal proportion, and br = b0 * (1 - r) + b1 * r.
To generalize, we always use br in the calculation. For twisted quads, it is 0 and we can use the same expression as for straight quads. This is the key to eliminate any tests and produce a pure vectorized function.
The rest is a bit of numpy expressions to calculate all these values efficiently.
Example detail
def plot_details(details, ax=None):
x, y1, y2, dx, r, a = [details[k] for k in 'x y1 y2 dx r a'.split()]
ax = ax if ax else plt.gca()
ax.plot(x, y1, 'b.-')
ax.plot(x, y2, 'r.-')
xmid = x[:-1] + dx * r
[ax.axvline(xi) for xi in xmid]
xy1 = np.c_[x, y1]
xy2 = np.c_[x, y2]
for A,B,C,D,r,(a0,a1) in zip(xy1, xy2, xy1[1:], xy2[1:], r, a):
ACmid = A*(1-r) + C*r
BDmid = B*(1-r) + D*r
q0 = np.c_[A,ACmid,BDmid,B]
q1 = np.c_[ACmid,C,D,BDmid]
ax.fill(*q0, alpha=.2)
ax.fill(*q1, alpha=.2)
ax.text(*q0.mean(1), f'{a0:.3f}', ha='center')
ax.text(*q1.mean(1), f'{a1:.3f}', ha='center')
Taking the earlier example:
x = np.array([0,1,2])
y1 = np.array([1,0,3])
y2 = np.array([0,3,4])
details = {}
>>> areas(x, y1, y2, details)
(0.125, -3.125)
>>> details
{'x': array([0, 1, 2]),
'y1': array([1, 0, 3]),
'y2': array([0, 3, 4]),
'details': {...},
'dy': array([ 1, -3, -1]),
'b0': array([ 1, -3]),
'b1': array([-3, -1]),
'b': array([[ 1, -3],
[-3, -1]]),
'r': array([0.25, 0.75]),
'rr': array([[0.25, 0.75],
[0.75, 0.25]]),
'dx': array([1, 1]),
'h': array([[0.25, 0.75],
[0.75, 0.25]]),
'br': array([ 0. , -1.5]),
'a': array([[ 0.125 , -1.125 ],
[-1.6875, -0.3125]]),
'result': (0.125, -3.125)}
And:
plot_details(details)
Perhaps you can integrate the absolute difference of both arrays:
>>> np.trapz(np.abs(y2 - y1))
7.1417718350001

How to make Matplotlib Animation for a computer simulation of Earth, Moon and Asteroid (only animation part) in Python?

I'm trying to make a computer simulation for Earth, Moon and Asteroid as they orbit around the Sun.
The data r_earth, r_moon and the r_asteroid are already given (they are an array). The xlim and ylim are so big because I have to use real values from the universe, otherwise I wouldn't see anything on the animation.
import numpy as np
def RK4_step(y, t, f, dt): #for numerical part I decided to use RK4 method
k1 = dt * f(y, t)
k2 = dt * f(y + 0.5 * k1, t + 0.5 * dt)
k3 = dt * f(y + 0.5 * k2, t + 0.5 * dt)
k4 = dt * f(y + k3, t + dt)
return (t + dt, y + (k1 + 2. * (k2 + k3) + k4) / 6.)
def integrate_ode(y0, derivative_fn, step_fn, a, b, n):
dt = (b - a) / (n - 1)
t = a
y = np.array(y0)
res = [y]
for _ in range(1, n):
t, y = step_fn(y, t, derivative_fn, dt)
res.append(y)
return (np.linspace(a, b, n), np.array(res))
# np.array(res) is 2D array of dimensions (<time steps>, <um variables>) that holds the values for each time step.
# Initial parameters for body masses(Sun, Earth, Moon, Asteroid)
G = 6.674e-11
m_s = 1.989e30
m_e = 5.972e24
m_m = 7.346e22
m_a = 1e25
def derivative_fn(y, t): # vectors necessary for 2.Newton's Law
d1 = y[1] - y[0]
vec01 = d1 / np.linalg.norm(d1) ** 3
d2 = y[2] - y[0]
vec02 = d2 / np.linalg.norm(d2) ** 3
d3 = y[2] - y[1]
vec12 = d3 / np.linalg.norm(d3) ** 3
der = np.array([
y[3],
y[4],
y[5],
- G * m_s * y[0] / np.linalg.norm(y[0]) ** 3 + G * m_m * vec01 + G * m_a * vec02,
- G * m_s * y[1] / np.linalg.norm(y[1]) ** 3 - G * m_e * vec01 + G * m_a * vec12,
- G * m_s * y[2] / np.linalg.norm(y[2]) ** 3 - G * m_e * vec02 - G * m_m * vec12])
return der
# numerically computed data in the array form
# y = [r_e, r_m, r_a, v_e, v_m, v_a] -> 2D array of size (6, 2)
# the initial distances between the bodies,
# for Earth and Moon we compute it from 2nd Newton's Law (orbital velocity)
r_e0 = 1.519e11
v_e0 = np.sqrt(G * m_s / r_e0)
r_m0 = 1.521e11
v_m0 = np.sqrt(G * m_e / abs(r_m0 - r_e0))
r_a0 = 1e11
v_a0 = 31293 # m/s
y0 = np.array([[r_e0, 0.], [r_m0, 0.], [r_a0, 0.], [0., v_e0], [0., v_e0 + v_m0], [0., v_e0 + v_a0]])
# all the parameters are now in the array y0,
# the last two are velocities relative to the Earth
n = 10000
ts, ys = integrate_ode(y0, derivative_fn, RK4_step, 0., 5.154e7, n)
r_earth = ys[:, 0, :]
r_moon = ys[:, 1, :]
r_asteroid = ys[:, 2, :]
# Plotting
import matplotlib.pyplot as plt
plt.xlabel("x")
plt.ylabel("y")
plt.plot(r_earth[:, 0], r_earth[:, 1], label="Earth")
plt.plot(r_moon[:, 0], r_moon[:, 1], label="Moon")
plt.plot(r_asteroid[:, 0], r_asteroid[:, 1], label="Asteroid")
plt.show()
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
ax.set_xlim([-0.3e12, 0.3e12])
ax.set_ylim([-0.3e12, 0.3e12])
# xlim and ylim are so big because we wouldn't see the animation.
sun, = ax.plot(0., 0., 'oy', ms=20)
earth, = ax.plot(r_earth[0, 0], r_earth[0, 1], 'og', ms=10)
moon, = ax.plot(r_moon[0, 0], r_moon[0, 0], 'ob', ms=3)
asteroid, = ax.plot(r_asteroid[0, 0], r_asteroid[0, 0], 'ok', ms=1)
num_frames = 10000
frame_duration = n / num_frames
def animation_frame(frame):
index = int(frame_duration * frame)
earth.set_data(r_earth[index, 0], r_earth[index, 1])
moon.set_data(r_moon[index, 0] / r_earth[index, 0], r_moon[index, 1] / r_earth[index, 1])
asteroid.set_data(r_asteroid[index, 0] / r_earth[index, 0], r_asteroid[index, 1] / r_earth[index, 1])
return earth, moon, asteroid
animation = FuncAnimation(fig, func=animation_frame, frames=range(num_frames), interval=50)
plt.show()
When I start my code, the Moon is in the same position as Sun, both are static. The Earth is moving around the Sun very slowly and there is no Asteroid on the animation.
How to fix this?
I still want to use real data, but wish that animation would go 100x faster(but still smooth animation). How do I do that?

Transfrom matrix from scipy.spatial.procrustes [duplicate]

Is there something like Matlab's procrustes function in NumPy/SciPy or related libraries?
For reference. Procrustes analysis aims to align 2 sets of points (in other words, 2 shapes) to minimize square distance between them by removing scale, translation and rotation warp components.
Example in Matlab:
X = [0 1; 2 3; 4 5; 6 7; 8 9]; % first shape
R = [1 2; 2 1]; % rotation matrix
t = [3 5]; % translation vector
Y = X * R + repmat(t, 5, 1); % warped shape, no scale and no distortion
[d Z] = procrustes(X, Y); % Z is Y aligned back to X
Z
Z =
0.0000 1.0000
2.0000 3.0000
4.0000 5.0000
6.0000 7.0000
8.0000 9.0000
Same task in NumPy:
X = arange(10).reshape((5, 2))
R = array([[1, 2], [2, 1]])
t = array([3, 5])
Y = dot(X, R) + t
Z = ???
Note: I'm only interested in aligned shape, since square error (variable d in Matlab code) is easily computed from 2 shapes.
I'm not aware of any pre-existing implementation in Python, but it's easy to take a look at the MATLAB code using edit procrustes.m and port it to Numpy:
def procrustes(X, Y, scaling=True, reflection='best'):
"""
A port of MATLAB's `procrustes` function to Numpy.
Procrustes analysis determines a linear transformation (translation,
reflection, orthogonal rotation and scaling) of the points in Y to best
conform them to the points in matrix X, using the sum of squared errors
as the goodness of fit criterion.
d, Z, [tform] = procrustes(X, Y)
Inputs:
------------
X, Y
matrices of target and input coordinates. they must have equal
numbers of points (rows), but Y may have fewer dimensions
(columns) than X.
scaling
if False, the scaling component of the transformation is forced
to 1
reflection
if 'best' (default), the transformation solution may or may not
include a reflection component, depending on which fits the data
best. setting reflection to True or False forces a solution with
reflection or no reflection respectively.
Outputs
------------
d
the residual sum of squared errors, normalized according to a
measure of the scale of X, ((X - X.mean(0))**2).sum()
Z
the matrix of transformed Y-values
tform
a dict specifying the rotation, translation and scaling that
maps X --> Y
"""
n,m = X.shape
ny,my = Y.shape
muX = X.mean(0)
muY = Y.mean(0)
X0 = X - muX
Y0 = Y - muY
ssX = (X0**2.).sum()
ssY = (Y0**2.).sum()
# centred Frobenius norm
normX = np.sqrt(ssX)
normY = np.sqrt(ssY)
# scale to equal (unit) norm
X0 /= normX
Y0 /= normY
if my < m:
Y0 = np.concatenate((Y0, np.zeros(n, m-my)),0)
# optimum rotation matrix of Y
A = np.dot(X0.T, Y0)
U,s,Vt = np.linalg.svd(A,full_matrices=False)
V = Vt.T
T = np.dot(V, U.T)
if reflection != 'best':
# does the current solution use a reflection?
have_reflection = np.linalg.det(T) < 0
# if that's not what was specified, force another reflection
if reflection != have_reflection:
V[:,-1] *= -1
s[-1] *= -1
T = np.dot(V, U.T)
traceTA = s.sum()
if scaling:
# optimum scaling of Y
b = traceTA * normX / normY
# standarised distance between X and b*Y*T + c
d = 1 - traceTA**2
# transformed coords
Z = normX*traceTA*np.dot(Y0, T) + muX
else:
b = 1
d = 1 + ssY/ssX - 2 * traceTA * normY / normX
Z = normY*np.dot(Y0, T) + muX
# transformation matrix
if my < m:
T = T[:my,:]
c = muX - b*np.dot(muY, T)
#transformation values
tform = {'rotation':T, 'scale':b, 'translation':c}
return d, Z, tform
There is a Scipy function for it: scipy.spatial.procrustes
I'm just posting its example here:
>>> import numpy as np
>>> from scipy.spatial import procrustes
>>> a = np.array([[1, 3], [1, 2], [1, 1], [2, 1]], 'd')
>>> b = np.array([[4, -2], [4, -4], [4, -6], [2, -6]], 'd')
>>> mtx1, mtx2, disparity = procrustes(a, b)
>>> round(disparity)
0.0
You can have both Ordinary Procrustes Analysis and Generalized Procrustes Analysis in python with something like this:
import numpy as np
def opa(a, b):
aT = a.mean(0)
bT = b.mean(0)
A = a - aT
B = b - bT
aS = np.sum(A * A)**.5
bS = np.sum(B * B)**.5
A /= aS
B /= bS
U, _, V = np.linalg.svd(np.dot(B.T, A))
aR = np.dot(U, V)
if np.linalg.det(aR) < 0:
V[1] *= -1
aR = np.dot(U, V)
aS = aS / bS
aT-= (bT.dot(aR) * aS)
aD = (np.sum((A - B.dot(aR))**2) / len(a))**.5
return aR, aS, aT, aD
def gpa(v, n=-1):
if n < 0:
p = avg(v)
else:
p = v[n]
l = len(v)
r, s, t, d = np.ndarray((4, l), object)
for i in range(l):
r[i], s[i], t[i], d[i] = opa(p, v[i])
return r, s, t, d
def avg(v):
v_= np.copy(v)
l = len(v_)
R, S, T = [list(np.zeros(l)) for _ in range(3)]
for i, j in np.ndindex(l, l):
r, s, t, _ = opa(v_[i], v_[j])
R[j] += np.arccos(min(1, max(-1, np.trace(r[:1])))) * np.sign(r[1][0])
S[j] += s
T[j] += t
for i in range(l):
a = R[i] / l
r = [np.cos(a), -np.sin(a)], [np.sin(a), np.cos(a)]
v_[i] = v_[i].dot(r) * (S[i] / l) + (T[i] / l)
return v_.mean(0)
For testing purposes, the output of each algorithm can be visualized as follows:
import matplotlib.pyplot as p; p.rcParams['toolbar'] = 'None';
def plt(o, e, b):
p.figure(figsize=(10, 10), dpi=72, facecolor='w').add_axes([0.05, 0.05, 0.9, 0.9], aspect='equal')
p.plot(0, 0, marker='x', mew=1, ms=10, c='g', zorder=2, clip_on=False)
p.gcf().canvas.set_window_title('%f' % e)
x = np.ravel(o[0].T[0])
y = np.ravel(o[0].T[1])
p.xlim(min(x), max(x))
p.ylim(min(y), max(y))
a = []
for i, j in np.ndindex(len(o), 2):
a.append(o[i].T[j])
O = p.plot(*a, marker='x', mew=1, ms=10, lw=.25, c='b', zorder=0, clip_on=False)
O[0].set(c='r', zorder=1)
if not b:
O[2].set_color('b')
O[2].set_alpha(0.4)
p.axis('off')
p.show()
# Fly wings example (Klingenberg, 2015 | https://en.wikipedia.org/wiki/Procrustes_analysis)
arr1 = np.array([[588.0, 443.0], [178.0, 443.0], [56.0, 436.0], [50.0, 376.0], [129.0, 360.0], [15.0, 342.0], [92.0, 293.0], [79.0, 269.0], [276.0, 295.0], [281.0, 331.0], [785.0, 260.0], [754.0, 174.0], [405.0, 233.0], [386.0, 167.0], [466.0, 59.0]])
arr2 = np.array([[477.0, 557.0], [130.129, 374.307], [52.0, 334.0], [67.662, 306.953], [111.916, 323.0], [55.119, 275.854], [107.935, 277.723], [101.899, 259.73], [175.0, 329.0], [171.0, 345.0], [589.0, 527.0], [591.0, 468.0], [299.0, 363.0], [306.0, 317.0], [406.0, 288.0]])
def opa_out(a):
r, s, t, d = opa(a[0], a[1])
a[1] = a[1].dot(r) * s + t
return a, d, False
plt(*opa_out([arr1, arr2, np.matrix.copy(arr2)]))
def gpa_out(a):
g = gpa(a, -1)
D = [avg(a)]
for i in range(len(a)):
D.append(a[i].dot(g[0][i]) * g[1][i] + g[2][i])
return D, sum(g[3])/len(a), True
plt(*gpa_out([arr1, arr2]))
Probably you want to try this package with various flavors of different Procrustes methods, https://github.com/theochem/procrustes.

how to compute covariance in tensorflow?

I have a problem that I don't know how to compute the covariance of two tensor. I have tried the contrib.metrics.streaming_covariance. But is always returns 0. There must be some errors.
You could use the definition of the covariance of two random variables X and Y with the expected values x0 and y0:
cov_xx = 1 / (N-1) * Sum_i ((x_i - x0)^2)
cov_yy = 1 / (N-1) * Sum_i ((y_i - y0)^2)
cov_xy = 1 / (N-1) * Sum_i ((x_i - x0) * (y_i - y0))
The crucial point is to estimate x0 and y0 here, since you normally do not know the probability distribution. In many cases, the mean of the x_i or y_i is estimated to be x_0 or y_0, respectively, i.e. the distribution is estimated to be uniform.
Then you can compute the elements of the covariance matrix as follows:
import tensorflow as tf
x = tf.constant([1, 4, 2, 5, 6, 24, 15], dtype=tf.float64)
y = tf.constant([8, 5, 4, 6, 2, 1, 1], dtype=tf.float64)
cov_xx = 1 / (tf.shape(x)[0] - 1) * tf.reduce_sum((x - tf.reduce_mean(x))**2)
cov_yy = 1 / (tf.shape(x)[0] - 1) * tf.reduce_sum((y - tf.reduce_mean(y))**2)
cov_xy = 1 / (tf.shape(x)[0] - 1) * tf.reduce_sum((x - tf.reduce_mean(x)) * (y - tf.reduce_mean(y)))
with tf.Session() as sess:
sess.run([cov_xx, cov_yy, cov_xy])
print(cov_xx.eval(), cov_yy.eval(), cov_xy.eval())
Of course, if you need the covariance in a matrix form, you can modify the last part as follows:
with tf.Session() as sess:
sess.run([cov_xx, cov_yy, cov_xy])
print(cov_xx.eval(), cov_yy.eval(), cov_xy.eval())
cov = tf.constant([[cov_xx.eval(), cov_xy.eval()], [cov_xy.eval(),
cov_yy.eval()]])
print(cov.eval())
To verify the elements of the TensorFlow way, you can check with numpy:
import numpy as np
x = np.array([1,4,2,5,6, 24, 15], dtype=float)
y = np.array([8,5,4,6,2,1,1], dtype=float)
pc = np.cov(x,y)
print(pc)
You can also try tensorflow probability for easy calculation of correlation or covariance.
x = tf.random_normal(shape=(100, 2, 3))
y = tf.random_normal(shape=(100, 2, 3))
# cov[i, j] is the sample covariance between x[:, i, j] and y[:, i, j].
cov = tfp.stats.covariance(x, y, sample_axis=0, event_axis=None)
# cov_matrix[i, m, n] is the sample covariance of x[:, i, m] and y[:, i, n]
cov_matrix = tfp.stats.covariance(x, y, sample_axis=0, event_axis=-1)

Producing 2D perlin noise with numpy

I'm trying to produce 2D perlin noise using numpy, but instead of something smooth I get this :
my broken perlin noise, with ugly squares everywhere
For sure, I'm mixing up my dimensions somewhere, probably when I combine the four gradients ... But I can't find it and my brain is melting right now. Anyone can help me pinpoint the problem ?
Anyway, here is the code:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
def perlin(x,y,seed=0):
# permutation table
np.random.seed(seed)
p = np.arange(256,dtype=int)
np.random.shuffle(p)
p = np.stack([p,p]).flatten()
# coordinates of the first corner
xi = x.astype(int)
yi = y.astype(int)
# internal coordinates
xf = x - xi
yf = y - yi
# fade factors
u = fade(xf)
v = fade(yf)
# noise components
n00 = gradient(p[p[xi]+yi],xf,yf)
n01 = gradient(p[p[xi]+yi+1],xf,yf-1)
n11 = gradient(p[p[xi+1]+yi+1],xf-1,yf-1)
n10 = gradient(p[p[xi+1]+yi],xf-1,yf)
# combine noises
x1 = lerp(n00,n10,u)
x2 = lerp(n10,n11,u)
return lerp(x2,x1,v)
def lerp(a,b,x):
"linear interpolation"
return a + x * (b-a)
def fade(t):
"6t^5 - 15t^4 + 10t^3"
return 6 * t**5 - 15 * t**4 + 10 * t**3
def gradient(h,x,y):
"grad converts h to the right gradient vector and return the dot product with (x,y)"
vectors = np.array([[0,1],[0,-1],[1,0],[-1,0]])
g = vectors[h%4]
return g[:,:,0] * x + g[:,:,1] * y
lin = np.linspace(0,5,100,endpoint=False)
y,x = np.meshgrid(lin,lin)
plt.imshow(perlin(x,y,seed=0))
Thanks to Paul Panzer and a good night of sleep it works now ...
import numpy as np
import matplotlib.pyplot as plt
def perlin(x, y, seed=0):
# permutation table
np.random.seed(seed)
p = np.arange(256, dtype=int)
np.random.shuffle(p)
p = np.stack([p, p]).flatten()
# coordinates of the top-left
xi, yi = x.astype(int), y.astype(int)
# internal coordinates
xf, yf = x - xi, y - yi
# fade factors
u, v = fade(xf), fade(yf)
# noise components
n00 = gradient(p[p[xi] + yi], xf, yf)
n01 = gradient(p[p[xi] + yi + 1], xf, yf - 1)
n11 = gradient(p[p[xi + 1] + yi + 1], xf - 1, yf - 1)
n10 = gradient(p[p[xi + 1] + yi], xf - 1, yf)
# combine noises
x1 = lerp(n00, n10, u)
x2 = lerp(n01, n11, u) # FIX1: I was using n10 instead of n01
return lerp(x1, x2, v) # FIX2: I also had to reverse x1 and x2 here
def lerp(a, b, x):
"linear interpolation"
return a + x * (b - a)
def fade(t):
"6t^5 - 15t^4 + 10t^3"
return 6 * t**5 - 15 * t**4 + 10 * t**3
def gradient(h, x, y):
"grad converts h to the right gradient vector and return the dot product with (x,y)"
vectors = np.array([[0, 1], [0, -1], [1, 0], [-1, 0]])
g = vectors[h % 4]
return g[:, :, 0] * x + g[:, :, 1] * y
lin = np.linspace(0, 5, 100, endpoint=False)
x, y = np.meshgrid(lin, lin) # FIX3: I thought I had to invert x and y here but it was a mistake
plt.imshow(perlin(x, y, seed=2), origin='upper')

Categories

Resources