Related
I'm trying to project 3D body keypoints to 2D keypoints,
My 3D points are:
points = np.array([[-7.55801499e-02, -3.69511306e-01, -2.63576955e-01],
[ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[ 3.08661222e-01, -2.93346141e-02, 3.72593999e-02],
[ 5.96781611e-01, -2.82074720e-01, 4.71359938e-01],
[ 5.38534284e-01, -8.05779934e-01, 4.68694866e-01],
[-3.67936224e-01, -1.09069087e-01, 9.90774706e-02],
[-5.24732828e-01, -2.87176669e-01, 6.09635711e-01],
[-4.37022656e-01, -7.87327409e-01, 4.43706572e-01],
[ 1.33009470e-09, -5.10657072e-09, 1.00000000e+00],
[ 1.13241628e-01, 3.25177647e-02, 1.24026799e+00],
[ 3.43442023e-01, -2.51034945e-01, 1.90472209e+00],
[ 2.57550180e-01, -2.86886752e-01, 2.75528717e+00],
[-1.37361348e-01, -2.60521360e-02, 1.19951272e+00],
[-3.26779515e-01, -5.59706092e-01, 1.75905156e+00],
[-4.65996087e-01, -7.69565761e-01, 2.56634569e+00],
[-1.89841837e-02, -3.19088846e-01, -3.69913191e-01],
[-1.61812544e-01, -3.10732543e-01, -3.47061515e-01],
[ 7.68100023e-02, -1.19293019e-01, -3.72248143e-01],
[-2.24317372e-01, -1.02143347e-01, -3.32051814e-01],
[-3.77829641e-01, -1.19915462e+00, 2.56900430e+00],
[-5.45104921e-01, -1.13393784e+00, 2.57149625e+00],
[-5.66698492e-01, -6.89325571e-01, 2.67840290e+00],
[ 4.65222150e-01, -6.44857705e-01, 2.83186650e+00],
[ 5.27995050e-01, -4.69421804e-01, 2.87518311e+00],
[ 1.77749291e-01, -1.74753308e-01, 2.88810611e+00]])
I plotted them using:
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.set_xlim3d(1, -1)
ax.set_ylim3d(1, -1)
ax.set_zlim3d(1, -1)
ax.scatter3D(points[:, 0], points[:, 1],
points[:, 2], cmap='Greens')
The result is:
I want an array of 2D points with the same camera view, so my desired result a 2D array:
I have tried so far:
import cv2
ans = []
for k in range(25):
tmp = np.array(s[0, k, :]).reshape(1,3)
revc = np.array([0, 0, 0], np.float) # rotation vector
tvec = np.array([0, 0, 0], np.float) # translation vector
fx = fy = 1.0
cx = cy = 0.0
cameraMatrix = np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]])
result = cv2.projectPoints(tmp, revc, tvec, cameraMatrix, None)
ans.append(result[0])
ans = np.array(ans).squeeze()
But the result I'm getting is:
plt.scatter(ans[:,0], ans[:, 1])
I can't figure out why the information is lost during projection, kindly help me in this. Also its not necessary for me to use OpenCV so you can suggest other methods like using numpy too.
Thanks
Here's a way to do this from "scratch". I have the following import statements:
import numpy as np
import matplotlib.pyplot as plt
from numpy import sin,cos,pi
from scipy.linalg import norm
After your 3d plotting code, I added the following:
azim = ax.azim*pi/180
elev = ax.elev*pi/180
elev *= 1.2 # this seems to improve the outcome
a_vec = np.array([cos(azim),sin(azim),0])
normal = cos(elev)*a_vec + np.array([0,0,sin(elev)])
z_vec = np.array([0,0,1])
y_comp = z_vec - (z_vec#normal)*normal
y_comp = y_comp/norm(y_comp)
x_comp = np.cross(y_comp,normal)
proj_mat = np.vstack([x_comp,y_comp]) # build projection matrix
proj_mat = -proj_mat # account for flipped axes
points_2D = points # proj_mat.T # apply projection
plt.figure()
plt.scatter(*points_2D.T)
plt.gca().set_aspect('equal', adjustable='box')
plt.axis('off')
plt.show()
The resulting points:
I have this function for computing a rotation matrix:
import numpy as np
from scipy.spatial.transform import Rotation as R
def rotation_matrix(phi,theta,psi):
# Pure rotation in X
def Rx(phi):
return np.matrix([[ 1, 0 , 0 ],
[ 0, np.cos(phi) ,-np.sin(phi) ],
[ 0, np.sin(phi) , np.cos(phi)]])
# Pure rotation in y
def Ry(theta):
return np.matrix([[ np.cos(theta), 0, np.sin(theta)],
[ 0 , 1, 0 ],
[-np.sin(theta) , 0, np.cos(theta)]])
# Pure rotation in z
def Rz(psi):
return np.matrix([[ np.cos(psi), -np.sin(psi) , 0 ],
[ np.sin(psi) , np.cos(psi) , 0 ],
[ 0 , 0 , 1 ]])
return Rx(phi)*Ry(theta)*Rz(psi)
I know that scipy has a built-in function to compute rotation matrices, however I am being able to get the same results as the function.
I have the following example:
rotVec = np.array([np.pi/3, np.pi/4, 0]) # 60º in x-axis, 45º in y-axis
rotMat1 = rotation_matrix(*rotVec)
rotMat2 = R.from_euler('xyz', rotVec).as_matrix() # not the same result
What am I doing wrong?
OK...
It appears to be with capital letters in the rotation axis
rotVec = np.array([np.pi/3, np.pi/4, 0]) # 60º in x-axis, 45º in y-axis
rotMat1 = rotation_matrix(*rotVec)
rotMat2 = R.from_euler('XYZ', rotVec).as_matrix()
soo, for rotational matrix you need to multiplication from right to left, so this
return Rx(phi)*Ry(theta)*Rz(psi)
should be:
return Rz(psi)* Ry(theta)*Rx(phi)
instead
I have an application where I am using matplotlib to display elliptical regions on an image. To do this I'm using mpl.patches.Circle along with mp.patches.Affine2D to warp unit circles into an elliptical shape.
import numpy as np
import matplotlib as mpl
import pyplot as plt
invVR_mats = np.array([
[[ 7.80247545, 0. , 92.9254837 ],
[ -3.46026921, 10.85727882, 17.53866959],
[ 0. , 0. , 1. ]],
[[ 11.42656994, 0. , 76.86006927],
[ -3.26515651, 9.61946297, 24.79440498],
[ 0. , 0. , 1. ]],
[[ 10.40444851, 0. , 140.62428284],
[ -10.94557095, 10.59212685, 24.91024971],
[ 0. , 0. , 1. ]],])
invVR_aff2Ds = [mpl.transforms.Affine2D(invVR)
for invVR in invVR_mats]
ell_actors = [mpl.patches.Circle((0, 0), 1, transform=invVR)
for invVR in invVR_aff2Ds]
coll = mpl.collections.PatchCollection(ell_actors)
plt.figure()
ax = plt.gca()
ax.set_ylim(0, 100)
ax.set_xlim(0, 300)
ax.add_collection(coll)
There is a point in my application that the ellipses in one image are put in correspondence with ellipses from a second image using a homography matrix. So far I have been using it to warp points from image1 into image2.
I would like to get a visual idea of how these ellipses warp into image2. I can transform my affine matrices with this homography matrix, but the resulting matrix is no longer affine. (I believe it represents a general conic, either a circle, ellipse, hyperbola, or parabola)
from numpy.core.umath_tests import matrix_multiply
H = np.array([[ -0.70098, 0.12273, 5.18734],
[ 0.12444, -0.63474, 14.13995],
[ 0.00004, 0.00025, -0.64873]])
HinvVR_mats = matrix_multiply(H, invVR_mats)
print(HinvVR_mats)
#---------
np.array([
[[ -5.89405808e+00, 1.33251383e+00, -5.77990446e+01],
[ 3.16731132e+00, -6.89154916e+00, 1.45711021e+01],
[ -5.52968284e-04, 2.71431970e-03, -6.40628313e-01]],
[[ -8.41052966e+00, 1.18059669e+00, -4.56470140e+01],
[ 3.49444781e+00, -6.10585793e+00, 7.96641640e+00],
[ -3.59226330e-04, 2.40486574e-03, -6.39456996e-01]],
[[ -8.63666024e+00, 1.29997173e+00, -9.03302348e+01],
[ 8.24232128e+00, -6.72324660e+00, 1.58277039e+01],
[ -2.32021480e-03, 2.64803171e-03, -6.36877466e-01]]])
If I de-homogenize only the last column I can find the center of where the ellipse was projected, but I would like to see some shape information as well.
So far the best I've done is just de-homogenizing the last column and ignoring the values in [:, 2, 0] and [:, 2, 1]
HinvVR_mats = np.divide(HinvVR_mats , HinvVR_mats[:, None, None, 2, 2])
print(HinvVR_mats)
array([[[ 9.20043332e+00, -2.08001083e+00, 9.02224323e+01],
[ -4.94407015e+00, 1.07574845e+01, -2.27450173e+01],
[ 8.63165541e-04, -4.23696494e-03, 1.00000000e+00]],
[[ 1.31526118e+01, -1.84624877e+00, 7.13840248e+01],
[ -5.46471120e+00, 9.54850438e+00, -1.24580956e+01],
[ 5.61767769e-04, -3.76079354e-03, 1.00000000e+00]],
[[ 1.35609449e+01, -2.04116458e+00, 1.41832989e+02],
[ -1.29417694e+01, 1.05565779e+01, -2.48520394e+01],
[ 3.64311021e-03, -4.15783546e-03, 1.00000000e+00]]])
Is there a way I can tranform mpl.patches.Circle (or any other patch for that matter) using a non-affine matrix. The documentation seems to suggest it is possible, but I'm not seeing any way to go about it.
I have
I was able to solve this by looking at the tutorial posted by tcaswell
I had to create my own tranformation class though which looked like this
class HomographyTransform(mpl.transforms.Transform):
"""
References:
http://stackoverflow.com/questions/28401788/using-homogeneous-transforms-non-affine-with-matplotlib-patches?noredirect=1#comment45156353_28401788
http://matplotlib.org/users/transforms_tutorial.html
"""
input_dims = 2
output_dims = 2
is_separable = False
def __init__(self, H, axis=None, use_rmin=True):
mpl.transforms.Transform.__init__(self)
self._axis = axis
self._use_rmin = use_rmin
self.H = H
def transform_non_affine(self, input_xy):
"""
The input and output are Nx2 numpy arrays.
"""
import vtool as vt
_xys = input_xy.T
xyz = vt.add_homogenous_coordinate(_xys)
xyz_t = vt.matrix_multiply(self.H, xyz)
xy_t = vt.remove_homogenous_coordinate(xyz_t)
output_xy = xy_t.T
return output_xy
#transform_non_affine.__doc__ = mpl.transforms.Transform.transform_non_affine.__doc__
def transform_path_non_affine(self, path):
vertices = path.vertices
if len(vertices) == 2 and vertices[0, 0] == vertices[1, 0]:
return mpl.path.Path(self.transform(vertices), path.codes)
ipath = path.interpolated(path._interpolation_steps)
return mpl.path.Path(self.transform(ipath.vertices), ipath.codes)
#transform_path_non_affine.__doc__ = mpl.transforms.Transform.transform_path_non_affine.__doc__
The functions called by my own library vtool are:
def add_homogenous_coordinate(_xys):
assert _xys.shape[0] == 2
_zs = np.ones((1, _xys.shape[1]), dtype=_xys.dtype)
_xyzs = np.vstack((_xys, _zs))
return _xyzs
def remove_homogenous_coordinate(_xyzs):
assert _xyzs.shape[0] == 3
_xys = np.divide(_xyzs[0:2], _xyzs[None, 2])
return _xys
and matrix_multiply is the same matrix_multiply used earlier.
and my function to create the transform matrices currently looks like this:
def get_invVR_aff2Ds(kpts, H=None):
""" Returns matplotlib keypoint transformations (circle -> ellipse) """
#invVR_mats = ktool.get_invV_mats(kpts, with_trans=True, with_ori=True)
invVR_mats = ktool.get_invVR_mats3x3(kpts)
if H is None:
invVR_aff2Ds = [mpl.transforms.Affine2D(invVR)
for invVR in invVR_mats]
else:
# not actually affine
invVR_aff2Ds = [HomographyTransform(H.dot(invVR))
for invVR in invVR_mats]
return invVR_aff2Ds
I am trying to get the rasterized line data from a pylab plot function. My code is like so:
fitfunc = lambda p, x: p[0] + p[1] * sin(2 * pi * x / data[head[0]].size + p[2])
errfunc = lambda p, x, y: fitfunc(p, x) - y
data = np.genfromtxt(dataFileName, dtype=None, delimiter='\t', names=True)
xAxisSeries =linspace(0., data[head[0]].max(), data[head[0]].size)
p0 = [489., 1000., 9000.] # Initial guess for the parameters
p1, success = optimize.leastsq(errfunc, p0[:], args=(xAxisSeries, data[head[1]]))
time = linspace(xAxisSeries.min(), xAxisSeries.max(), 1000)
plotinfo = plot(time, fitfunc(p1, time), 'r-')
I want to get the x and y line data from plotinfo. When I use "type(plotinfo)," plotinfo is a list, but when using "print plotinfo," it is a 2dlist object.
import numpy as np
import matplotlib.pyplot as plt
N=4
x=np.linspace(0, 10, N)
y=np.cumsum(np.random.random(N) - 0.5)
line=plt.plot(x,y)[0]
path=line._path
These are the original (x,y) data points:
print(path.vertices)
# [[ 0. 0.08426592]
# [ 3.33333333 0.14204252]
# [ 6.66666667 0.41860647]
# [ 10. 0.22516175]]
Here we (linearly) interpolate to find additional points. You can increase the argument to path.interpolated to find more interpolated points between the original points.
path2=path.interpolated(2)
print(path2.vertices)
# [[ 0. 0.08426592]
# [ 1.66666667 0.11315422]
# [ 3.33333333 0.14204252]
# [ 5. 0.2803245 ]
# [ 6.66666667 0.41860647]
# [ 8.33333333 0.32188411]
# [ 10. 0.22516175]]
I want to calculate the magnetic field of a wire using biot-savart-law. Some people recommend to use numpy arrays. At first i did it with vpython and it worked. But know I want to use Matplotlib for visualisation. Therefore I need arrays right? But I stuck now.
I also posted this question to codereview, but they send me to stackoverflow.
The problem is in this line --> bfield2 = konstante*I*cross(dl, (rx,ry,rz))/r**3
import matplotlib
import numpy as np
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
from visual import *
I = 1
mu0 = 1e-7
konstante = mu0/(4*np.pi)
# wire elements; always lenght one
coord = [(0,0), (1,0), (2,0), (3,0), (4,0), (5,0), (6,0), (7,0), (8,0), (9,0), (9,1),
(9,2), (9,3), (9,4), (9,5), (9,6), (9,7), (9,8)]
# draw the wires
#for i in range(len(coord)-1):
# wire = curve(pos=(coord[i],coord[i+1]), radius=0.2)
# calculate the b-field
def bfield(x,y,z):
bfield3 = 0
# number of wire elements
for i in range(len(coord)-1):
# center of the wire element
wiremiddlex = coord[i][0]+(coord[i+1][0]-coord[i][0])/2.0
wiremiddley = coord[i][1]+(coord[i+1][1]-coord[i][1])/2.0
wiremiddlez = 0
rx = x-wiremiddlex
ry = y-wiremiddley
rz = 0
r = (rx**2+ry**2+rz**2)**0.5
dl = ((coord[i+1][0]-coord[i][0]), (coord[i+1][1]-coord[i][1]), 0)
bfield2 = konstante*I*cross(dl, (rx,ry,rz))/r**3 # i have to use numpy arrays
bfield3 += (bfield2[0]**2 + bfield2[1]**2 + bfield2[2]**2)**0.5
return bfield3
# visualize
xwidth=10
ywidth=10
delta = 1
x = np.arange(0, xwidth, delta)
y = np.arange(0, ywidth, delta)
X, Y = np.meshgrid(x, y)
slicee = 3
Z = bfield(X,Y,slicee)
plt.figure()
CS = plt.contour(X, Y, Z)
plt.clabel(CS, inline=1, fontsize=10)
plt.title('Simplest default with labels')
plt.show()
EDIT No. 7: I delete the other Edits. I don't want to confuse. The output in not correct. Please see the next Edit.
# Calculation of a magnetic field of a wire
# later I want to to it three dimensional
import matplotlib
import numpy as np
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
from pylab import *
I = 10000000000
mu0 = 1e-7
constant = mu0/(4*np.pi)
# wire elements; always lenght one
coord = [(0,0), (1,0), (2,0), (3,0), (4,0), (5,0), (6,0), (7,0), (8,0),
(9,0), (9,1), (9,2), (9,3), (9,4), (9,5), (9,6), (9,7), (9,8),
(8,8), (7,8), (6,8), (5,8)]
# calculate the b-field
def bfield(x,y,z):
b2 = np.zeros((xwidth,ywidth))
for x in range(xwidth):
for y in range(ywidth):
# number of wire elements
for i in range(21):
rx = (coord[i][0]+coord[i+1][0])/2. - x
ry = (coord[i][1]+coord[i+1][1])/2. - y
rz = z * 1.0 # = z-0
r = (rx**2+ry**2+rz**2)**0.5 # distance r between field and middle of the wire
dl = np.array([(coord[i+1][0]-coord[i][0]), (coord[i+1][1]-coord[i][1]), 0])
b = np.cross(dl, np.array([rx,ry,rz]))
e = constant*I*b/r**3
b2[y][x] += e[2] # why not x y?
return b2
xwidth = 15
ywidth = 15
delay = 1
x = np.arange(0, xwidth, delay)
y = np.arange(0, ywidth, delay)
X, Y = np.meshgrid(x, y)
slicee = 0.1
Z = bfield(X,Y,slicee)
# visualize
plt.figure()
CS = plt.contour(X, Y, Z)
plt.clabel(CS, inline=1, fontsize=10)
x1 = array([0,1,2,3,4,5,6,7,8,9,9,9,9,9,9,9,9,9,8,7,6,5])
y1 = array([0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,8,8,8,8])
plot(x1,y1)
plt.title('magnetic field')
plt.show()
Last edit:
Finally i did it without numpy.
The following version works.
# Calculation of a magnetic field of a wire
# later I want to to it three dimensional
import matplotlib
import numpy as np
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
from pylab import *
# constant
I = 10000000000
mu0 = 1e-7
constant = mu0/(4*np.pi)
# wire position
coord = [(10,10), (20,10), (20,20), (10,20), (10,25)]
coord2 = []
# devide path of the wire in parts of length one
parts = 0
for n in range(len(coord)-1):
lengthx = coord[n+1][0] - coord[n][0]
lengthy = coord[n+1][1] - coord[n][1]
length = (lengthx**2 + lengthy**2)**.5
for m in range(int(length)):
coord2.append((coord[n][0]+lengthx/length*m, coord[n][1]+lengthy/length*m))
parts += 1
# calculate the b-field
def bfield(x,y,z):
b = 0
for i in range(parts-1):
dlx = coord2[i+1][0]-coord2[i][0]
dly = coord2[i+1][1]-coord2[i][1]
dlz = 0
dl = np.array([dlx,dly,dlz])
rspace_minus_rwire_x = x - (coord2[i][0]+dlx)
rspace_minus_rwire_y = y - (coord2[i][1]+dly)
rspace_minus_rwire_z = z - 0
rspace_minus_rwire = np.array([rspace_minus_rwire_x, rspace_minus_rwire_y, rspace_minus_rwire_z])
absr = (rspace_minus_rwire_x**2 + rspace_minus_rwire_y**2 + rspace_minus_rwire_z**2)**0.5
a = constant * I * np.cross(dl, rspace_minus_rwire) / absr**3
b += (a[0]**2 + a[1]**2 + a[2]**2)**0.5
return b
xwidth = 26
ywidth = 26
z = 1
bmatrix = np.zeros((xwidth,ywidth))
for x in range(xwidth):
for y in range(ywidth):
bmatrix[x][y] = bfield(x,y,z)
# visualize
plt.figure()
x = range(xwidth)
y = range(ywidth)
z = bmatrix[x][y].T
contour(x,y,z,35)
plt.show()
Change
dl = ((coord[i+1][0]-coord[i][0]), (coord[i+1][1]-coord[i][1]), 0)
bfield2 = konstante*I*cross(dl, (rx,ry,rz))/r**3 # i have to use numpy arrays
To
dl = np.array([(coord[i+1][0]-coord[i][0]), (coord[i+1][1]-coord[i][1]), 0])
bfield2 = konstante*I*cross(dl, np.array([rx,ry,rz]))/r**3 # i have to use numpy arrays
I don't have Numpy on this machine, so this is untested. Basically, change your tuples into a numpy arrays using np.array.
You could probably also leave dl alone and change bfield2 to use np.array(dl) instead of dl.
This is not any answer tou your original question, but just a hint how to operate with numpy arrays:
In []: coord = [(0,0), (1,0), (2,0), (3,0), (4,0), (5,0), (6,0), (7,0), (8,0), (9,0), (9,1), (9,2), (9,3), (9,4), (9,5), (9,6), (9,7), (9,8)]
In []: coord= np.array(coord).T
In []: coord
Out[]:
array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8]])
In [170]: wiremiddle= (coord[:, 1:]- coord[:, :-1])/ 2.
In []: wiremiddle
Out[]:
array([[ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]])
I'll hope this will help to rewrite your code.
you do this:
bfield3 = 0
maybe you should do something like this:
bfield3 = np.zeros((len(...),len(...)))
Or maybe bfield3 is allocated already? and you just want to set all values to zero? Then do this:
bfield3[:,:] = 0
I would avoid bringing in the visual module, which it appears you are using only for the call to 'cross' and use numpy's cross in its place:
http://docs.scipy.org/doc/numpy/reference/generated/numpy.cross.html
You'll have to change a couple of lines to make dl and the second argument of cross numpy arrays
dl = np.array([(coord[i+1][0]-coord[i][0]), (coord[i+1][1]-coord[i][1]), 0])
and double check to make sure that numpy's cross is doing the same thing that visual's was.
If you insist on using the visual cross method, then it is clear from the error that you're having a type conflict which you'll have to resolve