forked from yukitsuji/3D_CNN_tensorflow
-
Notifications
You must be signed in to change notification settings - Fork 0
/
input_velodyne.py
328 lines (285 loc) · 12.9 KB
/
input_velodyne.py
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
#!/usr/bin/env python
import sys
import os
import rospy
import numpy as np
import cv2
import pcl
import glob
import math
import std_msgs.msg
import sensor_msgs.point_cloud2 as pc2
from sensor_msgs.msg import PointCloud2
from parse_xml import parseXML
def load_pc_from_pcd(pcd_path):
"""Load PointCloud data from pcd file."""
p = pcl.load(pcd_path)
return np.array(list(p), dtype=np.float32)
def load_pc_from_bin(bin_path):
"""Load PointCloud data from pcd file."""
obj = np.fromfile(bin_path, dtype=np.float32).reshape(-1, 4)
return obj
def read_label_from_txt(label_path):
"""Read label from txt file."""
text = np.fromfile(label_path)
bounding_box = []
with open(label_path, "r") as f:
labels = f.read().split("\n")
for label in labels:
if not label:
continue
label = label.split(" ")
if (label[0] == "DontCare"):
continue
if label[0] == ("Car" or "Van"): # or "Truck"
bounding_box.append(label[8:15])
if bounding_box:
data = np.array(bounding_box, dtype=np.float32)
return data[:, 3:6], data[:, :3], data[:, 6]
else:
return None, None, None
def read_label_from_xml(label_path):
"""Read label from xml file.
# Returns:
label_dic (dictionary): labels for one sequence.
size (list): Bounding Box Size. [l, w. h]?
"""
labels = parseXML(label_path)
label_dic = {}
for label in labels:
first_frame = label.firstFrame
nframes = label.nFrames
size = label.size
obj_type = label.objectType
for index, place, rotate in zip(range(first_frame, first_frame+nframes), label.trans, label.rots):
if index in label_dic.keys():
label_dic[index]["place"] = np.vstack((label_dic[index]["place"], place))
label_dic[index]["size"] = np.vstack((label_dic[index]["size"], np.array(size)))
label_dic[index]["rotate"] = np.vstack((label_dic[index]["rotate"], rotate))
else:
label_dic[index] = {}
label_dic[index]["place"] = place
label_dic[index]["rotate"] = rotate
label_dic[index]["size"] = np.array(size)
return label_dic, size
def read_calib_file(calib_path):
"""Read a calibration file."""
data = {}
with open(calib_path, 'r') as f:
for line in f.readlines():
if not line or line == "\n":
continue
key, value = line.split(':', 1)
try:
data[key] = np.array([float(x) for x in value.split()])
except ValueError:
pass
return data
def proj_to_velo(calib_data):
"""Projection matrix to 3D axis for 3D Label"""
rect = calib_data["R0_rect"].reshape(3, 3)
velo_to_cam = calib_data["Tr_velo_to_cam"].reshape(3, 4)
inv_rect = np.linalg.inv(rect)
inv_velo_to_cam = np.linalg.pinv(velo_to_cam[:, :3])
return np.dot(inv_velo_to_cam, inv_rect)
def filter_camera_angle(places):
"""Filter camera angles for KiTTI Datasets"""
bool_in = np.logical_and((places[:, 1] < places[:, 0] - 0.27), (-places[:, 1] < places[:, 0] - 0.27))
# bool_in = np.logical_and((places[:, 1] < places[:, 0]), (-places[:, 1] < places[:, 0]))
return places[bool_in]
def create_publish_obj(obj, places, rotates, size):
"""Create object of correct data for publisher"""
for place, rotate, sz in zip(places, rotates, size):
x, y, z = place
obj.append((x, y, z))
h, w, l = sz
if l > 10:
continue
for hei in range(0, int(h*100)):
for wid in range(0, int(w*100)):
for le in range(0, int(l*100)):
a = (x - l / 2.) + le / 100.
b = (y - w / 2.) + wid / 100.
c = (z) + hei / 100.
obj.append((a, b, c))
return obj
def get_boxcorners(places, rotates, size):
"""Create 8 corners of bounding box from bottom center."""
corners = []
for place, rotate, sz in zip(places, rotates, size):
x, y, z = place
h, w, l = sz
if l > 10:
continue
corner = np.array([
[x - l / 2., y - w / 2., z],
[x + l / 2., y - w / 2., z],
[x - l / 2., y + w / 2., z],
[x - l / 2., y - w / 2., z + h],
[x - l / 2., y + w / 2., z + h],
[x + l / 2., y + w / 2., z],
[x + l / 2., y - w / 2., z + h],
[x + l / 2., y + w / 2., z + h],
])
corner -= np.array([x, y, z])
rotate_matrix = np.array([
[np.cos(rotate), -np.sin(rotate), 0],
[np.sin(rotate), np.cos(rotate), 0],
[0, 0, 1]
])
a = np.dot(corner, rotate_matrix.transpose())
a += np.array([x, y, z])
corners.append(a)
return np.array(corners)
def publish_pc2(pc, obj):
"""Publisher of PointCloud data"""
pub = rospy.Publisher("/points_raw", PointCloud2, queue_size=1000000)
rospy.init_node("pc2_publisher")
header = std_msgs.msg.Header()
header.stamp = rospy.Time.now()
header.frame_id = "velodyne"
points = pc2.create_cloud_xyz32(header, pc[:, :3])
pub2 = rospy.Publisher("/points_raw1", PointCloud2, queue_size=1000000)
header = std_msgs.msg.Header()
header.stamp = rospy.Time.now()
header.frame_id = "velodyne"
points2 = pc2.create_cloud_xyz32(header, obj)
r = rospy.Rate(0.1)
while not rospy.is_shutdown():
pub.publish(points)
pub2.publish(points2)
r.sleep()
def raw_to_voxel(pc, resolution=0.50, x=(0, 90), y=(-50, 50), z=(-4.5, 5.5)):
"""Convert PointCloud2 to Voxel"""
logic_x = np.logical_and(pc[:, 0] >= x[0], pc[:, 0] < x[1])
logic_y = np.logical_and(pc[:, 1] >= y[0], pc[:, 1] < y[1])
logic_z = np.logical_and(pc[:, 2] >= z[0], pc[:, 2] < z[1])
pc = pc[:, :3][np.logical_and(logic_x, np.logical_and(logic_y, logic_z))]
pc =((pc - np.array([x[0], y[0], z[0]])) / resolution).astype(np.int32)
voxel = np.zeros((int((x[1] - x[0]) / resolution), int((y[1] - y[0]) / resolution), int(round((z[1]-z[0]) / resolution))))
voxel[pc[:, 0], pc[:, 1], pc[:, 2]] = 1
return voxel
def center_to_sphere(places, size, resolution=0.50, min_value=np.array([0., -50., -4.5]), scale=4, x=(0, 90), y=(-50, 50), z=(-4.5, 5.5)):
"""Convert object label to Training label for objectness loss"""
x_logical = np.logical_and((places[:, 0] < x[1]), (places[:, 0] >= x[0]))
y_logical = np.logical_and((places[:, 1] < y[1]), (places[:, 1] >= y[0]))
z_logical = np.logical_and((places[:, 2] < z[1]), (places[:, 2] >= z[0]))
xyz_logical = np.logical_and(x_logical, np.logical_and(y_logical, z_logical))
center = places.copy()
center[:, 2] = center[:, 2] + size[:, 0] / 2.
sphere_center = ((center[xyz_logical] - min_value) / (resolution * scale)).astype(np.int32)
return sphere_center
def sphere_to_center(p_sphere, resolution=0.5, scale=4, min_value=np.array([0., -50., -4.5])):
"""from sphere center to label center"""
center = p_sphere * (resolution*scale) + min_value
return center
def voxel_to_corner(corner_vox, resolution, center):#TODO
"""Create 3D corner from voxel and the diff to corner"""
corners = center + corner_vox
return corners
def read_labels(label_path, label_type, calib_path=None, is_velo_cam=False, proj_velo=None):
"""Read labels from xml or txt file.
Original Label value is shifted about 0.27m from object center.
So need to revise the position of objects.
"""
if label_type == "txt": #TODO
places, size, rotates = read_label_from_txt(label_path)
if places is None:
return None, None, None
rotates = np.pi / 2 - rotates
dummy = np.zeros_like(places)
dummy = places.copy()
if calib_path:
places = np.dot(dummy, proj_velo.transpose())[:, :3]
else:
places = dummy
if is_velo_cam:
places[:, 0] += 0.27
elif label_type == "xml":
bounding_boxes, size = read_label_from_xml(label_path)
places = bounding_boxes[30]["place"]
rotates = bounding_boxes[30]["rotate"][:, 2]
size = bounding_boxes[30]["size"]
return places, rotates, size
def create_label(places, size, corners, resolution=0.50, x=(0, 90), y=(-50, 50), z=(-4.5, 5.5), scale=4, min_value=np.array([0., -50., -4.5])):
"""Create training Labels which satisfy the range of experiment"""
x_logical = np.logical_and((places[:, 0] < x[1]), (places[:, 0] >= x[0]))
y_logical = np.logical_and((places[:, 1] < y[1]), (places[:, 1] >= y[0]))
z_logical = np.logical_and((places[:, 2] + size[:, 0]/2. < z[1]), (places[:, 2] + size[:, 0]/2. >= z[0]))
xyz_logical = np.logical_and(x_logical, np.logical_and(y_logical, z_logical))
center = places.copy()
center[:, 2] = center[:, 2] + size[:, 0] / 2. # Move bottom to center
sphere_center = ((center[xyz_logical] - min_value) / (resolution * scale)).astype(np.int32)
train_corners = corners[xyz_logical].copy()
anchor_center = sphere_to_center(sphere_center, resolution=resolution, scale=scale, min_value=min_value) #sphere to center
for index, (corner, center) in enumerate(zip(corners[xyz_logical], anchor_center)):
train_corners[index] = corner - center
return sphere_center, train_corners
def corner_to_train(corners, sphere_center, resolution=0.50, x=(0, 90), y=(-50, 50), z=(-4.5, 5.5), scale=4, min_value=np.array([0., -50., -4.5])):
"""Convert corner to Training label for regression loss"""
x_logical = np.logical_and((corners[:, :, 0] < x[1]), (corners[:, :, 0] >= x[0]))
y_logical = np.logical_and((corners[:, :, 1] < y[1]), (corners[:, :, 1] >= y[0]))
z_logical = np.logical_and((corners[:, :, 2] < z[1]), (corners[:, :, 2] >= z[0]))
xyz_logical = np.logical_and(x_logical, np.logical_and(y_logical, z_logical)).all(axis=1)
train_corners = corners[xyz_logical].copy()
sphere_center = sphere_to_center(sphere_center, resolution=resolution, scale=scale, min_value=min_value) #sphere to center
for index, (corner, center) in enumerate(zip(corners[xyz_logical], sphere_center)):
train_corners[index] = corner - center
return train_corners
def corner_to_voxel(voxel_shape, corners, sphere_center, scale=4):
"""Create final regression label from corner"""
corner_voxel = np.zeros((voxel_shape[0] / scale, voxel_shape[1] / scale, voxel_shape[2] / scale, 24))
corner_voxel[sphere_center[:, 0], sphere_center[:, 1], sphere_center[:, 2]] = corners
return corner_voxel
def create_objectness_label(sphere_center, resolution=0.5, x=90, y=100, z=10, scale=4):
"""Create Objectness label"""
obj_maps = np.zeros((int(x / (resolution * scale)), int(y / (resolution * scale)), int(round(z / (resolution * scale)))))
obj_maps[sphere_center[:, 0], sphere_center[:, 1], sphere_center[:, 2]] = 1
return obj_maps
def process(velodyne_path, label_path=None, calib_path=None, dataformat="pcd", label_type="txt", is_velo_cam=False):
p = []
pc = None
bounding_boxes = None
places = None
rotates = None
size = None
proj_velo = None
if dataformat == "bin":
pc = load_pc_from_bin(velodyne_path)
elif dataformat == "pcd":
pc = load_pc_from_pcd(velodyne_path)
if calib_path:
calib = read_calib_file(calib_path)
proj_velo = proj_to_velo(calib)[:, :3]
if label_path:
places, rotates, size = read_labels(label_path, label_type, calib_path=calib_path, is_velo_cam=is_velo_cam, proj_velo=proj_velo)
corners = get_boxcorners(places, rotates, size)
print("################", len(pc))
pc = filter_camera_angle(pc)
# obj = []
# obj = create_publish_obj(obj, places, rotates, size)
p.append((0, 0, 0))
p.append((0, 0, -1))
print pc.shape
print 1
# publish_pc2(pc, obj)
a = center_to_sphere(places, size, resolution=0.25)
print places
print a
print sphere_to_center(a, resolution=0.25)
bbox = sphere_to_center(a, resolution=0.25)
print corners.shape
# publish_pc2(pc, bbox.reshape(-1, 3))
publish_pc2(pc, corners.reshape(-1, 3))
if __name__ == "__main__":
# pcd_path = "../data/training/velodyne/000012.pcd"
# label_path = "../data/training/label_2/000012.txt"
# calib_path = "../data/training/calib/000012.txt"
# process(pcd_path, label_path, calib_path=calib_path, dataformat="pcd")
# bin_path = "../data/2011_09_26/2011_09_26_drive_0001_sync/velodyne_points/data/0000000030.bin"
# xml_path = "../data/2011_09_26/2011_09_26_drive_0001_sync/tracklet_labels.xml"
# process(bin_path, xml_path, dataformat="bin", label_type="xml")
pcd_path = "/home/katou01/download/training/velodyne/000410.bin"
label_path = "/home/katou01/download/training/label_2/000410.txt"
calib_path = "/home/katou01/download/training/calib/000410.txt"
process(pcd_path, label_path, calib_path=calib_path, dataformat="bin", is_velo_cam=True)