How should I convert this from Matlab into Python:
A = sparse(row_idx, col_idx, values, len, s1 * s2);
scales = zeros(size(A, 1), 1);
scales(sub2ind([s1 s2], floor(frames(2, :)), floor(frames(1, :)))) = ...
frames(3, :);
eq = A \ scales;
My attempt is:
from scipy.sparse import csr_matrix # to replace sparse matrix
import numpy as np # to replace \ with np.linalg.lstsq
A = csr_matrix((values, (row_idx , col_idx )), shape=(length, width * height))
scales = np.zeros((A.shape[0]));
for kp in kps:
x,y = int(kp.pt[0]), int(kp.pt[1])
scales[y][x] = int(kp.size) # error
scales[y*x] = int(kp.size) # again, error:(
...
eq = np.linalg.lstsq(A, scales)
I changed variables names ( len -> length
, (s1,s2) -> (width, height)
), and accesses size
member in the keypoint class instead of frames[3]
in matlab, but these are minor changes.
What I'm not sure, is what exactly should I do with the scales
creation and index access. I seem to miss something but can't find what.
I get TypeError: 'numpy.float64' object does not support item assignment
which doesn't surprise me since scales
is 1-dim array and I shouldn't access it with [][]
.
However, changing it to scales[y*x] = int(kp.size)
raises the following: LinAlgError: 0-dimensional array given. Array must be two-dimensional
LinAlgError: 0-dimensional array given. Array must be two-dimensional
.
From what I understand, the Matlab code takes a sparse matrix, creates a column vector ( scales
) which is then populated such that any index (x,y)
from frame
(ie index of every frame (= keypoint
in my Python code)) and inserts a new value at said index (the value is size
of frame(3)
). Seems easy enough but I don't know where I'm going wrong.
Any help would be much appreciated, Thanks :)
The problem is the np.linalg.lstsqr
is a numpy function, and doesn't understand sparse matrices. Numpy function work if they delegate the job to the methods, but not if they first try to turn the sparse matrix into an array.
For a simple example:
In [345]: R = np.arange(1,6)
In [346]: M = sparse.csr_matrix(([1,1,1],([0,2,4],[0,1,2])),shape=(5,3))
In [347]: M.A
Out[347]:
array([[1, 0, 0],
[0, 0, 0],
[0, 1, 0],
[0, 0, 0],
[0, 0, 1]], dtype=int64)
In [348]: np.linalg.lstsq(M,R, rcond=None)
...
-> 1977 _assertRank2(a, b)
1978 _assertNoEmpty2d(a, b) # TODO: relax this constraint
1979 m = a.shape[0]
/usr/local/lib/python3.6/dist-packages/numpy/linalg/linalg.py in _assertRank2(*arrays)
193 if a.ndim != 2:
....
LinAlgError: 0-dimensional array given. Array must be two-dimensional
It thinks the dimension of M
is 0-d, not 2-d. That's because, a sparse matrix when wrapped in np.array
(or `asarray), produces a 0d object array:
In [351]: np.array(M)
Out[351]:
array(<5x3 sparse matrix of type '<class 'numpy.int64'>'
with 3 stored elements in Compressed Sparse Row format>, dtype=object)
In [352]: _.shape
Out[352]: ()
The correct way is to turn the sparse matrix into a dense with its own method:
In [354]: np.linalg.lstsq(M.A,R, rcond=None)
....
Out[354]: (array([1., 3., 5.]), array([20.]), 3, array([1., 1., 1.]))
In MATLAB sparse matrices are integrated into the main code. In numpy
, they are in a separate scipy.sparse
package. A sparse matrix is not subclass of np.ndarray
.
There is a sparse linear algebra subpackage:
In [355]: from scipy.sparse import linalg as spla
In [356]: spla.lsqr(M, R)
Out[356]:
(array([1., 3., 5.]),
2,
1,
4.47213595499958,
4.47213595499958,
1.0,
1.0,
4.082652109348718e-16,
5.916079783099617,
array([0., 0., 0.]))
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.