Skip to content

Commit 555cb55

Browse files
committed
calibration Lidar to Vehicle. Running OK. To be improved
1 parent e23a5cb commit 555cb55

1 file changed

Lines changed: 123 additions & 41 deletions

File tree

GEMstack/offboard/calibration/make_gem_e4_ouster.py

Lines changed: 123 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,21 @@
22
import os
33
import sys
44
os.getcwd()
5+
VIS = False
56

7+
#%% things to extract
8+
tx,ty,tz,rx,ry,rz = [None] * 6
69
#%%
7-
pbg = '/mount/wp/GEMstack/data/lidar76.npz'
10+
pbg = '/mount/wp/GEMstack/data/lidar76.npz' #null scene
811
pbgAndLine = '/mount/wp/GEMstack/data/lidar78.npz'
912

1013
#%% load and wash data
1114
import numpy as np
12-
#load null scene -- no added objects
13-
bg = np.load(pbg)['arr_0']
14-
#load data pc -- with added object
15-
bgAndLine = np.load(pbgAndLine)['arr_0']
16-
#remove (0,0,0)'s
17-
bg = bg[~np.all(bg == 0, axis=1)]
18-
bgAndLine = bgAndLine[~np.all(bgAndLine == 0, axis=1)]
1915

20-
#%% crop to only keep a frontal box area
21-
def crop(pc,ix=None,iy=None,iz=None):
22-
mask = True
23-
for dim,intervel in zip([0,1,2],[ix,iy,iz]):
24-
if not intervel: continue
25-
d,u = intervel
26-
mask &= pc[:,dim] >= d
27-
mask &= pc[:,dim] <= u
28-
print(f'points left after cropping {dim}\'th dim',mask.sum())
29-
return pc[mask]
30-
#
31-
area = (-0,5),(-1,1)
32-
bg = crop(bg,*area)
33-
bgAndLine = crop(bgAndLine,*area)
34-
print(bg.shape)
35-
print(bgAndLine.shape)
16+
bg = np.load(pbg)['arr_0'] # load null scene -- no added objects
17+
bgAndLine = np.load(pbgAndLine)['arr_0'] # load data pc -- with added object
18+
bg = bg[~np.all(bg == 0, axis=1)] # remove (0,0,0)'s
19+
bgAndLine = bgAndLine[~np.all(bgAndLine == 0, axis=1)]
3620

3721
#%% visualize cropped null scene and data scene
3822
import pyvista as pv
@@ -45,23 +29,121 @@ def vispc(pc):
4529
plotter.add_mesh(cloud, render_points_as_spheres=True, point_size=2, color='blue')
4630
plotter.camera.position = (-20,0,20)
4731
plotter.camera.focal_point = (0,0,0)
32+
plotter.show_axes()
4833
plotter.show()
34+
if VIS:
35+
vispc(bg)
36+
vispc(bgAndLine)
37+
38+
39+
#%%==============================================================
40+
#======================= util functions =========================
41+
#================================================================
42+
def crop(pc,ix=None,iy=None,iz=None):
43+
# crop a subrectangle in a pointcloud
44+
# usage: crop(pc, ix = (x_min,x_max), ...)
45+
# return: array(N,3)
46+
mask = True
47+
for dim,intervel in zip([0,1,2],[ix,iy,iz]):
48+
if not intervel: continue
49+
d,u = intervel
50+
mask &= pc[:,dim] >= d
51+
mask &= pc[:,dim] <= u
52+
print(f'points left after cropping {dim}\'th dim',mask.sum())
53+
return pc[mask]
54+
55+
from sklearn.linear_model import RANSACRegressor
56+
from sklearn.linear_model import LinearRegression
57+
def fit_plane_ransac(pc,tol=0.01):
58+
# fit a plane in a pointcloud
59+
# and visualize inliers
60+
# pc: np array (N,3). the pointcloud
61+
# tol: the tolerance. default 0.01
62+
# return: float, float, float, array(N,3)
63+
# ^: coeff1, coeff2, intercept toward the plane, inliers of the fit
64+
model = RANSACRegressor(LinearRegression(), residual_threshold=tol)
65+
model.fit(pc[:,:2], pc[:,2])
66+
a, b = model.estimator_.coef_
67+
inter = model.estimator_.intercept_
68+
return a,b,inter,cropped_bg[model.inlier_mask_]
4969

50-
vispc(bg)
51-
vispc(bgAndLine)
52-
#%% take difference to only keep added object
5370
from scipy.spatial import cKDTree
54-
tree = cKDTree(bg)
55-
56-
tolerance = 0.08
57-
# Find points in pc1 that do not have a match in pc2 within the tolerance
58-
idiff = []
59-
for i, point in enumerate(bgAndLine):
60-
_, idx = tree.query(point) # Find the nearest neighbor in pc2
61-
distance = np.linalg.norm(point - bg[idx]) # Compute the distance
62-
if distance > tolerance: # If the nearest neighbor is outside the tolerance
63-
idiff.append(i)
64-
65-
diff = np.array(bgAndLine[diff])
66-
#visualize
67-
vispc(diff)
71+
def pc_diff(pc0,pc1,tol=0.1):
72+
# remove points in pc0 from pc1 s.t. euclidian distance is within tolerance
73+
# return: array(N,3)
74+
tree = cKDTree(pc0)
75+
diff = []
76+
for i, point in enumerate(pc1):
77+
_, idx = tree.query(point)
78+
distance = np.linalg.norm(point - pc0[idx]) # Compute the distance
79+
if distance > tol:
80+
diff.append(point)
81+
# tree = cKDTree(pc1)
82+
# for i, point in enumerate(pc0):
83+
# _, idx = tree.query(point)
84+
# distance = np.linalg.norm(point - pc1[idx]) # Compute the distance
85+
# if distance > tol:
86+
# diff.append(point)
87+
return np.array(diff)
88+
89+
90+
91+
#%%==============================================================
92+
#========================== tx ty rz ============================
93+
#================================================================
94+
#%% crop to only keep a frontal box area
95+
area = (-0,10),(-2,2),(-3,1)
96+
cropped_bg = crop(bg,*area)
97+
cropped_bgAndLine = crop(bgAndLine,*area)
98+
print(cropped_bg.shape)
99+
print(cropped_bgAndLine.shape)
100+
101+
#%% Take difference to only keep added object
102+
diff = pc_diff(cropped_bg,cropped_bgAndLine)
103+
if VIS:
104+
vispc(diff) #visualize diff, hopefully the added objects
105+
106+
# %% use the added objects to find rz.
107+
# TODO after dataset retake
108+
# right now we assume tx = ty = 0 and \
109+
# just use median to find a headding direction
110+
tx = ty = 0
111+
hx,hy = np.median(diff,axis=0)[:2]
112+
rz = -np.arctan2(hy,hx)
113+
114+
115+
116+
117+
#%%==============================================================
118+
#========================= tz rx ry =============================
119+
#================================================================
120+
# %% this time we crop to keep the ground
121+
cropped_bg = crop(bg,iz = (-3,-2))
122+
if VIS:
123+
print(cropped_bg.shape)
124+
vispc(cropped_bg)
125+
126+
#%%
127+
from math import sqrt
128+
a, b, tz, inliers = fit_plane_ransac(cropped_bg,tol=0.001)
129+
if VIS:
130+
vispc(inliers)
131+
normv = np.array([a, b, -1])
132+
normv /= np.linalg.norm(normv)
133+
nx,ny,nz = normv
134+
ry = np.arctan2(-nx, sqrt(ny**2 + nz**2))
135+
rx = np.arctan2(ny,sqrt(nx**2 + nz**2))
136+
137+
138+
139+
140+
141+
#%% visualize calibrated pointcloud
142+
if VIS:
143+
from scipy.spatial.transform import Rotation as R
144+
rot = R.from_euler('xyz',[rx,ry,rz]).as_matrix()
145+
146+
calibrated_bgAndLine = bgAndLine @ rot.T + [tx,ty,tz]
147+
148+
vispc(calibrated_bgAndLine)
149+
# %%

0 commit comments

Comments
 (0)