OpenCV Python findHomography srcPoint input not compatible - python

I am trying to find the transformation of an loaded image to a plane detected off of a marker so that I can transform it to appear perpendicular to the marker plane. I am having trouble putting inputs to cv2.findHomography. Please help to change the input format to this function
Here is my code that is causing issue:
muffinImg = cv2.imread('muffin.jpg',0)
muffinCoords = np.zeros((4,2), np.float32)
muffheight, muffwidth = muffinImg.shape
muffinCoords[0] = (0,muffwidth)
muffinCoords[1] = (muffwidth,muffheight)
muffinCoords[2] = (0,muffheight)
muffinCoords[3] = (0,0)
found, corners = cv2.findChessboardCorners(frameLeft, (5,4),None)
if (found):
corners2 = cv2.cornerSubPix(grayframeLeft,corners,(11,11),(-1,-1),criteria)
q = [(0,0)]*4
q[0] = corners[0][0]
q[1] = corners[3][0]
q[2] = corners[19][0]
q[3] = corners[16][0]
retvalHomography, mask = cv2.findHomography(q, muffinCoords, cv2.RANSAC)
cv2.warpPerspective(muffinImg, retvalHomography, (400, 500), muffinImg, cv2.INTER_NEAREST, cv2.BORDER_CONSTANT, 0)
I am getting this error on the cv2.findHomography line: srcPoints is not a numpy array, neither a scalar
Here is what Microsoft Visual object inspection tool gives me
q:
muffin:
EDIT: I have some additional info about the inputs but I don't see how they are different, maybe I am just making a noob mistake: from here http://opencv-users.1802565.n2.nabble.com/Anyone-have-a-Python2-example-using-estimateRigidTransform-td7322817.html.
One quick answer which might help (depending on what you are trying to do) is that the cv2.findHomography function does work from python. It returns 3x3 rather than 2x3 matrix but you will find coefficients in the bottom row close to either zero or one if the transform really is rigid so slice them off.
a=np.array([0,0,1,0,0,1,1,1],np.float32).reshape(-1,2) #small square
b=a*2 #scale x2
b+=0.5 #translate across and down
H,matches=cv2.findHomography(a,b,cv2.RANSAC)

Your variable q is not a numpy array. Try converting it to an array before passing it to cv2.findHomography().
I don't know the cv2 API well enough to be sure, but I think you should change this:
q = [(0,0)]*4
q[0] = corners[0][0]
q[1] = corners[3][0]
q[2] = corners[19][0]
q[3] = corners[16][0]
to something like this:
q = np.zeros((4,2), dtype=np.float32)
q[0] = corners[0][0]
q[1] = corners[3][0]
q[2] = corners[19][0]
q[3] = corners[16][0]
After a brief look at the cv2 docs, I think corners is an array with shape n x 2, so those assignments don't make much sense to me. corners[0][0] (which could be written more succinctly as corner[0,0]) is the first coordinate of the first corner, i.e. corner[0][0] is a scalar. Why are you assigning only the first coordinate to q[0]? What is the intent of that code? I suspect it could be simplified to:
q = corners[[0, 3, 19, 16]]
For example:
In [12]: corners = np.arange(40).reshape(20,2).astype(np.float32)
In [13]: corners
Out[13]:
array([[ 0., 1.],
[ 2., 3.],
[ 4., 5.],
[ 6., 7.],
[ 8., 9.],
[ 10., 11.],
[ 12., 13.],
[ 14., 15.],
[ 16., 17.],
[ 18., 19.],
[ 20., 21.],
[ 22., 23.],
[ 24., 25.],
[ 26., 27.],
[ 28., 29.],
[ 30., 31.],
[ 32., 33.],
[ 34., 35.],
[ 36., 37.],
[ 38., 39.]], dtype=float32)
In [14]: q = corners[[0, 3, 19, 16]]
In [15]: q
Out[15]:
array([[ 0., 1.],
[ 6., 7.],
[ 38., 39.],
[ 32., 33.]], dtype=float32)

Related

How do I to average irregularly spaced x & y coordinate tensor into a grid with a specific cell size?

I have an algorithm that generates a tensor of irregularly spaced x and y coordinates (ex: torch.size([3600, 2])), and I need to average the points into grid cells of a specific size (ex: 8 by 8). The resulting grid needs to be either an array or tensor.
It's not required, but I would also like to be able to determine if any of the resulting cells have less than a specified number of points in them.
For example I can graph the tensor using matplotlib's plt.scatter, and it looks like this:
In the above example, 100,000 points exist but the number of points can sometimes be in the tens of millions.
I've tried using histogram approaches, and most of them use a specific number of cells vs a specific cell size. Matplotlib can seemingly do it in a graph, but that doesn't help me get an array or tensor.
Edit:
This code might work, if it can be made to work properly.
def grid_torch(x_coords, y_coords, grid_size=(8,8), x_extent=(0., 1.), y_extent=(0., 1.)):
x_coords = ((x_coords - x_extent[0]) / (x_extent[1] - x_extent[0])) * grid_size[0]
y_coords = ((y_coords - y_extent[0]) / (y_extent[1] - y_extent[0])) * grid_size[1]
x_list = []
for x in range(grid_size[0]):
x = torch.ones_like(x_coords) * x
y_list = []
for y in range(grid_size[1]):
y = torch.ones_like(y_coords) * y
in_bounds_x = torch.logical_and(x <= x_coords, x_coords <= x + 1)
in_bounds_y = torch.logical_and(y <= y_coords, y_coords <= y + 1)
in_bounds = torch.logical_and(in_bounds_x, in_bounds_y)
in_bounds_indices = torch.where(in_bounds)
print(in_bounds_indices)
y_list.append(in_bounds_indices)
x_list.append(torch.stack(y_list))
return torch.stack(x_list)
out = grid_torch(xy_tensor[:,0], xy_tensor[:,1])
print(out.shape)
def create_grid(grid_layout, activ, grid_size=(8,8), min_density=8):
cells = []
for x in range(grid_size[0]):
for y in range(grid_size[1]):
indices = grid_layout[x, y]
if len(indices) > min_density:
average_activation = torch.mean(activ[indices])
cells.append((average_activation, x, y))
print(average_activation, x, y)
return torch.stack(cells)
grid_test = create_grid(out, xy_tensor, grid_size=(8,8))
I think this code would give you a good starting point.
def grid_torch(x_coords, y_coords, grid_size=(8,8), x_extent=(0., 1.), y_extent=(0., 1.)):
# This part converts coordinates to bin numbers (like (2,5), (7,7) etc)
x_bin = (((x_coords - x_extent[0]) / (x_extent[1] - x_extent[0])) * grid_size[0]).int()
y_bin = (((y_coords - y_extent[0]) / (y_extent[1] - y_extent[0])) * grid_size[1]).int()
counts = torch.zeros(grid_size)
means = torch.zeros(list(grid_size) + [2])
for x in range(grid_size[0]):
for y in range(grid_size[1]):
# these tensors are 1 where (x_bin == x and y_bin == y), 0 else where
x_where = 1 * (x_bin == x)
y_where = 1 * (y_bin == y)
p_where = (x_where * y_where)
cnt = p_where.sum()
counts[x, y] = cnt
# we'll average both x and y coords seperately.
# you can embed min_density logic here.
if cnt > 0:
means[x, y, 0] = (x_coords * p_where).sum() / p_where.sum()
means[x, y, 1] = (y_coords * p_where).sum() / p_where.sum()
return counts, means
# Generate sample points
points = torch.tensor(np.concatenate([
np.random.normal(loc=0.2, scale=0.1, size=(1000, 2)),
np.random.normal(loc=0.6, scale=0.1, size=(1000, 2))
]).clip(0,1)).float()
# plt.scatter(points[:,0], points[:,1])
# plt.grid()
counts, means = grid_torch(points[:,0], points[:,1])
counts
>>>
tensor([[ 47., 114., 75., 10., 0., 0., 0., 0.],
[102., 204., 141., 27., 0., 0., 0., 0.],
[ 60., 101., 74., 16., 7., 4., 1., 0.],
[ 5., 17., 9., 23., 72., 51., 10., 0.],
[ 1., 1., 4., 54., 186., 141., 28., 3.],
[ 0., 0., 3., 47., 154., 117., 14., 0.],
[ 0., 0., 0., 9., 37., 24., 4., 0.],
[ 0., 0., 0., 2., 0., 1., 0., 0.]])

Keeping gradients while rearranging data in a tensor, with pytorch

I have a scheme where I store a matrix with zeros on the diagonals as a vector. I want to later on optimize over that vector, so I require gradient tracking.
My challenge is to reshape between the two.
I want - for domain specific reasons - keep the order of data in the matrix so that transposed elements of the W matrix next to each other in the vector form.
The size of the W matrix is subject to change, so I start with enumering items in the top-left part of the matrix, and continue outwards.
I have come up with two ways to do this. See code snippet.
import torch
import torch.sparse
w = torch.tensor([10,11,12,13,14,15],requires_grad=True,dtype=torch.float)
i = torch.LongTensor([
[0, 1,0],
[1, 0,1],
[0, 2,2],
[2, 0,3],
[1, 2,4],
[2, 1,5],
])
v = torch.FloatTensor([1, 1, 1 ,1,1,1 ])
reshaper = torch.sparse.FloatTensor(i.t(), v, torch.Size([3,3,6])).to_dense()
W_mat_with_reshaper = reshaper # w
W_mat_directly = torch.tensor([
[0, w[0], w[2],],
[w[1], 0, w[4],],
[w[3], w[5], 0,],
])
print(W_mat_with_reshaper)
print(W_mat_directly)
and this gives output
tensor([[ 0., 10., 12.],
[11., 0., 14.],
[13., 15., 0.]], grad_fn=<UnsafeViewBackward>)
tensor([[ 0., 10., 12.],
[11., 0., 14.],
[13., 15., 0.]])
As you can see, the direct way to reshape the vector into a matrix does not have a grad function, but the multiply-with-a-reshaper-tensor does. Creating the reshaper-tensor seems like it will be a hassle, but on the other hand, manually writing the matrix for is also infeasible.
Is there a way to do arbitrary reshapes in pytorch that keeps grack of gradients?
Instead of constructing W_mat_directly from the elements of w, try assigning w into W:
W_mat_directly = torch.zeros((3, 3), dtype=w.dtype)
W_mat_directly[(0, 0, 1, 1, 2, 2), (1, 2, 0, 2, 0, 1)] = w
You'll get
tensor([[ 0., 10., 11.],
[12., 0., 13.],
[14., 15., 0.]], grad_fn=<IndexPutBackward>)
You can use the facts that:
slicing preserves gradients while indexing doesn't;
concatenation preserves gradients while tensor creation doesn't.
tensor0 = torch.zeros(1)
W_mat_directly = torch.concatenate(
[tensor0, w[0:1], w[1:2], w[1:2], tensor0, w[4:5], w[3:4], w[5:6], tensor0]
).reshape(3,3)
With this approach you can apply arbitrary functions to the elements of the initial tensor w.

Why are full stops appearing in the printed statement of an array?

I am currently learning how to use python and jupyter notebook. I want to create my own dataset. The code for that is as follows (which was taken from this website: How to create my own datasets using in scikit-learn?):
import numpy as np
import csv
from sklearn.datasets.base import Bunch
def load_movies_dataset():
with open('Documents/movies_dataset.csv') as csv_file:
data_file = csv.reader(csv_file)
temp = next(data_file)
n_samples = int(temp[0])
n_features = int(temp[1])
data = np.empty((n_samples, n_features))
target = np.empty((n_samples,), dtype=np.int)
for i, sample in enumerate(data_file):
data[i] = np.asarray(sample[:-1], dtype=np.int)
target[i] = np.asarray(sample[-1], dtype=np.int)
return Bunch(data=data, target=target)
This is the csv file that I'm using:
"6","2","numKicks","numKisses"
"3","104","0"
"2","100","0"
"1","81","0"
"101","10","1"
"99","5","1"
"98","2","1"
This example determines if a movie is a romance(0) or action(1) based on the number of kicks and number of kisses.
This is the code I'm using to test the creation of the dataset:
md = load_movies_dataset()
X = md.data
y = md.target
X
And this is the output:
array([[ 3., 104.],
[ 2., 100.],
[ 1., 81.],
[101., 10.],
[ 99., 5.],
[ 98., 2.]])
My question is, why are there full stops in the array display?
They are decimal points. It is an array of floats:
>>> x
array([[ 3., 104.],
[ 2., 100.],
[ 1., 81.],
[101., 10.],
[ 99., 5.],
[ 98., 2.]])
>>> y
array([0, 0, 0, 1, 1, 1])
>>> x.dtype
dtype('float64')
>>>
The default data-type for numpy.empty is numpy.float64.

How to copy list of tuples to EXISTING numpy array in shared memory

I have a structured numpy array in shared memory, that's only one "layer" of a higher dimensional array.
And I have a list of tuples whose values I want to copy to this (sub) array.
I've found how to make a new numpy structured array out of a list of tuples.
But I can't find out how to convert this list of tuples to an EXISTING numpy (sub) array.
The sizes already match, of course.
Of course I can copy elementwise in a Python for-loop, but this seems awfully inefficient. I'd like the looping to be done in the C++ that underlies numpy.
Explanation: The reason my array is in shared memory is that I use this as a common datatructure with a C++ process, guarded by mutex semaphores.
My list of tuples looks like:
[(25141156064, 5.3647, 221.32287846), (25141157138, 5.3647, 73.70348602), (25141155120, 5.3646, 27.77147382), (25141160388, 5.3643, 55.5000024), (25141160943, 5.3636, 166.49511561), (25141154452, 5.3578, 92), (25141154824, 5.3539, 37.22246003), (25141155187, 5.3504, 37.22246003), (25141157611, 5.34, 915), (25141157598, 5.3329, 1047.32982582), (25140831246, 5.3053, 915), (25141165780, 5.2915, 2000), (25141165781, 5.2512, 2000), (25140818946, 5.2483, 915), (25138992274, 5.1688, 458), (25121724934, 5.1542, 458), (25121034787, 4.8993, 3.47518861), (24402133353, 2.35, 341), (24859679064, 0.8, 1931.25), (24046377720, 0.5, 100), (25141166091, 5.3783, -650.51242432), (25141165779, 5.3784, -1794.28608778), (25141157632, 5.3814, -2000), (25141157601, 5.3836, -2000), (25141164181, 5.3846, -499.65636506), (25141164476, 5.4025, -91), (25141157766, 5.4026, -634.80061236), (25141153364, 5.4034, -2000), (25141107806, 5.4035, -1601.88882309), (25141157694, 5.4136, -1047.32982582), (25141148874, 5.4278, -266), (25141078136, 5.4279, -48.4864096), (25141165317, 5.4283, -2000), (25141097109, 5.4284, -914), (25141110492, 5.4344, -774.75614589), (25141110970, 5.4502, -928.32048159), (25141166045, 5.4527, -2000), (25141166041, 5.493, -2000), (25139832350, 5.5, -10.2273)]
My numpy array has elements that are defined as follows:
Id = np.uint64
Price = np.float64
Amount = np.float64
Quotation = np.dtype ([
('id', Id),
('price', Price),
('amount', Amount),
])
self._contents = np.ndarray (
shape = (
maxNrOfMarkets,
maxNrOfItemKindsPerMarket,
maxNrOfQuotationsPerItemKind
)
dtype = Quotation,
buffer = self.sharedMemory.buf,
offset = offset
)
Same way you'd do it if the array wasn't backed by shared memory. Just make sure you synchronize access properly.
your_array[:] = your_list
Say you have an array of shape (list_length, tuples_length).
Is this what you're looking for?
my_sub_array[:] = my_list_of_tuples
As an example :
my_sub_array = np.zeros((5, 3))
my_list_of_tuples = [(i, i + 1, i + 2) for i in range(5)]
my_sub_array
array([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
my_sub_array[:] = my_list_of_tuples
my_sub_array
array([[0., 1., 2.],
[1., 2., 3.],
[2., 3., 4.],
[3., 4., 5.],
[4., 5., 6.]])

numpy concatenate not appending new array to empty multidimensional array

I bet I am doing something very simple wrong. I want to start with an empty 2D numpy array and append arrays to it (with dimensions 1 row by 4 columns).
open_cost_mat_train = np.matrix([])
for i in xrange(10):
open_cost_mat = np.array([i,0,0,0])
open_cost_mat_train = np.vstack([open_cost_mat_train,open_cost_mat])
my error trace is:
File "/Users/me/anaconda/lib/python2.7/site-packages/numpy/core/shape_base.py", line 230, in vstack
return _nx.concatenate([atleast_2d(_m) for _m in tup], 0)
ValueError: all the input array dimensions except for the concatenation axis must match exactly
What am I doing wrong? I have tried append, concatenate, defining the empty 2D array as [[]], as [], array([]) and many others.
You need to reshape your original matrix so that the number of columns match the appended arrays:
open_cost_mat_train = np.matrix([]).reshape((0,4))
After which, it gives:
open_cost_mat_train
# matrix([[ 0., 0., 0., 0.],
# [ 1., 0., 0., 0.],
# [ 2., 0., 0., 0.],
# [ 3., 0., 0., 0.],
# [ 4., 0., 0., 0.],
# [ 5., 0., 0., 0.],
# [ 6., 0., 0., 0.],
# [ 7., 0., 0., 0.],
# [ 8., 0., 0., 0.],
# [ 9., 0., 0., 0.]])
If open_cost_mat_train is large I would encourage you to replace the for loop by a vectorized algorithm. I will use the following funtions to show how efficiency is improved by vectorizing loops:
def fvstack():
import numpy as np
np.random.seed(100)
ocmt = np.matrix([]).reshape((0, 4))
for i in xrange(10):
x = np.random.random()
ocm = np.array([x, x + 1, 10*x, x/10])
ocmt = np.vstack([ocmt, ocm])
return ocmt
def fshape():
import numpy as np
from numpy.matlib import empty
np.random.seed(100)
ocmt = empty((10, 4))
for i in xrange(ocmt.shape[0]):
ocmt[i, 0] = np.random.random()
ocmt[:, 1] = ocmt[:, 0] + 1
ocmt[:, 2] = 10*ocmt[:, 0]
ocmt[:, 3] = ocmt[:, 0]/10
return ocmt
I've assumed that the values that populate the first column of ocmt (shorthand for open_cost_mat_train) are obtained from a for loop, and the remaining columns are a function of the first column, as stated in your comments to my original answer. As real costs data are not available, in the forthcoming example the values in the first column are random numbers, and the second, third and fourth columns are the functions x + 1, 10*x and x/10, respectively, where x is the corresponding value in the first column.
In [594]: fvstack()
Out[594]:
matrix([[ 5.43404942e-01, 1.54340494e+00, 5.43404942e+00, 5.43404942e-02],
[ 2.78369385e-01, 1.27836939e+00, 2.78369385e+00, 2.78369385e-02],
[ 4.24517591e-01, 1.42451759e+00, 4.24517591e+00, 4.24517591e-02],
[ 8.44776132e-01, 1.84477613e+00, 8.44776132e+00, 8.44776132e-02],
[ 4.71885619e-03, 1.00471886e+00, 4.71885619e-02, 4.71885619e-04],
[ 1.21569121e-01, 1.12156912e+00, 1.21569121e+00, 1.21569121e-02],
[ 6.70749085e-01, 1.67074908e+00, 6.70749085e+00, 6.70749085e-02],
[ 8.25852755e-01, 1.82585276e+00, 8.25852755e+00, 8.25852755e-02],
[ 1.36706590e-01, 1.13670659e+00, 1.36706590e+00, 1.36706590e-02],
[ 5.75093329e-01, 1.57509333e+00, 5.75093329e+00, 5.75093329e-02]])
In [595]: np.allclose(fvstack(), fshape())
Out[595]: True
In order for the calls to fvstack() and fshape() produce the same results, the random number generator is initialized in both functions through np.random.seed(100). Notice that the equality test has been performed using numpy.allclose instead of fvstack() == fshape() to avoid the round off errors associated to floating point artihmetic.
As for efficiency, the following interactive session shows that initializing ocmt with its final shape is significantly faster than repeatedly stacking rows:
In [596]: import timeit
In [597]: timeit.timeit('fvstack()', setup="from __main__ import fvstack", number=10000)
Out[597]: 1.4884241055042366
In [598]: timeit.timeit('fshape()', setup="from __main__ import fshape", number=10000)
Out[598]: 0.8819408006311278

Categories

Resources