How do I implement bilinear interpolation for image data represented as a numpy array in python?
I found many questions on this topic and many answers, though none were efficient for the common case that the data consists of samples on a grid (i.e. a rectangular image) and represented as a numpy array. This function can take lists as both x and y coordinates and will perform the lookups and summations without need for loops.
def bilinear_interpolate(im, x, y):
x = np.asarray(x)
y = np.asarray(y)
x0 = np.floor(x).astype(int)
x1 = x0 + 1
y0 = np.floor(y).astype(int)
y1 = y0 + 1
x0 = np.clip(x0, 0, im.shape[1]-1);
x1 = np.clip(x1, 0, im.shape[1]-1);
y0 = np.clip(y0, 0, im.shape[0]-1);
y1 = np.clip(y1, 0, im.shape[0]-1);
Ia = im[ y0, x0 ]
Ib = im[ y1, x0 ]
Ic = im[ y0, x1 ]
Id = im[ y1, x1 ]
wa = (x1-x) * (y1-y)
wb = (x1-x) * (y-y0)
wc = (x-x0) * (y1-y)
wd = (x-x0) * (y-y0)
return wa*Ia + wb*Ib + wc*Ic + wd*Id
Related
Im trying to create a volume with a custom shape, to add Z-axis data I need to mesh X-Y data.
Hence my issue. I'd like to have this shape as the base
Trapezoid Base
However, after doing
X,Y = np.mesh(x,y)
I get a symmetric rectangle rather than the trapezoid-looking like shape.
meshed data
is there another effecient way I can fill the trapezoid ?
here is the code:
x1 = np.zeros(20)
y1 = np.linspace(-2,2,20)
x2 = np.linspace(0,30,20)
y2 = np.sqrt(( 5/max(x2) * x2 +4 ))
x3 = np.linspace(0, 30, 20)
y3 = -np.sqrt((5 / max(x3) * x3 + 4))
x4 = np.ones(20)*30
y4 = np.linspace(-3,3,20)
x = np.concatenate((x1, x2, x3, x4))
y = np.concatenate((y1,y2,y3,y4))
# u,v = np.meshgrid(x,y)
# x = u.flatten()
# y = v.flatten()
plt.plot(x,y)
plt.show()
Trying to fill a trapizoid shape to construct a 3d volume representation using plotly
I think you can do something like this.
The key is to define a normalized version of y that has a domain of -1 to 1 and multiply it by your final equation for y
import numpy as np
import matplotlib.pyplot as plt
n = 20
x = np.linspace(0, 30, n)
y = np.linspace(-1, 1, n)
xx, yy = np.meshgrid(x, y)
yy *= np.sqrt(5/x.max() * x + 4)
plt.scatter(xx, yy)
plt.show()
I want to plot the motion of a double pendulum with a spring in python. I need to plot the theta1, theta2, r, and their first derivatives. I have found my equations for the motion, which are second-order ODEs so I then converted them to first-order ODEs where x1=theta1, x2=theta1-dot, y1=theta2, y2=theta2-dot, z1=r, and z2=r-dot. Here is a picture of the double pendulum problem: enter image description here
Here is my code:
from scipy.integrate import solve_ivp
from numpy import pi, sin, cos, linspace
g = 9.806 #Gravitational acceleration
l0 = 1 #Natural length of spring is 1
k = 2 #K value for spring is 2
OA = 2 #Length OA is 2
m = 1 #Mass of the particles is 1
def pendulumDynamics1(t, x): #Function to solve for theta-1 double-dot
x1 = x[0]
x2 = x[1]
y1 = y[0]
y2 = y[1]
z1 = z[0]
z2 = z[1]
Fs = -k*(z1-l0)
T = m*(x2**2)*OA + m*g*cos(x1) + Fs*cos(y1-x1)
x1dot = x2
x2dot = (Fs*sin(y1-x1) - m*g*sin(x1))/(m*OA) # angles are in radians
return [x1dot,x2dot]
def pendulumDynamics2(t, y): #Function to solve for theta-2 double-dot
x1 = x[0]
x2 = x[1]
y1 = y[0]
y2 = y[1]
z1 = z[0]
z2 = z[1]
Fs = -k*(z1-l0)
y1dot = y2
y2dot = (-g*sin(y1) - (Fs*cos(y1-x1)*sin(x1))/m + g*cos(y1-x1)*sin(x1) - x2*z1*sin(x1))/z1
return [y1dot,y2dot]
def pendulumDynamics3(t, z): #Function to solve for r double-dot (The length AB which is the spring)
x1 = x[0]
x2 = x[1]
y1 = y[0]
y2 = y[1]
z1 = z[0]
z2 = z[1]
Fs = -k*(z1-l0)
z1dot = z2
z2dot = g*cos(y1) - Fs/m + (y2**2)*z1 + x2*OA*cos(y1-x1) - (Fs*(sin(y1-x1))**2)/m + g*sin(x1)*sin(y1-x1)
return [z1dot,z2dot]
# Define initial conditions, etc
d2r = pi/180
x0 = [30*d2r, 0] # start from 30 deg, with zero velocity
y0 = [60*d2r, 0] # start from 60 deg, with zero velocity
z0 = [1, 0] #Start from r=1
t0 = 0
tf = 10
#Integrate dynamics, initial value problem
sol1 = solve_ivp(pendulumDynamics1,[t0,tf],x0,dense_output=True) # Save as a continuous solution
sol2 = solve_ivp(pendulumDynamics2,[t0,tf],y0,dense_output=True) # Save as a continuous solution
sol3 = solve_ivp(pendulumDynamics3,[t0,tf],z0,dense_output=True) # Save as a continuous solution
t = linspace(t0,tf,200) # determine solution at these times
dt = t[1]-t[0]
x = sol1.sol(t)
y = sol2.sol(t)
z = sol3.sol(t)
I have 3 functions in my code, each to solve for x, y, and z. I then use solve_ivp function to solve for x, and y, and z. The error in the code is:
`File "C:\Users\omora\OneDrive\Dokument\AERO 211\project.py", line 13, in pendulumDynamics1
y1 = y[0]
NameError: name 'y' is not defined`
I don't understand why it is saying that y is not defined, because I defined it in my functions.
Your system is closed without friction, thus can be captured by the Lagrange or Hamiltonian formalism. You have 3 position variables, thus a 6-dimensional dynamical state, complemented either by the velocities or the impulses.
Let q_k be theta_1, theta_2, r, Dq_k their time derivatives and p_k the impulse variables to q_k, then the dynamics can be realized by
def DoublePendulumSpring(u,t,params):
m_1, l_1, m_2, l_2, k, g = params
q_1,q_2,q_3 = u[:3]
p = u[3:]
A = [[l_1**2*(m_1 + m_2), l_1*m_2*q_3*cos(q_1 - q_2), -l_1*m_2*sin(q_1 - q_2)],
[l_1*m_2*q_3*cos(q_1 - q_2), m_2*q_3**2, 0],
[-l_1*m_2*sin(q_1 - q_2), 0, m_2]]
Dq = np.linalg.solve(A,p)
Dq_1,Dq_2,Dq_3 = Dq
T1 = Dq_2*q_3*sin(q_1 - q_2) + Dq_3*cos(q_1 - q_2)
T3 = Dq_1*l_1*cos(q_1 - q_2) + Dq_2*q_3
Dp = [-l_1*(m_2*Dq_1*T1 + g*(m_1+m_2)*sin(q_1)),
l_1*m_2*Dq_1*T1 - g*m_2*q_3*sin(q_2),
m_2*Dq_2*T3 + g*m_2*cos(q_2) + k*(l_2 - q_3) ]
return [*Dq, *Dp]
For a derivation see the Euler-Lagrange equations and their connection to the Hamilton equations. You might get asked about such a derivation.
This, after suitable defining the parameter tuple and initial conditions, can be fed to odeint and produces a solution that can then be plotted, animated or otherwise examined. The lower bob traces a path like the one below, not periodic and not very deterministic. (The fulcrum and the arc of the upper bob are also inserted, but less interesting.)
def pendulumDynamics1(t, x):
x1 = x[0]
x2 = x[1]
y1 = y[0]
y2 = y[1]
z1 = z[0]
z2 = z[1]
You only pass x as a parameter. The code inside the function has no idea what y and z refer to.
You will need to change the function call to also include those variables.
def pendulumDynamics1(t, x, y, z):
I would like to reset/remove offset quaternion data from real-time IMU sensor recordings. E.g. I get [-0.754, -0.0256, 0.0321, 0.324] (XYZW) when I start recordings. I would like to reset this to be [0, 0, 0, 1] when I start recording, as I am using it to rotate a 3D object which initial quaternion values are [X: 0, Y: 0, Z: 0, W: 1].
I tried subtracting all quaternion data from the first as so:
counter = 0
quat = getting_sensor_data_from_somewhere()
while True:
if counter == 1:
offset = quat
calib_data = [x1 -x2 for x1, x2 in zip(quat, offset)
However, it doesn't seem to be the right solution. I am a bit confused of why W should be 1. Can you help me?
The 3D model are from ThreeJS libraries.
Try this out:
def quaternion_multiply(quaternion1, quaternion0):
import numpy as np
w0, x0, y0, z0 = quaternion0
w1, x1, y1, z1 = quaternion1
return np.array([-x1 * x0 - y1 * y0 - z1 * z0 + w1 * w0,
x1 * w0 + y1 * z0 - z1 * y0 + w1 * x0,
-x1 * z0 + y1 * w0 + z1 * x0 + w1 * y0,
x1 * y0 - y1 * x0 + z1 * w0 + w1 * z0], dtype=np.float64)
glob_quat = [1,0,0,0]
counter = 0
quat = getting_sensor_data_from_somewhere() # W,X,Y,Z order
while True:
if counter == 0:
quat_first = [quat[0], -quat[1], -quat[2], -quat[3]]
offset = quaternion_multiply(glob_quat, quat_first)
quat_calib = quaternion_multiply(offset, quat)
# Now first quat will always be [1, 0, 0, 0]
# Shift places if W is at the end instead of in the start
Nice description of usage of equation rotation about axis set as quaterion can be found here:
http://wiki.alioth.net/index.php/Quaternion
quote
A quaternion is a set of four values (W X Y Z) that are used in Oolite to specify a rotation in 3D space. To specify a particular rotation you need to think about the axis about which the rotation is made and the angle or amount by which the model is to be rotated.
For a given axis (x y z) and angle (α), the quaternion representing a rotation of a degrees around the axis from the origin (0,0,0) to (x,y,z) is:
W = cos (0.5 × α)
X = x × sin (0.5 × α)
Y = y × sin (0.5 × α)
Z = z × sin (0.5 × α)
So a rotation of 90 degrees about the z axis (0 0 1) would be:
W = cos 45 ° = 0.707…
X = 0 × sin 45 ° = 0
Y = 0 × sin 45 ° = 0
Z = 1 × sin 45 ° = 0.707…
That mean You need to select different axis to achieve the setting to [0,0,0,1] as desired.
I want to know how many grid points in each closed contour.
assume a mesh grid. I have a list of points which form a closed (connected) contours.
I want to know How many grid points in closed contours separately?
import numpy as np
import matplotlib.pyplot as plt
import xarray as xr
import math
#calculate area
def area(vs):
a = 0
x0, y0 = vs[0]
for [x1, y1] in vs[1:]:
dx = (x1 - x0) * 119.19
dy = (y1 - y0) * 103.09
a += 0.5 * (y0 * dx - x0 * dy)
x0 = x1
y0 = y1
return a
# Read data
ds1 = xr.open_dataset('2015.nc')
lons = ds1.variables['lon'][:]
lats = ds1.variables['lat'][:]
times = ds1.variables['time'][:]
surf_els = ds1.variables['surf_el'][:]
lon = np.asarray(lons)
lat = np.asarray(lats)
time = np.asarray(times)
surf_el = np.asarray(surf_els)
ds1.close()
surf_el_mean = np.nanmean(surf_el[0])
surf_el[0] = (surf_el[0]) - surf_el_mean
#contour level -35/1000
cs = plt.contour(lon, lat, surf_el[0], [-35/1000],colors='r')
#extract path or contours level -35/1000
p = cs.collections[0].get_paths()[0]
v = p.vertices
x = v[:, 0]
y = v[:, 1]
vs = p.vertices
print(p)
plt.show()
#All of p are not closed.Closed contour important for me. but i don't know #how many points inside a closed contour? this problem is similar Pick's #theorem in math.
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')