forked from NVIDIA-AI-IOT/CUDA-PointPillars
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvisualize_point_cloud.py
141 lines (113 loc) · 5.8 KB
/
visualize_point_cloud.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
import argparse
import os
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from shapely.geometry import Polygon
def visualize_3d_point_cloud(bin_dir, pred_dir, truth_dir, output_dir):
# Create the output directory if it doesn't exist
os.makedirs(output_dir, exist_ok=True)
# List all binary point cloud files in the specified directory
bin_files = [f for f in os.listdir(bin_dir) if f.endswith('.bin')]
for bin_file in bin_files:
bin_path = os.path.join(bin_dir, bin_file)
pred_file = os.path.join(pred_dir, bin_file.replace('.bin', '.txt'))
truth_file = os.path.join(truth_dir, bin_file.replace('.bin', '.txt'))
# Check if prediction and truth files exist before processing
if not (os.path.exists(pred_file)):
print(f"Skipping {bin_file} as prediction label file do not exist.")
continue
# Load binary point cloud
bin = np.fromfile(bin_path, dtype=np.float32)
# Reshape and drop reflection values
points = bin.reshape((-1, 4))[:, 0:3]
# Read the content of the output file and parse the data
with open(pred_file, 'r') as file:
lines = file.readlines()
# Create a list of bounding boxes (cuboids)
pred_boxes = []
for line in lines:
data = line.split()
if len(data) == 9:
x, y, z, dx, dy, dz, rot, cls, conf = map(float, data)
# Add a filter to ignore bounding boxes below confidence score 0.2
if conf < 0.2:
continue
elif len(data) == 8: # To use two truth labels files instead
x, y, z, dx, dy, dz, rot, cls = map(float, data)
else:
print(f"Unexpected pred number of items in line: {len(data)}")
# Create a rectangle representing the bounding box (bird's eye view)
#rectangle = plt.Rectangle((x - dx / 2, y - dy / 2), dx, dy, fill=False, color="red")
bottom_left_x = x - dx / 2
bottom_left_y = y - dy / 2
rot = rot * 57.2957795 # rad to degree
if cls == 1:
color = 'red'
else:
color = 'blue'
rectangle = matplotlib.patches.Rectangle((bottom_left_x, bottom_left_y), dx, dy, angle=rot, \
rotation_point="center", color=color, fill=False)
pred_boxes.append(rectangle)
# Read the content of the output file and parse the data
with open(truth_file, 'r') as file:
lines = file.readlines()
# Create a list of bounding boxes (cuboids)
truth_boxes = []
for line in lines:
data = line.split()
if len(data) == 8:
x, y, z, dx, dy, dz, rot, cls = map(float, data)
else:
print(f"Unexpected truth number of items in line: {len(data)}")
# Create a rectangle representing the bounding box (bird's eye view)
#rectangle = plt.Rectangle((x - dx / 2, y - dy / 2), dx, dy, fill=False, color="red")
bottom_left_x = x - dx / 2
bottom_left_y = y - dy / 2
rot = rot * 57.2957795 # rad to degree
if cls == 1:
color = 'red'
else:
color = 'blue'
rectangle = matplotlib.patches.Rectangle((bottom_left_x, bottom_left_y), dx, dy, angle=rot, \
rotation_point="center", color=color, fill=False)
truth_boxes.append(rectangle)
# Create a figure with two subplots
fig, axs = plt.subplots(1, 2, figsize=(20, 10))
# Create a scatter plot of the point cloud (bird's eye view) in the left subplot
axs[0].scatter(points[:, 0], points[:, 1], s=0.1, c=points[:, 2], cmap='viridis')
# Add the bounding boxes to the right subplot
for box in truth_boxes:
axs[0].add_patch(box)
# Set plot limits and labels for the left subplot
axs[0].set_xlim(-5, 32)
axs[0].set_ylim(-5, 25)
axs[0].set_title("Truth Label")
axs[0].set_xticks([])
axs[0].set_yticks([])
# Create a scatter plot of the point cloud (bird's eye view) in the right subplot
axs[1].scatter(points[:, 0], points[:, 1], s=0.1, c=points[:, 2], cmap='viridis')
# Add the bounding boxes to the right subplot
for box in pred_boxes:
axs[1].add_patch(box)
# Set plot limits and labels for the right subplot
axs[1].set_xlim(-5, 32)
axs[1].set_ylim(-5, 25)
axs[1].set_title("Predicted Label")
axs[1].set_xticks([])
axs[1].set_yticks([])
# Save the figure with a unique name based on the input binary file
figure_filename = os.path.splitext(bin_file)[0] + '_visualization.png'
figure_path = os.path.join(output_dir, figure_filename)
plt.savefig(figure_path)
print(f'Saved visualization for {bin_file} in {figure_path}')
# Close the figures to prevent memory consumption
plt.close('all')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Visualize 3D point clouds with bounding boxes')
parser.add_argument('--bin_dir', type=str, required=True, help='Directory containing binary point cloud files')
parser.add_argument('--pred_dir', type=str, required=True, help='Directory containing prediction text files')
parser.add_argument('--truth_dir', type=str, required=True, help='Directory containing truth label text files')
parser.add_argument('--output_dir', type=str, required=True, help='Directory to save visualization figures')
args = parser.parse_args()
visualize_3d_point_cloud(args.bin_dir, args.pred_dir, args.truth_dir, args.output_dir)