KITTI 데이터셋의 LiDAR와 image 데이터를 사용하여 LiDAR data를 이미지에 projection 해보았다
*.bin
P0
, P1
, P2
, P3
: projection 행렬P2
만 사용하면 된다R0_rect
: rectificationTr_velo_to_cam
: LiDAR 좌표 -> camera 좌표
def visualization_open3d(data):
pcd = open3d.geometry.PointCloud()
pcd.points = open3d.utility.Vector3dVector(data[:, :3])
open3d.visualization.draw_geometries([pcd])
file_name = '000000'
velo_file = f'./data_object_velodyne/training/velodyne/{file_name}.bin'
with open(velo_file, 'rb') as f:
data = np.fromfile(f, dtype=np.float32).reshape(-1,4)
visualization_open3d(data)
def visualization_mayavi(data):
x = data[:, 0]
y = data[:, 1]
z = data[:, 2]
mlab.figure(bgcolor=(0, 0, 0))
mlab.points3d(x, y, z, color=(0, 1, 0), mode='point')
# mlab.axes()
mlab.show()
file_name = '000000'
velo_file = f'./data_object_velodyne/training/velodyne/{file_name}.bin'
with open(velo_file, 'rb') as f:
data = np.fromfile(f, dtype=np.float32).reshape(-1,4)
visualization_mayavi(data)
def read_calib_file(file_path):
with open(file_path, 'r') as f:
lines = f.readlines()
P2 = np.array([float(i) for i in lines[2].split(' ')[1:]]).reshape(3,4)
R0_rect = np.array([float(i) for i in lines[4].split(' ')[1:]]).reshape(3,3)
Tr_velo_to_cam = np.array([float(i) for i in lines[5].split(' ')[1:]]).reshape(3,4)
return P2, R0_rect, Tr_velo_to_cam
[z>0]
을 하는 이유는 depth가 양수인 것만 투영하도록 하기 위해서이다. depth가 음수인 경우는 뒷쪽 lidar 데이터이기 때문이다file_name = '000000'
calib_file = f'./calib/training/calib/{file_name}.txt'
image_file = f'./data_object_image_2/training/image_2/{file_name}.png'
velo_file = f'./data_object_velodyne/training/velodyne/{file_name}.bin' #lidar 파일
P2, R0_rect, Tr_velo_to_cam = read_calib_file(calib_file)
R0 = np.eye(4)
R0[:3, :3] = R0_rect #3x3 행렬인 R0_rect을 4x4 행렬로 변환
Tr = np.vstack([Tr_velo_to_cam, [0,0,0,1]]) #3x4 행렬인 Tr_velo_to_cam를 4x4 행렬로 변환
#lidar 데이터 불러오기
with open(velo_file, 'rb') as f:
data = np.fromfile(f, dtype=np.float32).reshape(-1,4)
XYZ1 = np.vstack([data[:,:3].T, np.ones((1, data.shape[0]))])
xyz = np.dot(P2,np.dot(R0,np.dot(Tr, XYZ1)))
z = xyz[2, :]
x = (xyz[0, :] / z).astype(np.int32)[z>0]
y = (xyz[1, :] / z).astype(np.int32)[z>0]
def visualization_plt(image_file, data, x, y):
img = cv2.imread(image_file)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
aspect_ratio = float(img.shape[1]) / img.shape[0]
fig, axs = plt.subplots(1, 2, figsize=(20, 25 ))
axs[0].imshow(img_rgb)
axs[0].axis('off')
x_values = data[:, 0]
x_min, x_max = np.percentile(x_values, 1), np.percentile(x_values, 99)
scatter = axs[1].scatter(x, img.shape[0] - y, c=x_values, cmap='jet', marker='.', s=15, vmin=x_min, vmax=x_max)
axs[1].set_xlim([0, img.shape[1]])
axs[1].set_ylim([0, img.shape[0]])
axs[1].axis('off')
for ax in axs:
ax.set_aspect(aspect_ratio)
plt.tight_layout()
plt.show()
def visualization_projection(image_file, data, x, y):
img = cv2.imread(image_file)
img_mapped = img.copy()
img_h, img_w = img.shape[:2]
# 거리에 따라 color값을 다르게 주기 위한 부분
x_normalized = (data[:, 0] - np.min(data[:, 0])) / (np.max(data[:, 0]) - np.min(data[:, 0]))
colors = plt.cm.magma(x_normalized)
for i, (ix, iy) in enumerate(zip(x, y)):
if 0 <= ix < img_w and 0 <= iy < img_h:
color = (colors[i] * 255).astype(np.uint8)[:3]
color = (int(color[2]), int(color[1]), int(color[0]))
cv2.circle(img_mapped, (ix, iy), radius=1, color=color, thickness=2)
img_mapped_rgb = cv2.cvtColor(img_mapped, cv2.COLOR_BGR2RGB)
plt.imshow(img_mapped_rgb)
plt.show()
https://www.cvlibs.net/datasets/kitti/setup.php
https://darkpgmr.tistory.com/190