Understanding OpenCV homography at a minimum of points - python

I am quite intrigued by the idea of a homography and try to get it to work at a minimal example with python and OpenCV. Yet, my tests do not pass and I am not quite sure why. I pass in a set of corresponding points into the findHomography function according to This
and then multiply the homography matrix to receive my new point.
so the idea behind it is to find the planar coordinate transformation and then transform the points with
X' = H#X
where X' are the new coordinates and X are the coordinates in the new coordinate frame.
Here is some minimal code example:
import cv2
import numpy as np
import matplotlib.pyplot as plt
points = np.array([
[675, 585],
[675, 1722],
[3155, 580],
[3162, 1722],
])
t_points = np.array([
[0,0],
[0, 8.23],
[23.77, 0],
[23.77, 8.23]
])
pt = np.array([675, 580+(1722-580)/2, 0])
pt_test = np.array([0,8.23/2, 0])
def get_h_matrix(src_list, dst_list):
src_pts = np.array(src_list).reshape(-1,1,2)
dst_pts = np.array(dst_list).reshape(-1,1,2)
H, mask = cv2.findHomography(src_pts, dst_pts)
return H
H = get_h_matrix(points, t_points)
transformed = H#pt
plt.scatter(t_points[:,0], t_points[:,1], color = 'blue')
plt.scatter(transformed[0], transformed[1], color = 'orange')
plt.scatter(pt_test[0], pt_test[1], color = 'green')
plt.show()
plt.scatter(points[:,0], points[:,1], color = 'blue')
plt.scatter(pt[0],pt[1], color = 'orange')
plt.show()
where the output corresponds to the following plot
Plot of the coordinate Transformation. We can see that the green point, where the transformed point actually should be, is not even close to the orange point, where the homography transformed the point to.
Maybe somebody can see the error in my train of thoughts.
Your help is kindly appreciated.
EDIT: I swaped the points array a few times, because I thought I made a mistake, but still the wrong transformation.

As Micka mentioned in the comments, the problem is the representation of the test points.
pt = [x,y,1]
instead of
pt = [x,y,0]
after the transformation, the homogeneous coordinates get transformed back by
pt' = pt'/pt'[2]
I appreciate the help.

Related

Counterclockwise sorting of x, y data

I have a set of points in a text file: random_shape.dat.
The initial order of points in the file is random. I would like to sort these points in a counter-clockwise order as follows (the red dots are the xy data):
I tried to achieve that by using the polar coordinates: I calculate the polar angle of each point (x,y) then sort by the ascending angles, as follows:
"""
Script: format_file.py
Description: This script will format the xy data file accordingly to be used with a program expecting CCW order of data points, By soting the points in Counterclockwise order
Example: python format_file.py random_shape.dat
"""
import sys
import numpy as np
# Read the file name
filename = sys.argv[1]
# Get the header name from the first line of the file (without the newline character)
with open(filename, 'r') as f:
header = f.readline().rstrip('\n')
angles = []
# Read the data from the file
x, y = np.loadtxt(filename, skiprows=1, unpack=True)
for xi, yi in zip(x, y):
angle = np.arctan2(yi, xi)
if angle < 0:
angle += 2*np.pi # map the angle to 0,2pi interval
angles.append(angle)
# create a numpy array
angles = np.array(angles)
# Get the arguments of sorted 'angles' array
angles_argsort = np.argsort(angles)
# Sort x and y
new_x = x[angles_argsort]
new_y = y[angles_argsort]
print("Length of new x:", len(new_x))
print("Length of new y:", len(new_y))
with open(filename.split('.')[0] + '_formatted.dat', 'w') as f:
print(header, file=f)
for xi, yi in zip(new_x, new_y):
print(xi, yi, file=f)
print("Done!")
By running the script:
python format_file.py random_shape.dat
Unfortunately I don't get the expected results in random_shape_formated.dat! The points are not sorted in the desired order.
Any help is appreciated.
EDIT: The expected resutls:
Create a new file named: filename_formatted.dat that contains the sorted data according to the image above (The first line contains the starting point, the next lines contain the points as shown by the blue arrows in counterclockwise direction in the image).
EDIT 2: The xy data added here instead of using github gist:
random_shape
0.4919261070361315 0.0861956168831175
0.4860816807027076 -0.06601587301587264
0.5023029456281289 -0.18238249845392662
0.5194784026079869 0.24347943722943777
0.5395164357511545 -0.3140611471861465
0.5570497147514262 0.36010146103896146
0.6074231036252226 -0.4142604617604615
0.6397066014669927 0.48590810704447085
0.7048302091822873 -0.5173701298701294
0.7499157837544145 0.5698170011806378
0.8000108666123336 -0.6199254449254443
0.8601249660418364 0.6500974025974031
0.9002010323281716 -0.7196585989767801
0.9703341483292582 0.7299242424242429
1.0104102146155935 -0.7931355765446666
1.0805433306166803 0.8102046438410078
1.1206193969030154 -0.865251869342778
1.1907525129041021 0.8909386068476981
1.2308285791904374 -0.9360074773711129
1.300961695191524 0.971219008264463
1.3410377614778592 -1.0076702085792988
1.4111708774789458 1.051499409681228
1.451246943765281 -1.0788793781975592
1.5213800597663678 1.1317798110979933
1.561456126052703 -1.1509956709956706
1.6315892420537896 1.2120602125147582
1.671665308340125 -1.221751279024005
1.7417984243412115 1.2923406139315234
1.7818744906275468 -1.2943211334120424
1.8520076066286335 1.3726210153482883
1.8920836729149686 -1.3596340023612745
1.9622167889160553 1.4533549783549786
2.0022928552023904 -1.4086186540731989
2.072425971203477 1.5331818181818184
2.1125020374898122 -1.451707005116095
2.182635153490899 1.6134622195985833
2.2227112197772345 -1.4884454939000387
2.292844335778321 1.6937426210153486
2.3329204020646563 -1.5192876820149541
2.403053518065743 1.774476584022039
2.443129584352078 -1.5433264462809912
2.513262700353165 1.8547569854388037
2.5533387666395 -1.561015348288075
2.6234718826405867 1.9345838252656438
2.663547948926922 -1.5719008264462806
2.7336810649280086 1.9858362849271942
2.7737571312143436 -1.5750757575757568
2.8438902472154304 2.009421487603306
2.883966313501766 -1.5687258953168035
2.954099429502852 2.023481896890988
2.9941754957891877 -1.5564797323888229
3.0643086117902745 2.0243890200708385
3.1043846780766096 -1.536523022432113
3.1745177940776963 2.0085143644234558
3.2145938603640314 -1.5088557654466737
3.284726976365118 1.9749508067689887
3.324803042651453 -1.472570838252656
3.39493615865254 1.919162731208186
3.435012224938875 -1.4285753640299088
3.5051453409399618 1.8343467138921687
3.545221407226297 -1.3786835891381335
3.6053355066557997 1.7260966810966811
3.655430589513719 -1.3197205824478546
3.6854876392284703 1.6130086580086582
3.765639771801141 -1.2544077134986225
3.750611246943765 1.5024152236652237
3.805715838087476 1.3785173160173163
3.850244800627849 1.2787337662337666
3.875848954088563 -1.1827449822904361
3.919007794704616 1.1336638361638363
3.9860581363759846 -1.1074537583628485
3.9860581363759846 1.0004485329485333
4.058012891753723 0.876878197560016
4.096267318663407 -1.0303482880755608
4.15638141809291 0.7443374218374221
4.206476500950829 -0.9514285714285711
4.256571583808748 0.6491902794175526
4.3166856832382505 -0.8738695395513574
4.36678076609617 0.593855765446675
4.426894865525672 -0.7981247540338443
4.476989948383592 0.5802489177489183
4.537104047813094 -0.72918339236521
4.587199130671014 0.5902272727272733
4.647313230100516 -0.667045454545454
4.697408312958435 0.6246979535615904
4.757522412387939 -0.6148858717040526
4.807617495245857 0.6754968516332154
4.8677315946753605 -0.5754260133805582
4.917826677533279 0.7163173947264858
4.977940776962782 -0.5500265643447455
5.028035859820701 0.7448917748917752
5.088149959250204 -0.5373268398268394
5.138245042108123 0.7702912239275879
5.198359141537626 -0.5445838252656432
5.2484542243955445 0.7897943722943728
5.308568323825048 -0.5618191656828015
5.358663406682967 0.8052154663518301
5.41877750611247 -0.5844972451790631
5.468872588970389 0.8156473829201105
5.5289866883998915 -0.6067217630853987
5.579081771257811 0.8197294372294377
5.639195870687313 -0.6248642266824076
5.689290953545233 0.8197294372294377
5.749405052974735 -0.6398317591499403
5.799500135832655 0.8142866981503349
5.859614235262157 -0.6493565525383702
5.909709318120076 0.8006798504525783
5.969823417549579 -0.6570670995670991
6.019918500407498 0.7811767020857934
6.080032599837001 -0.6570670995670991
6.13012768269492 0.7562308146399057
6.190241782124423 -0.653438606847697
6.240336864982342 0.7217601338055886
6.300450964411845 -0.6420995670995664
6.350546047269764 0.6777646595828419
6.410660146699267 -0.6225964187327819
6.4607552295571855 0.6242443919716649
6.520869328986689 -0.5922077922077915
6.570964411844607 0.5548494687131056
6.631078511274111 -0.5495730027548205
6.681173594132029 0.4686727666273125
6.7412876935615325 -0.4860743801652889
6.781363759847868 0.3679316979316982
6.84147785927737 -0.39541245791245716
6.861515892420538 0.25880333951762546
6.926639500135833 -0.28237987012986965
6.917336127605076 0.14262677798392165
6.946677533279001 0.05098957832291173
6.967431210462995 -0.13605442176870675
6.965045730326905 -0.03674603174603108
I find that an easy way to sort points with x,y-coordinates like that is to sort them dependent on the angle between the line from the points and the center of mass of the whole polygon and the horizontal line which is called alpha in the example. The coordinates of the center of mass (x0 and y0) can easily be calculated by averaging the x,y coordinates of all points. Then you calculate the angle using numpy.arccos for instance. When y-y0 is larger than 0 you take the angle directly, otherwise you subtract the angle from 360° (2𝜋). I have used numpy.where for the calculation of the angle and then numpy.argsort to produce a mask for indexing the initial x,y-values. The following function sort_xy sorts all x and y coordinates with respect to this angle. If you want to start from any other point you could add an offset angle for that. In your case that would be zero though.
def sort_xy(x, y):
x0 = np.mean(x)
y0 = np.mean(y)
r = np.sqrt((x-x0)**2 + (y-y0)**2)
angles = np.where((y-y0) > 0, np.arccos((x-x0)/r), 2*np.pi-np.arccos((x-x0)/r))
mask = np.argsort(angles)
x_sorted = x[mask]
y_sorted = y[mask]
return x_sorted, y_sorted
Plotting x, y before sorting using matplotlib.pyplot.plot (points are obvisously not sorted):
Plotting x, y using matplotlib.pyplot.plot after sorting with this method:
If it is certain that the curve does not cross the same X coordinate (i.e. any vertical line) more than twice, then you could visit the points in X-sorted order and append a point to one of two tracks you follow: to the one whose last end point is the closest to the new one. One of these tracks will represent the "upper" part of the curve, and the other, the "lower" one.
The logic would be as follows:
dist2 = lambda a,b: (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1])
z = list(zip(x, y)) # get the list of coordinate pairs
z.sort() # sort by x coordinate
cw = z[0:1] # first point in clockwise direction
ccw = z[1:2] # first point in counter clockwise direction
# reverse the above assignment depending on how first 2 points relate
if z[1][1] > z[0][1]:
cw = z[1:2]
ccw = z[0:1]
for p in z[2:]:
# append to the list to which the next point is closest
if dist2(cw[-1], p) < dist2(ccw[-1], p):
cw.append(p)
else:
ccw.append(p)
cw.reverse()
result = cw + ccw
This would also work for a curve with steep fluctuations in the Y-coordinate, for which an angle-look-around from some central point would fail, like here:
No assumption is made about the range of the X nor of the Y coordinate: like for instance, the curve does not necessarily have to cross the X axis (Y = 0) for this to work.
Counter-clock-wise order depends on the choice of a pivot point. From your question, one good choice of the pivot point is the center of mass.
Something like this:
# Find the Center of Mass: data is a numpy array of shape (Npoints, 2)
mean = np.mean(data, axis=0)
# Compute angles
angles = np.arctan2((data-mean)[:, 1], (data-mean)[:, 0])
# Transform angles from [-pi,pi] -> [0, 2*pi]
angles[angles < 0] = angles[angles < 0] + 2 * np.pi
# Sort
sorting_indices = np.argsort(angles)
sorted_data = data[sorting_indices]
Not really a python question I think, but still I think you could try sorting by - sign(y) * x doing something like:
def counter_clockwise_sort(points):
return sorted(points, key=lambda point: point['x'] * (-1 if point['y'] >= 0 else 1))
should work fine, assuming you read your points properly into a list of dicts of format {'x': 0.12312, 'y': 0.912}
EDIT: This will work as long as you cross the X axis only twice, like in your example.
If:
the shape is arbitrarily complex and
the point spacing is ~random
then I think this is a really hard problem.
For what it's worth, I have faced a similar problem in the past, and I used a traveling salesman solver. In particular, I used the LKH solver. I see there is a Python repo for solving the problem, LKH-TSP. Once you have an order to the points, I don't think it will be too hard to decide on a clockwise vs clockwise ordering.
If we want to answer your specific problem, we need to pick a pivot point.
Since you want to sort according to the starting point you picked, I would take a pivot in the middle (x=4,y=0 will do).
Since we're sorting counterclockwise, we'll take arctan2(-(y-pivot_y),-(x-center_x)) (we're flipping the x axis).
We get the following, with a gradient colored scatter to prove correctness (fyi I removed the first line of the dat file after downloading):
import numpy as np
import matplotlib.pyplot as plt
points = np.loadtxt('points.dat')
#oneliner for ordering points (transform, adjust for 0 to 2pi, argsort, index at points)
ordered_points = points[np.argsort(np.apply_along_axis(lambda x: np.arctan2(-x[1],-x[0]+4) + np.pi*2, axis=1,arr=points)),:]
#color coding 0-1 as str for gray colormap in matplotlib
plt.scatter(ordered_points[:,0], ordered_points[:,1],c=[str(x) for x in np.arange(len(ordered_points)) / len(ordered_points)],cmap='gray')
Result (in the colormap 1 is white and 0 is black), they're numbered in the 0-1 range by order:
For points with comparable distances between their neighbouring pts, we can use KDTree to get two closest pts for each pt. Then draw lines connecting those to give us a closed shape contour. Then, we will make use of OpenCV's findContours to get contour traced always in counter-clockwise manner. Now, since OpenCV works on images, we need to sample data from the provided float format to uint8 image format. Given, comparable distances between two pts, that should be pretty safe. Also, OpenCV handles it well to make sure it traces even sharp corners in curvatures, i.e. smooth or not-smooth data would work just fine. And, there's no pivot requirement, etc. As such all kinds of shapes would be good to work with.
Here'e the implementation -
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial.distance import pdist
from scipy.spatial import cKDTree
import cv2
from scipy.ndimage.morphology import binary_fill_holes
def counter_clockwise_order(a, DEBUG_PLOT=False):
b = a-a.min(0)
d = pdist(b).min()
c = np.round(2*b/d).astype(int)
img = np.zeros(c.max(0)[::-1]+1, dtype=np.uint8)
d1,d2 = cKDTree(c).query(c,k=3)
b = c[d2]
p1,p2,p3 = b[:,0],b[:,1],b[:,2]
for i in range(len(b)):
cv2.line(img,tuple(p1[i]),tuple(p2[i]),255,1)
cv2.line(img,tuple(p1[i]),tuple(p3[i]),255,1)
img = (binary_fill_holes(img==255)*255).astype(np.uint8)
if int(cv2.__version__.split('.')[0])>=3:
_,contours,hierarchy = cv2.findContours(img.copy(),cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
else:
contours,hierarchy = cv2.findContours(img.copy(),cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cont = contours[0][:,0]
f1,f2 = cKDTree(cont).query(c,k=1)
ordered_points = a[f2.argsort()[::-1]]
if DEBUG_PLOT==1:
NPOINTS = len(ordered_points)
for i in range(NPOINTS):
plt.plot(ordered_points[i:i+2,0],ordered_points[i:i+2,1],alpha=float(i)/(NPOINTS-1),color='k')
plt.show()
return ordered_points
Sample run -
# Load data in a 2D array with 2 columns
a = np.loadtxt('random_shape.csv',delimiter=' ')
ordered_a = counter_clockwise_order(a, DEBUG_PLOT=1)
Output -

How does one Fourier transform an array of 1's and 0's

I'm trying to Fourier transform a matrix of 0's with a solid circle (like a pinhole) of 1's using Python. I am trying to get an image of an Airy Function, which should look like concentric circular ripples viewed from above. I'm still a bit of a beginner with Python and coding more generally.
import numpy as np
dimension = 256
list1 = []
listpiece = []
for i in range(dimension):
for j in range(dimension):
listpiece.append(0)
list1.append(listpiece)
listpiece = []
k=128
for i in range(dimension):
for j in range(dimension):
if (i-k)*(i-k) + (j-k)*(j-k) <= 64*2:
list1[i][j] = 1
import matplotlib.pylab as plt
import scipy.sparse as sparse
plt.spy(list1)
plt.show()
Which gave this image of a black circle on a white background.
I then converted this list to a numpy array.
singledimlist = []
for i in range(dimension):
for j in range(dimension):
singledimlist.append(list1[i][j])
prefourierline = np.array( singledimlist )
shape = ( dimension, dimension )
prefourier = prefourierline.reshape( shape )
print(prefourier)
plt.spy(prefourier)
plt.show()
Which gave an identical image:
Using np.fft.fft2 gave a blank image, even though the output had very large changes:
from scipy.fftpack import fft, ifft
fouriered = np.fft.fft2(prefourier)
plt.spy(fouriered)
plt.show()
Output:
[[ 405. +0.00000000e+00j -401.08038516-1.50697234e-16j
389.47420686-2.31615451e-15j ... -370.63201656-5.88988318e-15j
389.47420686+2.35778788e-15j -401.08038516+8.95615360e-15j]
[-401.08038516-2.27306384e-15j 397.18553235-1.77932604e-15j
-385.65292606-1.63119926e-15j ... 366.93100304+7.84568423e-15j
-385.65292606-2.13934425e-15j 397.18553235-1.08069809e-14j]
[ 389.47420686+8.66313300e-15j -385.65292606-1.67296339e-14j
374.33891021+6.30297134e-15j ... -355.97430091-1.40810576e-14j
374.33891021+1.25700186e-14j -385.65292606-1.24588719e-14j]
...
[-370.63201656-4.69963986e-14j 366.93100304+4.87944288e-14j
-355.97430091-4.69561772e-14j ... 338.1937218 +3.81585557e-14j
-355.97430091-4.67444422e-14j 366.93100304+3.64531853e-14j]
[ 389.47420686+3.34933421e-14j -385.65292606-2.70693599e-14j
374.33891021+3.08443590e-14j ... -355.97430091-3.30709228e-14j
374.33891021+2.07603249e-14j -385.65292606-2.63513116e-14j]
[-401.08038516-5.83528175e-14j 397.18553235+7.09535468e-14j
-385.65292606-5.72142574e-14j ... 366.93100304+7.01916155e-14j
-385.65292606-6.12008707e-14j 397.18553235+6.47498390e-14j]]
So, I tried using np.fft.fft, but fared little better, instead of a blank image, I output a black horizontal stripe with the same width as the radius of the original circle, bisecting the white background.
from scipy.fftpack import fft, ifft
fouriered = np.fft.fft(prefourier)
plt.spy(fouriered)
plt.show()
I suspect the main problem lies between my computer screen and my chair.
My question is, what am I doing wrong? How does one Fourier transform an array of this sort?
Thanks, I'd be grateful for some help,
ES
There are multiple things, so I just provided a working example, that uses numpy. The zeroes and ones question is not a problem, since those are legitimate floating point numbers too, so the physics is fine. There are two issues in finding the right answer in the output. One is to zoom in or, alternatively, make the circle very small. Play with that and calculate the expected ring sizes from the close form solution (Airy-Function).
The other is contrast. Below I just used a log to visualize better. Alternatives would be to take a root. Also note that I didn't square the result (as physics would indicate, i.e. intensity vs electric field).
import matplotlib.pyplot as p
import numpy as np
n=1000
aa=np.ones((n,n))
x=np.linspace(-1,1,n)
y=np.linspace(-1,1,n)
X,Y= np.meshgrid(x,y) #this allows us to use vectorized approach, no for loops
R = np.sqrt(X**2+Y**2)
aa[R<0.1]=0
p.figure(figsize=(20,6))
p.subplot(131)
p.imshow(aa)
p.colorbar()
p.subplot(132)
spec= np.fft.fftshift(np.fft.fft2(aa))
p.imshow( np.log(np.abs(spec)))
p.colorbar()
p.title('airy func too fine to see')
p.subplot(133)
p.imshow( np.log(np.abs(spec[450:550,450:550])))
p.colorbar()
p.title('zoomed in');

Sfm, reconstruction from stereo image

I need your help.
I have to rebuild markers in 3D space from stereo image. In my case, I would like to reconstruct the markers using an uncalibrated method.
I shoot 2 photos and sign the markers manually for now.
import cv2
import numpy as np
from matplotlib import pyplot as plt
from scipy import linalg
img1 = cv2.imread('3.jpg',0)
img2 = cv2.imread('4.jpg',0)
pts1 = np.array([(1599.6711229946527, 1904.8048128342245), (1562.131016042781, 1734.4304812834225), (1495.7139037433158, 1295.5),
(2373.5748663101604, 1604.4839572192514), (2362.0240641711234, 2031.8636363636363), (2359.136363636364, 2199.3502673796793),
(2656.5695187165775, 1653.5748663101604), (2676.7834224598937, 1506.302139037433), (2740.312834224599, 1026.9438502673797),
(1957.745989304813, 807.4786096256685)],dtype='float64')
pts2 = np.array([(1579.457219251337, 1899.0294117647059), (1539.0294117647059, 1737.3181818181818),
(1472.612299465241, 1307.0508021390374), (2315.8208556149734, 1633.3609625668448),
(2298.4946524064176, 2054.9652406417113), (2301.3823529411766, 2190.687165775401),
(2630.5802139037432, 1670.9010695187167), (2642.131016042781, 1538.066844919786),
(2711.4358288770054, 1076.0347593582887), (1949.0828877005351, 842.1310160427806)],dtype='float64')
subsequently I find the fundamental matrix
F, mask = cv2.findFundamentalMat(pts1,pts2,cv2.FM_7POINT)
and print the result from cv2.computeCorrespondEpilines
link
it would seem to work well!
I have the camera matrix, previously calibrated with a chessboard, following the tutorial on the opencv website
mtx=np.array([[3.19134206e+03, 0.00000000e+00, 2.01707613e+03],
[0.00000000e+00, 3.18501724e+03, 1.54542273e+03],
[0.00000000e+00, 0.00000000e+00, 1.00000000e+00]])
extract the Essential matrix , following what is reported in the book Hartley and Zisserman
E = K.t() * F * K
E = mtx.T * F * mtx
I decomposed this matrix to find the rotation and translation matrices
R1, R2, T = cv2.decomposeEssentialMat(E)
kr= np.dot(mtx,R1)
kt= np.dot(mtx,T)
projction2=np.hstack((kr,kt))
projction1 = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]])
obtaining the projection matrices.
P1 is the first matrix, which as always described in the above book is P1 = [I | 0] the second matrix is P2 = K [ R | t ]
now I used the following code to go back to the triangulation of the points
points4D = cv2.triangulatePoints(projction1, projction2, pts1.T, pts2.T)
I convert the homogeneous coordinates into Cartesian and the result is this:
coordinate_eucl= cv2.convertPointsFromHomogeneous(points4D.T)
coordinate_eucl=coordinate_eucl.reshape(-1,3)
x,y,z=coordinate_eucl.T
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(x, y, z, c='r', marker='o')
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')
plt.show()
link
what am I wrong?
thx
It is good to check each step individually. (You may want to look 4th step first)
1- First, you said you calibrated camera previously. How much reprojection error you got? Did you do any checks to validate success of your calibration. I also assume both your cameras mostly identical.
2- If the fundamental matrix you found is correct (make sure your point lists have same order for both list by the way), it should satisfy epipolar constraint p' F p = 0 where p' is the point in right view and p is point in left view (homogeneous pixel coordinates). Although they will not be exactly 0, should be close to 0. This equation must hold for all point correspondences. If it does not, try using CM_FM_RANSAC or skip to step 3.
3- Check whether you can directly calculate essential matrix with opencv function. Also, a similar equation must hold for essential matrix.
4- OpenCV decomposeEssentialMat function returns two possible rotation matrices and there are two possible translations (so total 4 possible R T combination). Try testing all of them. If you can get correct solution with one of 4 combinations, I will edit my answer to include how to get correct combination.
If your fundamental / essential matrix calculations are correct and problem still occurs, please let me know.

Basic 3D voxel grid in Mayavi

I'm trying to visualize a 3D array through Mayavi in Python. I simply want to create a structured 3D voxel grid in which I can show some pre-specified voxel-space-filling points. I do not think that I want
The only example that I can find that I think is relatively relevant is this MRI example. I can use the following code to get a somewhat workable example:
import numpy as np
from mayavi import mlab
data = (100, 100, 100)
data = np.zeros(data)
data[0:50, 50:70, 0:50] = 1
data[0:50, 0:20, 0:50] = 1
src = mlab.pipeline.scalar_field(data)
outer = mlab.pipeline.iso_surface(src)
mlab.show()
This is able to generate the following images:
As you can see, not all sides of the boxes are generated, even though those points have the same value as the sides of the boxes that are generated.
Is there a way to visualize every single point in the numpy array that has value equal to 1? I am fine if there is no iso-surface visualization -- in fact, I would prefer some Minecraft-esque blocky voxel visualization.
Hi
import mayavi.mlab
import numpy
data = (100, 100, 100)
data = numpy.zeros(data)
data[0:50, 50:70, 0:50] = 1
data[0:50, 0:20, 0:50] = 1
xx, yy, zz = numpy.where(data == 1)
mayavi.mlab.points3d(xx, yy, zz,
mode="cube",
color=(0, 1, 0),
scale_factor=1)
mayavi.mlab.show()

generating a hemispherical surface with triangular_mesh and representing a data( as value or as colors) at each vertex

I want to generate a surface which should look like a hemisphere.. What I have done so far is to read an already existing BEM mesh and try to show the scalar values on it. But now I have to show the scalar values on a hemisphere instead of the Bem mesh. And I don't know how to generate using a triangular mesh that looks like an hemisphere.
This hemisphere needs to contain a set of N number of points(x,y,z)[using the mlab.triangular_mesh] and at each vertex I need to represent N data(float) either as a value or using variations in colormap(eg: blue(lowest value of the data) to red(highest value of the data)). data=its an array of size 2562, a set of float values, could be randomly generated as its part of another codes. Points were part of another set of code too.its of shape(2562,3). but the shape is not a hemisphere
This was the program I used for viewing using the BEM surface
fname = data_path + '/subjects/sample/bem/sample-5120-5120-5120-bem-sol.fif'
surfaces = mne.read_bem_surfaces(fname, add_geom=True)
print "Number of surfaces : %d" % len(surfaces)
head_col = (0.95, 0.83, 0.83) # light pink
colors = [head_col]
try:
from enthought.mayavi import mlab
except:
from mayavi import mlab
mlab.figure(size=(600, 600), bgcolor=(0, 0, 0))
for c, surf in zip(colors, surfaces):
points = surf['rr']
faces = surf['tris']
s=data
mlab.triangular_mesh(points[:, 0], points[:, 1], points[:, 2],faces,color=c, opacity=1,scalars=s[:,0])
#mesh= mlab.triangular_mesh(x,y,z,triangles,representation='wireframe',opacity=0) #point_data=mesh.mlab_source.dataset.point_data
#point_data.scalars=t
#point_data.scalars.name='Point data'
#mesh2= mlab.pipeline.set_active_attribute(mesh,point_scalars='Point data')
As others have pointed out your question is not very clear, and does not include an easily reproducible example -- your example would take considerable work for us to reproduce and you have not described the steps you have taken very clearly.
What you are trying to do is easy. Scalars can be defined for each vertex (i.e., each VTK point):
surf = mlab.triangular_mesh(x,y,z,triangles)
surf.mlab_source.scalars = t
And you need to set a flag to get them to appear, which I think might be your problem:
surf.actor.mapper.scalar_visibility=True
Here is some code to generate a half-sphere. It produces a VTK polydata. I'm not 100% sure if the mayavi source is the same source type as triangular_mesh but I think it is.
res = 250. #desired resolution (number of samples on sphere)
phi,theta = np.mgrid[0:np.pi:np.pi/res, 0:np.pi:np.pi/res]
x=np.cos(theta) * np.sin(phi)
y=np.sin(theta) * np.sin(phi)
z=np.cos(phi)
mlab.mesh(x,y,z,color=(1,1,1))

Categories