Related
Let's suppose we have these two matrices
epsilon = np.asmatrix([
[1,2],
[-1,2],
[0,2]
])
and this one:
step_weights = np.asmatrix(np.random.normal(0, 0.5, (np.shape(epsilon)))
I want to populate/update step_weights matrix based on epsilon values, that is:
if epsilon[i,j] > 0:
step_weights[i,j] = np.minimum(1.2 * step_weights[i,j], 50)
elif epsilon[i,j] < 0:
step_weights[i,j] = np.maximum(0.5 * step_weights[i,j], 10**-6)
This is what I have done:
import numpy as np
def update_steps(self, epsilon):
for (i, j), epsilon_ij in np.ndenumerate(epsilon):
if epsilon_ij > 0:
step_weights[i, j] = np.minimum(1.2 * step_weights[i,j], 50)
elif epsilon_ij < 0:
step_weights[i, j] =np.maximum(0.5 * step_weights[i,j], 10**-6)
and that's working fine.
My question is: is there a more efficient/cleaner way to do it, avoiding the for loop? For example exploiting matrix calculus or linear algebra?
Use bool indices array:
>>> np.random.seed(0)
>>> step_weights = np.asmatrix(np.random.normal(0, 0.5, np.shape(epsilon)))
>>> step_weights
matrix([[ 0.88202617, 0.2000786 ],
[ 0.48936899, 1.1204466 ],
[ 0.933779 , -0.48863894]])
>>> mask = epsilon > 0
>>> step_weights[mask] = np.minimum(step_weights.A[mask] * 1.2, 50)
>>> mask = epsilon < 0
>>> step_weights[mask] = np.maximum(step_weights.A[mask] * 0.5, 10 ** -6)
>>> step_weights
matrix([[ 1.05843141, 0.24009433],
[ 0.2446845 , 1.34453592],
[ 0.933779 , -0.58636673]])
Note: The matrix class is not recommended now, and will be discarded in the future. It should use a regular multidimensional array instead. The current multidimensional array already supports many matrix operations (such as using the # operator for matrix multiplication).
I asked a question here with the details: https://math.stackexchange.com/questions/4381785/possibly-speed-up-matrix-multiplications
In short, I am trying to create a P x N matrix, X, with typical element: \sum_{j,k;j,k \neq i} w_{jp} A_{jk} Y_{kp}, where w is P x N, A is N x N and Y is P x N. See the link above for a markup version of that formula.
I'm providing a mwe here to see how I can correct the code (the calculations seem correct, just incomplete see below) and more importantly speed this up however possible:
w = np.array([[2,1],[3,7]])
A = np.array([[2,1],[9,-1]])
Y = np.array([[6,2],[11,8]])
N=w.shape[1]
P=w.shape[0]
X = np.zeros((P, N))
for p in range(P) :
for i in range(N-1):
for j in range(N-1):
X[p,i] = np.delete(w,i,1)[i,p]*np.delete(np.delete(A,i,0),i,1)[i,j]*np.delete(Y.T,i,0)[j,p]
The output looks like:
array([[ -2. , 0. ],
[-56. , 0.]])
If we set (i,p) = to the (1,1) element of X_{ip}, the value can be understood using the formula provided above:
sum_{j,k;j,k \neq i} w_{j1} A_{jk} Y_{k1} = w_12 A_22 Y_12 = 1 * -1 * 2 = -2 as it is in the output.
the (1,2) element of X_{ip} should be:
sum_{j,k;j,k \neq i} w_{j2} A_{jk} Y_{k2} = w_22 A_22 Y_22 = 7 * -1 * 8 = -56 as it is in the output.
But I am not getting the correct answer for the final column of X because my range is to (N-1) not N because I received an IndexError out of bounds when it is N. More importantly, here N=P=2, but I have large N and P and the code, as is, takes a very long time to run. Any suggestions would be greatly appreciated.
Since the delete functions depend only on i, I factored them out, and reordered the loops. Also corrected the w1 index order.
In [274]: w = np.array([[2,1],[3,7]])
...: A = np.array([[2,1],[9,-1]])
...: Y = np.array([[6,2],[11,8]])
...: N=w.shape[1]
...: P=w.shape[0]
...: X = np.zeros((P, N))
...: for i in range(N-1):
...: print('i',i)
...: w1 = np.delete(w,i,1)
...: a1 = np.delete(np.delete(A,i,0),i,1)
...: y1 = np.delete(Y.T,i,0)
...: print(w1.shape, a1.shape, y1.shape)
...: print(w1#a1#y1)
...: print(np.einsum('ij,jk,li->i',w1,a1,y1))
...: for p in range(P):
...: for j in range(N-1):
...: X[p,i] = w1[p,i]*a1*y1[j,p]
...:
i 0
(2, 1) (1, 1) (1, 2)
[[ -2 -8]
[-14 -56]]
[ -2 -56]
In [275]: X
Out[275]:
array([[ -2., 0.],
[-56., 0.]])
Your [-2,-56] are the diagonal of w1#a1#y1, or the einsum. The 0's are from the original np.zeros because i is only on range(1).
This should be faster because the delete is not repeated unnecessarily. np.delete is still relatively expensive, but I haven't tried to figure out exactly what you are doing.
Didn't your question initially have (2,3) and (3,3) arrays? That, or something a bit larger, may be more general and informative.
edit
I think this is closer to the math expressions:
def foo(w,A,Y):
P, N = w.shape
X = np.zeros((P, N))
for i in range(N):
#w1 = np.delete(w,i,1)
a1 = np.delete(A,i,1)
y1 = np.delete(Y.T,i,0)
print(w1.shape, a1.shape, y1.shape)
for p in range(P) :
for j in range(N-1):
X[p,i] += w[p,i]*a1[i,j]*y1[j,p]
return X
we can get rid of the j loop with:
def foo1(w,A,Y):
P, N = w.shape
X = np.zeros((P, N))
for i in range(N):
a1 = np.delete(A,i,1)
y1 = np.delete(Y.T,i,0)
print(w1.shape, a1.shape, y1.shape)
for p in range(P) :
X[p,i] = w[p,i]*np.dot(a1[i,:],y1[:,p])
return X
with
...: w3 = np.array([[2,1,0],[3,7,0.5]])
...: A3 = np.array([[2,1,0],[9,0,8],[1,2,5]])
...: Y3 = np.array([[6,2,-1],[11,8,-7]])
...: w2 = np.array([[2,1],[3,7]])
...: A2 = np.array([[2,1],[9,-1]])
...: Y2 = np.array([[6,2],[11,8]])
both produce
In [372]: foo(w2,A2,Y2)
(2, 1) (2, 1) (1, 2)
...
Out[372]:
array([[ 4., 54.],
[ 24., 693.]])
In [373]: foo(w3,A3,Y3)
(2, 1) (3, 2) (2, 2)
...
Out[373]:
array([[ 4. , 46. , 0. ],
[ 24. , 301. , 13.5]])
and after more fiddling:
def foo4(w,A,Y):
P, N = w.shape
X = np.zeros((P, N))
for i in range(N):
a1 = np.delete(A,i,1)
y1 = np.delete(Y.T,i,0)
X[:,i] = np.einsum('j,jp->p',a1[i,:],y1)
# X[:,i] = a1[i,:]#y1
return X*w
I suspect it is possible to do w*(A#Y.T) and then subtract an array that involves A[:,i] and Y[:,i], but haven't figured out that array.
I'm trying to calculate 3D point from 2 Images. However I'm not sure whether my Implementation/thought process is correct, because I don't really know which of my calculated 3D points/Rotation & Translation matrix is the correct one.
Things which I can provide or have done:
got the intrinsic parameters of both cameras k1 and k2
calculated the fundamental matrix with cv2.findFundamentalMat (fairly sure that it is correct, because i checked it with the equation x'Fx = 0)
k1 = np.array([[512, 0, 512.],
[ 0, 512, 384],
[ 0, 0, 1]]).reshape(3,3)
k2 =np.array([[512, 0, 512.],
[ 0, 512, 384],
[ 0, 0, 1]]).reshape(3,3)
fMatrix = np.array([[ 2.13503670e-06, -1.09093289e-05, 1.34791051e-03],
[ 1.15140270e-05, -8.93292052e-07, -8.31221024e-03],
[-4.24200928e-03, 7.99815714e-03, 1.00000000e+00]]).reshape(3,3)
p1 = np.array([752, 573, 1])
p2 = np.array([701, 542, 1])
print(p2.T.dot(fMatrix).dot(p2))
-0.015196065125415714
calculated the essential matrix E = K2.T * F *K1 (Not sure if this is correct)
extracted the rotation and translation Matrix R, R2 and Sb, S2b.
constructed the 4 possible extrinsic matricies M1,M2, M3, M4, with [R|t]
essentialMatrix = k2.T.dot(fMatrix).dot(k1)
U, S, V = np.linalg.svd(essentialMatrix)
newEssentialMatrix = U.dot(np.diag([1,1,0])).dot(V.T)
U, S, V = np.linalg.svd(newEssentialMatrix)
W = np.array([[0, -1, 0], [1, 0, 0],[0, 0, 1]]).reshape(3,3)
Z = np.array([[0,1,0],[-1,0,0],[0,0,0]]).reshape(3,3)
Sb = U.dot(Z).dot(U.T) # [t]x
R = U.dot(W).dot(V.T) # R
S2b = U.dot(Z.T).dot(U.T) # [t]x
R2 = U.dot(W.T).dot(V.T) # R
t1 = np.array([[Sb[2][1]],[Sb[0][2]],[Sb[1][0]]])
t2 = np.array([[S2b[2][1]],[S2b[0][2]],[S2b[1][0]]])
# M = [U W.T V.T | t] = # M = [U W.T V.T | t] = [R | t]
M1 = np.append(R, t1, axis=1)
M2 = np.append(R, t2, axis=1)
M3 = np.append(R2, t1, axis=1)
M4 = np.append(R2, t2, axis=1)
trying to verify which extrinic/projection Matrix I need to use. In other words I'm creating for camera1 the projection matrix P1 = k1*[I|0].
And for camera2 4 different projection Matricies P2 = k2*M1, P2 = k2*M2, P2 = k2*M3, P2 = k2*M4
Testing\calculating with a the corresponding points p1 and p2 and cv2.triangulatePoints()
origin = np.array([[1,0,0,0],[0,1,0,0],[0,0,1,0]]).reshape(3,4)
projectionM1 = k1.dot(origin)
projectionM2 = k2.dot(M1)
p3D = cv2.triangulatePoints(projectionM1,projectionM2,p1[:2],p2[:2])
print("M1")
print(p3D/p3D[3])
print("-----")
projectionM2 = k2.dot(M2)
p3D = cv2.triangulatePoints(projectionM1,projectionM2,p1[:2],p2[:2])
print("M2")
print(p3D/p3D[3])
print("-----")
projectionM2 = k2.dot(M3)
p3D = cv2.triangulatePoints(projectionM1,projectionM2,p1[:2],p2[:2])
print("M3")
print(p3D/p3D[3])
print("-----")
projectionM2 = k2.dot(M4)
p3D = cv2.triangulatePoints(projectionM1,projectionM2,p1[:2],p2[:2])
print("M4")
print(p3D/p3D[3])
So here are my results:
M1
[[-0.19115383]
[-0.12595232]
[-0.51133412]
[ 1. ]]
-----
M2
[[0.19115383]
[0.12595232]
[0.51133412]
[1. ]]
-----
M3
[[-0.6098932 ]
[-0.25755958]
[-1.29386456]
[ 1. ]]
-----
M4
[[0.6098932 ]
[0.25755958]
[1.29386456]
[1. ]]
So my question is which one is the correct one?
My guess it's either M2 or M4 since they only contain positive Z values, but then again, I have no idea how the coordinate system of camera1 is defined, maybe M1 or M3 might be correct.
In this picture you can see the perspective of camera1 with the point which should be calculated.
If anything else is missing or wrong pls don't hesitate to tell me. Thank you very much for your help.
I am trying to calculate the rational basis for null space of a matrix. There is quite a few posts about how nullspace is calculated using Python/numpy but they calculate it for orthonormal basis and not for the rational basis. Here is how this is done in MATLAB:
ns = null(A,'r')
When I look at the source code, I saw that it is calculated like this:
function Z = null(A,how)
[m,n] = size(A)
%...
[R,pivcol] = rref(A);
r = length(pivcol);
nopiv = 1:n;
nopiv(pivcol) = [];
Z = zeros(n,n-r,class(A));
if n > r
Z(nopiv,:) = eye(n-r,n-r,class(A));
if r > 0
Z(pivcol,:) = -R(1:r,nopiv);
end
end
%...
function [A,jb] = rref(A,tol)
%...
[m,n] = size(A);
[num, den] = rat(A);
rats = isequal(A,num./den);
if (nargin < 2), tol = max(m,n)*eps(class(A))*norm(A,'inf'); end
i = 1;
j = 1;
jb = [];
while (i <= m) && (j <= n)
[p,k] = max(abs(A(i:m,j))); k = k+i-1;
if (p <= tol)
A(i:m,j) = zeros(m-i+1,1);
j = j + 1;
else
jb = [jb j];
A([i k],j:n) = A([k i],j:n);
A(i,j:n) = A(i,j:n)/A(i,j);
for k = [1:i-1 i+1:m]
A(k,j:n) = A(k,j:n) - A(k,j)*A(i,j:n);
end
i = i + 1;
j = j + 1;
end
end
if rats
[num,den] = rat(A);
A=num./den;
end
Here rref is the reduced row echelon form. Thus by looking at this source code I tried to recreate it with following code:
def fract(x):
return Fraction(x)
def dnm(x):
return x.denominator
def nmr(x):
return x.numerator
fractionize = np.vectorize(fract)
denom = np.vectorize(dnm)
numer = np.vectorize(nmr)
def rref(A,tol=1e-12):
m,n = A.shape
Ar = A.copy()
i,j = 0,0
jb = []
while i < m and j < n:
p = np.max(np.abs(Ar[i:m,j]))
k = np.where(np.abs(Ar[i:m,j]) == p)[0][0]
k = k + i - 1
if (p <= tol):
Ar[i:m,j] = np.zeros((m-i,))
j += 1
else:
jb.append(j)
Ar[(i,k),j:n] = Ar[(k,i),j:n]
Ar[i,j:n] = Ar[i,j:n]/Ar[i,j]
for k in np.hstack((np.arange(0,i),np.arange(i+1,m))):
Ar[k,j:n] = Ar[k,j:n] - Ar[k,j]*A[i,j:n]
i += 1
j += 1
print(len(jb))
return Ar,jb
def null(A,tol=1e-5):
m,n = A.shape
R,pivcol = rref(A,tol=tol)
print(pivcol)
r = len(pivcol)
nopiv = np.ones(n).astype(bool)
nopiv[pivcol] = np.zeros(r).astype(bool)
Z = np.zeros((n,n-r))
if n > r:
Z[nopiv,:] = np.eye(n-r,n-r)
if r > 0:
Z[pivcol,:] = -R[:r,nopiv]
return Z
There are two things that I don't know. First, I do not know how to add the ratios part into rref function. Second, I am not sure if my indexes are correct since MATLAB's indices are start from 1 and indexing includes the last element when you choose for a slice (i.e. 1:5 includes both 1 and 5).
SymPy does that out of the box, although (being symbolic, and in Python) not as fast as NumPy or Scipy would. An example with floating point input:
from sympy import Matrix, S, nsimplify
M = Matrix([[2.75, -1.2, 0, 3.2], [8.29, -4.8, 7, 0.01]])
print(nsimplify(M, rational=True).nullspace())
Prints a list of two column vectors, represented as one-column matrices.
[Matrix([
[ 700/271],
[9625/1626],
[ 1],
[ 0]]), Matrix([
[ -1279/271],
[-17667/2168],
[ 0],
[ 1]])]
The use of nsimplify was necessary to convert floats to the rationals that they were meant to represent. If the matrix is created as a matrix of integer/rational entries, that would not be necessary.
M = Matrix([[1, 2, 3, 5, 9], [9, -3, 0, 2, 4], [S(3)/2, 0, -1, 2, 0]])
print(M.nullspace())
[Matrix([
[ -74/69],
[-176/69],
[ 9/23],
[ 1],
[ 0]]), Matrix([
[ -70/69],
[-118/69],
[ -35/23],
[ 0],
[ 1]])]
Here, S(3)/2 is used instead of `3/2 in order to force SymPy object creation instead of floating point evaluation.
I have come across this matrix multiplication problem where M is some non-singular 3x3 matrix with known values (i.e M = sympy.Matrix([[1, 0, 0],[0, 2, 0],[0, 0, 3]])) C is a 3x3 matrix to be determined and N is of the following form:
1. The 1st and 3rdrow of N are the same as C (e.g N.row(0)[i] = C.row(0)[i] for 0<=i<=2)
2. The elements in the 2nd row of N are the sum of the corresponding column in M (e.g N.row(1)[1] = sum(M.col(1)))
After searching the web for a way to express this problem as a system of equations I've found nothing. I've been trying to solve this using symbolic matrices and by or by solving three different systems of the form Ax=b each one made of a row from C multiplied by M with b as a column from N such that A = M.T, x = (C.row(i)).T and b = N.
Solving it symbolically resulted in a ridiculous expression that cannot be even be comprehended and I was unable to get a numeric solution from it.
My latest attempt follow:
import sympy as sp
def func(mat=matrix([[1, 1, 1], [0, 2, 2], [1, 4, 5]])):
c11, c12, c13, c21, c22, c23, c31, c32, c33 = sp.symbols('c11, c12, c13, c21, c22, c23, c31, c32, c33')
M = mat.T
b1 = sp.Matrix([[x, y, z]]).T
b2 = sp.Matrix([[sum(M.col(0)), sum(M.col(1)), sum(M.col(2))]]).T
b3 = sp.Matrix([[a, b, c]]).T
M1 = M.col_insert(3, b1)
M2 = M.col_insert(3, b2)
M3 = M.col_insert(3, b3)
C1 = sp.linsolve(M1, (x, y, z))
C2 = sp.linsolve(M2, (x, y, z))
C3 = sp.linsolve(M3, (a, b, c))
return C1, C2, C3
Calling this yields the following:
>>> func()
({(x + y - z, -x/2 + 2*y - 3*z/2, -y + z)}, {(-3, -17/2, 6)}, {(a + b - c, -a/2 + 2*b - 3*c/2, -b + c)})
I won't claim I understand your code, but the solution is actually easy to guess: The first and third rows of C and N must either be left eigenvectors of M with eigenvalue 1 which will in the general case not exist or must be zero. The middle row requirement is solved by C being all ones and since M is nonsingular that's the only solution.
Let's use good old numpy to numerically check this:
import numpy as np
M = np.random.random((3, 3))
M
# array([[ 0.39632944, 0.82429087, 0.88705214],
# [ 0.39092656, 0.63228762, 0.54931835],
# [ 0.76935833, 0.40833527, 0.46202912]])
C = np.outer((0,1,0),(1,1,1))
C
# array([[0, 0, 0]
# [1, 1, 1],
# [0, 0, 0]])
N = np.outer((0,1,0),M.sum(0))
N
# array([[ 0. , 0. , 0. ],
# [ 1.55661432, 1.86491377, 1.89839961],
# [ 0. , 0. , 0. ]])
np.allclose(C # M , N)
# True