I can't get same point with homography matrix reverse transform - numpy

I get invert of homography matrix
self.inv_homography = np.linalg.inv(self.homography)
and my trasnform function
def doTransform(x, y, homography):
p = np.ndarray(shape=(3, 1), dtype=float, order='F')
p[0, 0] = x
p[1, 0] = y
p[2, 0] = 1
res = np.dot(homography, p)
return res
but third row is not same with first row, there is some pixel slip
ref coords :(768, 512, 1024, 768)
ref to wa coords: 569.5178327464915 185.9395922739289 790.8947327112375 448.7356913249636
wa to ref coords: 767.149391928569 510.19931575332294 1022.283053230326 764.3653307505839
how do I fix this slip ?

I think that you have hardcoded the z coordinate might be the problem. If the z coordinate does not transform to exactly 1, you will introduce an error. This code returns the expected output:
import numpy as np
def transform(x, y, z, homography):
p = np.array([x,y,z]).reshape(3,1)
return np.dot(homography, p)
hom = np.array([1.2,3.1, 4.0, 2.4, 5.4, 3.2, 1.1, 3.0, 1.2]).reshape(3,3)
x, y, z = 2.3, 1.7, 1
inv_hom = np.linalg.inv(hom)
x_wa = transform(x, y, z, hom)[0, 0]
y_wa = transform(x, y, z, hom)[1, 0]
z_wa = transform(x, y, z, hom)[2, 0]
print(transform(x_wa, y_wa, z_wa, inv_hom))
>>[[2.3]
[1.7]
[1. ]]

Related

Numpy.polyfit Not Returning Polynomial

I am trying to create a python program in which the user inputs a set of data and the program spits out an output in which it creates a graph with a line/polynomial which best fits the data.
This is the code:
from matplotlib import pyplot as plt
import numpy as np
x = []
y = []
x_num = 0
while True:
sequence = int(input("Input 1 number in the sequence, type 9040321 to stop"))
if sequence == 9040321:
poly = np.polyfit(x, y, deg=2, rcond=None, full=False, w=None, cov=False)
plt.plot(poly)
plt.scatter(x, y, c="blue", label="data")
plt.legend()
plt.show()
break
else:
y.append(sequence)
x.append(x_num)
x_num += 1
I used the polynomial where I inputed 1, 2, 4, 8 each in separate inputs. MatPlotLib graphed it properly, however, for the degree of 2, the output was the following image:
This is clearly not correct, however I am unsure what the problem is. I think it has something to do with the degree, however when I change the degree to 3, it still does not fit. I am looking for a graph like y=sqrt(x) to go over each of the points and when that is not possible, create the line that fits the best.
Edit: I added a print(poly) feature and for the selected input above, it gives [0.75 0.05 1.05]. I do not know what to make of this.
Approximation by a second degree polynomial
np.polyfit gives the coefficients of a polynomial close to the given points. To plot the polynomial as a smooth curve with matplotlib, you need to calculate a lot of x,y pairs. Using np.linspace(start, stop, numsteps) for the xs, numpy's vectorization allows calculating all the corresponding ys in one go. E.g. ys = a * x**2 + b * x + c.
from matplotlib import pyplot as plt
import numpy as np
x = [0, 1, 2, 3, 4, 5, 6]
y = [1, 2, 4, 8, 16, 32, 64]
plt.scatter(x, y, color='crimson', label='given points')
poly = np.polyfit(x, y, deg=2, rcond=None, full=False, w=None, cov=False)
xs = np.linspace(min(x), max(x), 100)
ys = poly[0] * xs ** 2 + poly[1] * xs + poly[2]
plt.plot(xs, ys, color='dodgerblue', label=f'$({poly[0]:.2f})x^2+({poly[1]:.2f})x + ({poly[2]:.2f})$')
plt.legend()
plt.show()
Higher degree approximating polynomials
Given N points, an N-1 degree polynomial can pass exactly through each of them. Here is an example with 7 points and polynomials of up to degree 6,
from matplotlib import pyplot as plt
import numpy as np
x = [0, 1, 2, 3, 4, 5, 6]
y = [1, 2, 4, 8, 16, 32, 64]
plt.scatter(x, y, color='black', zorder=3, label='given points')
for degree in range(0, len(x)):
poly = np.polyfit(x, y, deg=degree, rcond=None, full=False, w=None, cov=False)
xs = np.linspace(min(x) - 0.5, max(x) + 0.5, 100)
ys = sum(poly_i * xs**i for i, poly_i in enumerate(poly[::-1]))
plt.plot(xs, ys, label=f'degree {degree}')
plt.legend()
plt.show()
Another example
x = [0, 1, 2, 3, 4]
y = [1, 1, 6, 5, 5]
import numpy as np
import matplotlib.pyplot as plt
x = [1, 2, 3, 4]
y = [1, 2, 4, 8]
coeffs = np.polyfit(x, y, 2)
print(coeffs)
poly = np.poly1d(coeffs)
print(poly)
x_cont = np.linspace(0, 4, 81)
y_cont = poly(x_cont)
plt.scatter(x, y)
plt.plot(x_cont, y_cont)
plt.grid(1)
plt.show()
Executing the code, you have the graph above and this is printed in the terminal:
[ 0.75 -1.45 1.75]
2
0.75 x - 1.45 x + 1.75
It seems to me that you had false expectations about the output of polyfit.

How to override mpl_toolkits.mplot3d.Axes3D.draw() method?

I'm doing a small project which requires to resolve a bug in matplotlib in order to fix zorders of some ax.patches and ax.collections. More exactly, ax.patches are symbols rotatable in space and ax.collections are sides of ax.voxels (so text must be placed on them). I know so far, that a bug is hidden in draw method of mpl_toolkits.mplot3d.Axes3D: zorder are recalculated each time I move my diagram in an undesired way. So I decided to change definition of draw method in these lines:
for i, col in enumerate(
sorted(self.collections,
key=lambda col: col.do_3d_projection(renderer),
reverse=True)):
#col.zorder = zorder_offset + i #comment this line
col.zorder = col.stable_zorder + i #add this extra line
for i, patch in enumerate(
sorted(self.patches,
key=lambda patch: patch.do_3d_projection(renderer),
reverse=True)):
#patch.zorder = zorder_offset + i #comment this line
patch.zorder = patch.stable_zorder + i #add this extra line
It's assumed that every object of ax.collection and ax.patch has a stable_attribute which is assigned manually in my project. So every time I run my project, I must be sure that mpl_toolkits.mplot3d.Axes3D.draw method is changed manually (outside my project). How to avoid this change and override this method in any way inside my project?
This is MWE of my project:
import matplotlib.pyplot as plt
import numpy as np
#from mpl_toolkits.mplot3d import Axes3D
import mpl_toolkits.mplot3d.art3d as art3d
from matplotlib.text import TextPath
from matplotlib.transforms import Affine2D
from matplotlib.patches import PathPatch
class VisualArray:
def __init__(self, arr, fig=None, ax=None):
if len(arr.shape) == 1:
arr = arr[None,None,:]
elif len(arr.shape) == 2:
arr = arr[None,:,:]
elif len(arr.shape) > 3:
raise NotImplementedError('More than 3 dimensions is not supported')
self.arr = arr
if fig is None:
self.fig = plt.figure()
else:
self.fig = fig
if ax is None:
self.ax = self.fig.gca(projection='3d')
else:
self.ax = ax
self.ax.azim, self.ax.elev = -120, 30
self.colors = None
def text3d(self, xyz, s, zdir="z", zorder=1, size=None, angle=0, usetex=False, **kwargs):
d = {'-x': np.array([[-1.0, 0.0, 0], [0.0, 1.0, 0.0], [0, 0.0, -1]]),
'-y': np.array([[0.0, 1.0, 0], [-1.0, 0.0, 0.0], [0, 0.0, 1]]),
'-z': np.array([[1.0, 0.0, 0], [0.0, -1.0, 0.0], [0, 0.0, -1]])}
x, y, z = xyz
if "y" in zdir:
x, y, z = x, z, y
elif "x" in zdir:
x, y, z = y, z, x
elif "z" in zdir:
x, y, z = x, y, z
text_path = TextPath((-0.5, -0.5), s, size=size, usetex=usetex)
aff = Affine2D()
trans = aff.rotate(angle)
# apply additional rotation of text_paths if side is dark
if '-' in zdir:
trans._mtx = np.dot(d[zdir], trans._mtx)
trans = trans.translate(x, y)
p = PathPatch(trans.transform_path(text_path), **kwargs)
self.ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=z, zdir=zdir)
p.stable_zorder = zorder
return p
def on_rotation(self, event):
vrot_idx = [self.ax.elev > 0, True].index(True)
v_zorders = 10000 * np.array([(1, -1), (-1, 1)])[vrot_idx]
for side, zorder in zip((self.side1, self.side4), v_zorders):
for patch in side:
patch.stable_zorder = zorder
hrot_idx = [self.ax.azim < -90, self.ax.azim < 0, self.ax.azim < 90, True].index(True)
h_zorders = 10000 * np.array([(1, 1, -1, -1), (-1, 1, 1, -1),
(-1, -1, 1, 1), (1, -1, -1, 1)])[hrot_idx]
sides = (self.side3, self.side2, self.side6, self.side5)
for side, zorder in zip(sides, h_zorders):
for patch in side:
patch.stable_zorder = zorder
def voxelize(self):
shape = self.arr.shape[::-1]
x, y, z = np.indices(shape)
arr = (x < shape[0]) & (y < shape[1]) & (z < shape[2])
self.ax.voxels(arr, facecolors=self.colors, edgecolor='k')
for col in self.ax.collections:
col.stable_zorder = col.zorder
def labelize(self):
self.fig.canvas.mpl_connect('motion_notify_event', self.on_rotation)
s = self.arr.shape
self.side1, self.side2, self.side3, self.side4, self.side5, self.side6 = [], [], [], [], [], []
# labelling surfaces of side1 and side4
surf = np.indices((s[2], s[1])).T[::-1].reshape(-1, 2) + 0.5
surf_pos1 = np.insert(surf, 2, self.arr.shape[0], axis=1)
surf_pos2 = np.insert(surf, 2, 0, axis=1)
labels1 = (self.arr[0]).flatten()
labels2 = (self.arr[-1]).flatten()
for xyz, label in zip(surf_pos1, [f'${n}$' for n in labels1]):
t = self.text3d(xyz, label, zdir="z", zorder=10000, size=1, usetex=True, ec="none", fc="k")
self.side1.append(t)
for xyz, label in zip(surf_pos2, [f'${n}$' for n in labels2]):
t = self.text3d(xyz, label, zdir="-z", zorder=-10000, size=1, usetex=True, ec="none", fc="k")
self.side4.append(t)
# labelling surfaces of side2 and side5
surf = np.indices((s[2], s[0])).T[::-1].reshape(-1, 2) + 0.5
surf_pos1 = np.insert(surf, 1, 0, axis=1)
surf = np.indices((s[0], s[2])).T[::-1].reshape(-1, 2) + 0.5
surf_pos2 = np.insert(surf, 1, self.arr.shape[1], axis=1)
labels1 = (self.arr[:, -1]).flatten()
labels2 = (self.arr[::-1, 0].T[::-1]).flatten()
for xyz, label in zip(surf_pos1, [f'${n}$' for n in labels1]):
t = self.text3d(xyz, label, zdir="y", zorder=10000, size=1, usetex=True, ec="none", fc="k")
self.side2.append(t)
for xyz, label in zip(surf_pos2, [f'${n}$' for n in labels2]):
t = self.text3d(xyz, label, zdir="-y", zorder=-10000, size=1, usetex=True, ec="none", fc="k")
self.side5.append(t)
# labelling surfaces of side3 and side6
surf = np.indices((s[1], s[0])).T[::-1].reshape(-1, 2) + 0.5
surf_pos1 = np.insert(surf, 0, self.arr.shape[2], axis=1)
surf_pos2 = np.insert(surf, 0, 0, axis=1)
labels1 = (self.arr[:, ::-1, -1]).flatten()
labels2 = (self.arr[:, ::-1, 0]).flatten()
for xyz, label in zip(surf_pos1, [f'${n}$' for n in labels1]):
t = self.text3d(xyz, label, zdir="x", zorder=-10000, size=1, usetex=True, ec="none", fc="k")
self.side6.append(t)
for xyz, label in zip(surf_pos2, [f'${n}$' for n in labels2]):
t = self.text3d(xyz, label, zdir="-x", zorder=10000, size=1, usetex=True, ec="none", fc="k")
self.side3.append(t)
def vizualize(self):
self.voxelize()
self.labelize()
plt.axis('off')
arr = np.arange(60).reshape((2,6,5))
va = VisualArray(arr)
va.vizualize()
plt.show()
This is an output I get after external change of ...\mpl_toolkits\mplot3d\axes3d.py file:
This is an output (an unwanted one) I get if no change is done:
What you want to achieve is called Monkey Patching.
It has its downsides and has to be used with some care (there is plenty of information available under this keyword). But one option could look something like this:
from matplotlib import artist
from mpl_toolkits.mplot3d import Axes3D
# Create a new draw function
#artist.allow_rasterization
def draw(self, renderer):
# Your version
# ...
# Add Axes3D explicitly to super() calls
super(Axes3D, self).draw(renderer)
# Overwrite the old draw function
Axes3D.draw = draw
# The rest of your code
# ...
Caveats here are to import artist for the decorator and the explicit call super(Axes3D, self).method() instead of just using super().method().
Depending on your use case and to stay compatible with the rest of your code you could also save the original draw function and use the custom only temporarily:
def draw_custom():
...
draw_org = Axes3D.draw
Axes3D.draw = draw_custom
# Do custom stuff
Axes3D.draw = draw_org
# Do normal stuff

Several figures with subplots using a combination list in Matplotlib

I want to make a streamplot of a vectorial field which contains some free constants which I would like to change. So I've made combinations of these constants and I can sucessfully plot the stream plots one by one with this:
Y, X = np.mgrid[-1:10:200j, 0:10:200j]
tau_x = [0.01, 0.1, 1., 10.]
tau_y = [0.01, 0.1, 1., 10.]
alpha = [0.01, 0.1, 1., 10.]
r = [0.1, 0.01, 0.001]
K = [0.1, 0.5, 1.0, 1.5]
combinations_list = list(itertools.product(tau_x,tau_y,alpha,r,K))
for a in combinations_list:
(tau_x, tau_y, alpha, r, K) = a
Fx = (1/tau_x) * ( (-8/3)*(2*r-alpha)*(X-1) + K*X )
Fy = (2/(tau_y*X**(3/2))) * ( -2*(Y-1) + 3*Y*(X-1)/X + K*X*Y )
fig, ax = plt.subplots()
strm = ax.streamplot(X, Y, Fx, Fy, linewidth=0.5)
plt.show()
Now, because we are talking of a very large number of combinations, I would like to make a figure with subplots (say 9 each figure but it could be more) which would reduce a lot the number of figures.
Note: I am interested in seeing one figure each time and that's why plt.show() is inside the loop to avoid opening all figures at once.
EDIT: Following ImportanceOfBeingErnest sugestion I changed the code to
Y, X = np.mgrid[-1:10:200j, 0:10:200j]
tau_x = [0.01, 0.1, 1., 10.]
tau_y = [0.01, 0.1, 1., 10.]
alpha = [0.01, 0.1, 1., 10.]
r = [0.1, 0.01, 0.001]
K = [0.1, 0.5, 1.0, 1.5]
combinations_list = list(itertools.product(tau_x,tau_y,alpha,r,K))
length = len(combinations_list)
N = 9 #number of subplots per figure
for i in range(0,100):
subset = combinations_list[9*i:9*i+9]
fig = plt.figure()
j = 1
for a in subset:
(tau_x, tau_y, alpha, r, K) = a
Fx = (1/tau_x) * ( (-8/3)*(2*r-alpha)*(X-1) + K*X )
Fy = (2/(tau_y*X**(3/2))) * ( -2*(Y-1) + 3*Y*(X-1)/X + K*X*Y )
ax = fig.add_subplot(3,3,j)
ax.streamplot(X, Y, Fx, Fy, linewidth=0.5)
++j
plt.show()
but it's only plotting the first one of each subset and in a weird way with colors in the vectors.
You are not updating j correctly. ++j doesn't update the value of j. Your code will work fine if you replace ++j by j += 1 or j = j+1. Both are equivalent.
for i in range(0,100):
subset = combinations_list[9*i:9*i+9]
fig = plt.figure()
j = 1
for a in subset:
(tau_x, tau_y, alpha, r, K) = a
Fx = (1/tau_x) * ( (-8/3)*(2*r-alpha)*(X-1) + K*X )
Fy = (2/(tau_y*X**(3/2))) * ( -2*(Y-1) + 3*Y*(X-1)/X + K*X*Y )
ax = fig.add_subplot(3,3,j)
ax.streamplot(X, Y, Fx, Fy, linewidth=0.5)
j += 1 # <--- change here

Numpy incorrect dot product when filling

I am having some trouble with numpy dot product - the product of a rotation matrix & a vector. Please see code. The two lines should give the same result! Where I am storing the result of the calculation should not affect the calculation. Y should be the same as y1 and y2.
import numpy
rotMat = numpy.array([[-0.27514947, 0.40168313, 0.87346633], [ 0.87346633, -0.27514947, 0.40168313], [ 0.40168313, 0.87346633, -0.27514947]])
print "Rotation matrix:"
print rotMat
x = [1, 0, 1, 1, 1, 0]
X = numpy.array(x)
X.shape = (2, 3)
Y = numpy.array(6*[0])
Y.shape = (2, 3)
print "X", X
print "Y initialised:", Y
Y[0, :] = numpy.dot(rotMat, X[0, :])
Y[1, :] = numpy.dot(rotMat, X[1, :])
print "Filling Y initialised, Y=", Y
print "not filling Y initialised:"
print "y1", numpy.dot(rotMat, X[0, :])
print "y2", numpy.dot(rotMat, X[1, :])
Which gives result:
Rotation matrix: [[-0.27514947 0.40168313 0.87346633]
[ 0.87346633 -0.27514947 0.40168313]
[ 0.40168313 0.87346633 -0.27514947]]
X [[1 0 1]
[1 1 0]]
Y initialised: [[0 0 0]
[0 0 0]]
Filling Y initialised, Y= [[0 1 0]
[0 0 1]]
not filling Y initialised:
y1 [ 0.59831686 1.27514946 0.12653366]
y2 [ 0.12653366 0.59831686 1.27514946]
I am using Python 2.7.11, with Numpy 1.10.1
You are filling in Y which is of type int and therefore converts all values placed into it to int. When initializing Y, initialize as float.
Y = numpy.array(6*[0], float)
per #hpaulj's comment:
Y = numpy.zeros((6,))
will also work because the default dtype is float

How to plot hyperplane SVM in python?

My first question so please bear with me :)
I use the Shogun toolbox to work with SVM in Python. I just experiment first to get a better understanding of SVM's. I wrote something in Python with some data points to linearly separate. I use the LibSVM()
X = np.array([[2.0, 2.0, 1.0, 1.0],
[1.0, -1.0, 1.0, -1.0]])
Y = np.array([[4.0, 5.0, 5.0, 4.0],
[1.0, 1.0, -1.0, -1.0]])
After training the SVM with the given data I can retrieve its bias(get_bias()), the support vectors(get_support_vectors()) and other properties. What I can't get done is plotting the line/hyperplane. I know the equation for the hyperplane is y=wx + b but how to write/plot this down to see it in my figure.
for a complete example
import numpy as np
import matplotlib.pyplot as plt
def __intersect(rect, line):
l = []
xmin,xmax,ymin,ymax = rect
a,b,c = line
assert a!=0 or b!=0
if a == 0:
y = -c/b
if y<=ymax and y>=ymin:
l.append((xmin, y))
l.append((xmax, y))
return l
if b == 0:
x = -c/a
if x<=xmax and x>=xmin:
l.append((x, ymin))
l.append((x, ymax))
return l
k = -a/b
m = -c/b
for x in (xmin, xmax):
y = k*x+m
if y<=ymax and y>= ymin:
l.append((x,y))
k = -b/a
m = -c/a
for y in (ymin, ymax):
x = k*y+m
if x<xmax and x> xmin:
l.append((x,y))
return l
def plotline(coef, *args, **kwargs):
'''plot line: y=a*x+b or a*x+b*y+c=0'''
coef = np.float64(coef[:])
assert len(coef)==2 or len(coef)==3
if len(coef) == 2:
a, b, c = coef[0], -1., coef[1]
elif len(coef) == 3:
a, b, c = coef
ax = plt.gca()
limits = ax.axis()
points = __intersect(limits, (a,b,c))
if len(points) == 2:
pts = np.array(points)
ax.plot(pts[:,0], pts[:,1], *args, **kwargs)
ax.axis(limits)
def circle_out(x, y, s=20, *args, **kwargs):
'''Circle out points with size 's' and edgecolors'''
ax = plt.gca()
if 'edgecolors' not in kwargs:
kwargs['edgecolors'] = 'g'
ax.scatter(x, y, s, facecolors='none', *args, **kwargs)
def plotSVM(coef, support_vectors=None):
coef1 = coef[:]
coef2 = coef[:]
coef1[2] += 1
coef2[2] -= 1
plotline(coef, 'b', lw=2)
plotline(coef1, 'b', ls='dashed')
plotline(coef2, 'b', ls='dashed')
if support_vectors != None:
circle_out(support_vectors[:,0], support_vectors[:,1], s=100)
from pylab import *
X = array([[2.0, 2.0, 1.0, 1.0],
[1.0, -1.0, 1.0, -1.0]])
Y = array([[4.0, 5.0, 5.0, 4.0],
[1.0, 1.0, -1.0, -1.0]])
data = hstack((X,Y)).T
label = hstack((zeros(X.shape[1]), ones(Y.shape[1])))
from sklearn.svm import SVC
clf = SVC(kernel='linear')
clf.fit(data, label)
coef = [clf.coef_[0,0], clf.coef_[0,1], clf.intercept_[0]]
scatter(data[:,0], data[:,1], c=label)
plotSVM(coef, clf.support_vectors_)
show()
from pylab import *
def __intersect(rect, line):
l = []
xmin,xmax,ymin,ymax = rect
a,b,c = line
assert a!=0 or b!=0
if a == 0:
y = -c/b
if y<=ymax and y>=ymin:
l.append((xmin, y))
l.append((xmax, y))
return l
if b == 0:
x = -c/a
if x<=xmax and x>=xmin:
l.append((x, ymin))
l.append((x, ymax))
return l
k = -a/b
m = -c/b
for x in (xmin, xmax):
y = k*x+m
if y<=ymax and y>= ymin:
l.append((x,y))
k = -b/a
m = -c/a
for y in (ymin, ymax):
x = k*y+m
if x<=xmax and y>= xmin and len(l) < 2:
l.append((x,y))
return l
def plotLine(coef, *args, **kwargs):
'''plot line: y=a*x+b or a*x+b*y+c=0'''
coef = float64(coef[:])
assert len(coef)==2 or len(coef)==3
if len(coef) == 2:
a, b, c = coef[0], -1., coef[1]
elif len(coef) == 3:
a, b, c = coef
ax = gca()
limits = ax.axis()
print limits
points = __intersect(limits, (a,b,c))
print points
if len(points) == 2:
pts = array(points)
ax.plot(pts[:,0], pts[:,1], *args, **kwargs)
ax.axis(limits)