How to extrapolate points of a regular grid in python - python

I have a numpy array of points and want to extend my point (x, y and z) in a defined direction. This is my array:
coordinates=np.array([[1., 19., 4.], [2., 19., 4.5], [1., 20., 4.],[2., 20., 4.5], [3., 20., 4.]])
These points are on two y grids: 19 and 20. I want to extend my points in these grid lines. First grid has two point. x and y coordinates of extrapolated points are fixed. y equals the grid value (19 or 20) and x equals one unit more that the last point of the grid. For first grid the new x and y of two points are (3.,19.) and (4.,19.) and z should be calculated as:
z of last point + (z of last point - z of one point before the last)/2
In case of having just one point in the grid, I copy the value of that point. In the first grid, z value of first extrapolated point is :
4.5 + (4.5-4)/2 = 4.75
and for the second point is
4.75 + (4.75-4.5)/2 = 4.875
I want to do the same for the next grid (y=20) to finally add all four point to the existing array:
all_points=np.array([[1.,19.,4.], [1.,20.,4.], [2.,19.,4.5], [2.,20.,4.5], [3.,20.,4.],\
[3.,19.,4.75], [4.,19.,4.875], [4.,20,3.75], [5.,20, 3.625]])
I tried the following but firstly I have no idea how to generate z value dynamically. At the moment it is calculating the same z values for the new two generated points of each grid. Another issue is that my code is not effiecient and I believe there are much faster ways to do it:
nums, counts=np.unique(coordinates[:,1],return_counts=True) # gives the y grids
new_y=nums
cum=np.cumsum(counts)-1
new_x=[]
for i in cum:
new_x.append (coordinates[i,0])
new_x=np.array(new_x)
new_x_y=[]
for m, n in zip (new_x, new_y):
new_x_y.append([m,n])
new_x_y.append([m+1,n])
new_x_y=np.array(new_x_y)
z_difference=[]
for i in cum:
z_difference.append((coordinates[i,-1]-coordinates[i-1,-1])/2)# to find the difference of last two points of each grid
new_z=[]
for i in range (len(cum)-1):
new_z.append (coordinates[cum[i],-1]+z_difference)#to find the new z of each extrapolated point
new_z=np.array(new_z)
all_z=np.repeat (new_z, repeats=new_z.shape[1], axis=1)
final_arr=np.hstack ([new_x_y, all_z.T])
In advance, I do appreciate any help to solve my problem in python.

Related

cv2 triangulatePoints always returns same Z value

I am trying to get 3D points using cv2.triangulatePoints but it always returns almost same Z value. My output looks like this: As it seen, all points are in almost same Z value. There is no depth.
Here is my triangulation:
def triangulate(self, proj_mat1, pts0, pts1):
proj_mat0 = np.zeros((3,4))
proj_mat0[:, :3] = np.eye(3)
pts0, pts1 = self.normalize(pts0), self.normalize(pts1)
pts4d = cv2.triangulatePoints(proj_mat0, proj_mat1, pts0.T, pts1.T).T
pts4d /= pts4d[:, 3:]
out = np.delete(pts4d, 3, 1)
print(out)
return out
Here is my projection matrix calculation:
def getP(self, rmat, tvec):
P = np.concatenate([rmat, tvec.reshape(3, 1)], axis = 1)
return P
Here is the part that I get rmat, tvec and call triangulation:
E, mask = cv2.findEssentialMat(np.array(aa), np.array(bb), self.K)
_, R, t, mask = cv2.recoverPose(E, np.array(aa), np.array(bb), self.K)
proj_mat1 = self.getP(R, t)
out = self.triangulate(proj_mat1, np.array(aa, dtype = np.float32), np.array(bb, dtype = np.float32))
My camera matrix:
array([[787.8113353 , 0. , 318.49905794],
[ 0. , 786.9638204 , 245.98673477],
[ 0. , 0. , 1. ]])
My projection matrix 1:
array([[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.]])
Explanations:
aa and bb are matched points from 2 frames.
self.K is my camera matrix
rotation and translation matrices are extracted from Essential matrix
Essential matrix calculated from matched keypoints. It changes every frame.
Projection matrix 2 changes every frame.
Output after changing first projection matrix (I switched from matplotlib to pangolin as 3D visualization tool):
Output after using P1 and P2 that I mentioned in comments:
Where is my mistake? Please let me know if any further information needed. I will update my question.
Unfortunately I don't have the possibility to double-check directly but my gut feeling is that the issues you are facing are essentially due to the choice of your first projection matrix
I did some research and I found this great paper with both theory and practice. Despite differing a little bit from your approach, there is a thing that is worth saying
If you check carefully, the first projection matrix is exactly the camera matrix with an additional last column equal to zero. In fact, the rotation matrix for the first camera reduces to the identity matrix and the corresponding translation vector is a null vector, so using this general formula:
P = KT
where P is the projection matrix, K the camera matrix and T the matrix obtained by the rotation matrix R flanked by the translation vector t according to:
T = [R|t]
then you will get:
Coming back to your case, first of all I would suggest to change your first projection matrix as just said
Also, I understand that you are planned to work with something different at every frame but if after the suggested change the things still don't match then in your shoes I'd start working with just 2 images [I think you implicitly did already to create the correspondence between aa and bb], calculating first the matrices with your algorithm and then checking with the ones obtained following the article above
In this way you would be able to understand/debug which matrices are creating you troubles
Thank you so much for all the effort #Antonino. My webcams were pretty bad. After changing every part of my code and making many trials I decided to change my webcams and bought good webcams. It worked :D Here is the result:

How to append all subdivided polygon coordinates?

let A be set of coordinate (e.g. array([[ 10., 110.],[200., 90.],[210., 0.], [-10., 10.],[ 10., 110.]]).
If subdivision(coordinate) is a division code, giving two outcomes - subdivisionR, subdivisionL, then subdivision(A) gives array([[ 10., 110.],[110.0, 99.47],[110.0, 4.54],[-10., 10.],[ 10., 110.]]), array([[110.0, 99.47],[200.,90.],[210., 0.],[110.0, 4.54],[110.0, 99.47]]).
Since I wanted to divide the polygon until all subdivided polygons reach the area closest to 200 and get all subdivided coordinates, I used following code;
n=1
t=0
r=0
k=A
while area(subdivision(k)[n-1])>200:
for i in range(t,n):
k.append(subdivision(k[i])[0])
k.append(subdivision(k[i])[1])
t=2**r
r=r+1
n=2**r
However, I get warning - 'numpy.ndarray' object has no attribute 'append'.
How can I fix this?
The syntax for appending to a numpy array is different to say that of a python list. You want to use:
numpy.append(array, value, axis)
So something like:
numpy.append(k, subdivision(k[i]), axis = 0)
Note axis is optional and would default to 1. 'value' is a numpy array, not a discrete value.

how to incorporate two types in one loop in python

If subdivision(coordinate) is a division code using bounding box theory, giving two outcomes - subdivisionR, subdivisionL;
A = array([[ 10., 110.],[200., 90.],[210., 0.], [-10., 10.],[ 10., 110.]])
subdivision(A) = array([[ 10., 110.],[110.0, 99.47],[110.0, 4.54],[-10., 10.],[ 10., 110.]]),
array([[110.0, 99.47],[200.,90.],[210., 0.],[110.0, 4.54],[110.0, 99.47]])
area(A) = 19550.0
subdivision(A)
Since I want to repeat subdivision() for all subdivided polygons until each area reaches near 200, I made below code. However, tuple index for area() is a single integer and tuple index for subdivision() is array of coordinates. If I want to append all subdivided polygons until each area reaches 200 in a list of coordinates, how can I fix the code below?
n=1
t=0
r=0
k=A
while area(subdivision(k)[n-1])>200:
for i in range(t,n):
np.append(k[0],subdivision(k)[0])[i]
np.append(k[1],subdivision(k)[1])[i]
t=2**r
r=r+1
n=2**r

Python move point by matrix and then draw orbit

I know how to draw points moved by matrix, like this below
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
x=np.random.randn(2) #2*1 matrix
A=np.random.randn(2,2) #2*2 matrix
print ('the content of x:\n{}\n the content of A:\n{}'.format(x,A))
def action(pt,n):
record=[pt]
for i in range(n):
pt= A#pt
record=np.vstack([record,pt])
plt.scatter(record[:,1],record[:,1])
action(x,100)
the function "action" will draw something like a line, but I want to move points by matrix and then draw it like an orbit
SHORT ANSWER:
plt.scatter(record[:,1],record[:,1]) will feed same values in both x & y dimensions & hence will always return a line. Replace it by:
X,Y = np.hsplit(record,2)
plt.scatter(X,Y)
LONG ANSWER:
The main cause behind plot coming out as a line is that you are generating the plot using 2 constants (although randomly generated). I will illustrate using below example:
>>> c
array([[ 1., 2.],
[ 2., 4.]])
>>> d
array([ 3., 4.])
>>> d#c
array([ 11., 22.])
>>> d#c#c
array([ 55., 110.])
>>> d#c#c#c
array([ 275., 550.])
Notice how all the recursive operation is only multiplying the initial co-ordinate by 5 at each stage.
How to get a non-linear plot??
Utilize the variable 'i' which we are calling for loop operation by giving it a power of 2(parabola) or more.
Use random numbers populated in the 2 matrices greater than 1. Otherwise all the operations either increase the magnitude in -ve or if b/w (-1,1) the magnitude decreases.
Use mathematical functions to introduce non-linearity. Eg:
pt = pt + np.sin(pt)
Reflect if using 2 random matrices & looping over them is the only way to achieve the curve. If this activity is independent from your bigger programme etc, then probably try different approach by using mathematical functions which generate the curve you like.

Python - euclidean distance of all pairs of subsequences of given length from given array

Lets say I have an numpy array [5,7,2,3,4,6] and I choose length of subsequence to be 3.
I want to get euclidean distances of such subsequences.
Possible subsequences are:
[5,7,2]
[7,2,3]
[2,3,4]
[3,4,6]
Distance between subsequence 1. and 3. would be calculated as (5-2)^2 + (7-3)^2 + (2-4)^2. I want to do this for all pairs of subsequences.
Is there a way to avoid loops?
My real array is quite long so the solution should be memory efficient as well.
EDIT>
To elaborate more: I have a timeseries of size 10^5 to 10^8 elements
Time series is growing. each time new point is added I need to take the L newest points and find a closest match to these points in the past points of the dataset. (But I want all value of distances not only to find the closest match)
Repeating the whole calculation is unnecessary. The distance of "previously newest L points" can be updated and only modified by substracting point of age L+1 and adding point of age 0 (the newest).
E.g. lets say size of time series is currently 100 and L=10. I calculate distances of subsequence A[90:100] to all previous subsequences. When 101st point arrives I can reuse the distances and only update them by adding a squares of distances of 101st point from the time series and substracting squares of 90th point.
EDIT 2>
Thanks a lot for the ideas, looks like magic. I have one more idea that might be efficient especially for the online time series when new elements of tiem series are being added.
I am thinking about this way of updating the distances. To calculate distances of first subsequence of length L=4 to the matrix we need to have first 4 columns of the following matrix (the triangles on top and bottom could be ommited). Then the distances would be squared and summed as shown with colors.
To obtain the distances of second subsequence of L=4 we can actually reuse the previously calculated distances and substract first column (squared) from them and add 4th column(squared). For L=4 it might not make sense but for L=100 it might. One distance has to be calculated from scratch. (Actually 2 have to be calculated if the Time series grows in size).
This way I can keep in memory just the distances of one subsequence and update them to obtain distances of next subsequence.
Do you think this would be efficient with numpy? Is there an easy way to implement it?
Assuming A as the input array and L as the length of subsequence, you can get a sliding 2D array version of A with broadcasting and then use pdist from scipy.spatial.distance, like so -
# Get sliding 2D array version of input array
A2D = A[np.arange(A.size-L+1)[:,None] + np.arange(L)]
# Get pairwise distances with pdist
pairwise_dist = pdist(A2D,'sqeuclidean')
Please note that if you meant euclidean distances, you need to replace 'sqeuclidean' with 'euclidean' or just leave out that argument as it's the default one.
Sample run -
In [209]: # Inputs
...: A = np.array([5,7,2,3,4,6])
...: L = 3
...:
In [210]: A2D = A[np.arange(A.size-L+1)[:,None] + np.arange(L)]
In [211]: A2D
Out[211]:
array([[5, 7, 2],
[7, 2, 3],
[2, 3, 4],
[3, 4, 6]])
In [212]: pdist(A2D,'sqeuclidean')
Out[212]: array([ 30., 29., 29., 27., 29., 6.])
# [1] element (= 29) is (5-2)^2 + (7-3)^2 + (2-4)^2
To get the correspinding IDs, you could use np.triu_indices like so -
idx1,idx2 = np.triu_indices(A2D.shape[0],1)
And, finally show IDs alongside the distances like so -
ID_dist = np.column_stack((idx1,idx2,pairwise_dist))
Sample run -
In [201]: idx1,idx2
Out[201]: (array([0, 0, 0, 1, 1, 2]), array([1, 2, 3, 2, 3, 3]))
In [202]: np.column_stack((idx1,idx2,pairwise_dist))
Out[202]:
array([[ 0., 1., 30.],
[ 0., 2., 29.], # This was your (5-2)^2 + (7-3)^2 + (2-4)^2
[ 0., 3., 29.],
[ 1., 2., 27.],
[ 1., 3., 29.],
[ 2., 3., 6.]])
For cases, when you are dealing millions of elements in A and L is in hundreds, it might be a better idea to perform computations for each pairwise differentiations of such sub-sequences in a loop, like so -
# Get pairiwise IDs
idx1,idx2 = np.triu_indices(A.size-L+1,1)
# Store range array for L as would be used frequently in loop
R = np.arange(L)
# Initialize output array and start computing
pairwise_dist = np.empty(len(idx1))
for i in range(len(idx1)):
pairwise_dist[i] = ((A[R+idx2[i]] - A[R+idx1[i]])**2).sum()
You can also use np.einsum to get us the squared summations at each iteration, like so -
diffs = A[R+idx2[i]] - A[R+idx1[i]]
pairwise_dist[i] = np.einsum('i,i->',diffs,diffs)

Categories