Skip to content

Commit d2a80dc

Browse files
committed
add test against YOLO
1 parent 727b1d4 commit d2a80dc

2 files changed

Lines changed: 117 additions & 15 deletions

File tree

fps_demo/viewer.py

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -165,34 +165,62 @@ def main():
165165
rect_pos[1] -= 1
166166
if keys[pygame.K_SPACE]:
167167
# compute the prediction, we get the same array but with different estimated w,h in cm (two last columns)
168-
prediction = np.zeros((YOLO_data.shape[0], 7))
168+
# prediction = np.zeros((YOLO_data.shape[0], 7))
169+
# for i, line in enumerate(YOLO_data):
170+
# class_id, x_c, y_c, w, h, true_w, true_h = line
171+
# prediction[i, 0] = class_id
172+
# prediction[i, 1] = x_c
173+
# prediction[i, 2] = y_c
174+
175+
# if class_id != 0:
176+
# print(f"Skipping class {class_id} at line {i}")
177+
# continue
178+
179+
# # Convert to pixel coordinates
180+
# rect_x_estimation = int((x_c-w/2) * camera.resolution_px[0])
181+
# rect_y_estimation = int((y_c-h/2) * camera.resolution_px[1])
182+
# rect_width_estimation = int(w * camera.resolution_px[0])
183+
# rect_height_estimation = int(h * camera.resolution_px[1])
184+
185+
# # Estimate physical size in cm
186+
# largest_x, largest_y = get_largest_diameters(camera, rect_x_estimation, rect_y_estimation, rect_width_estimation, rect_height_estimation)
187+
# width_cm = largest_x * 100
188+
# height_cm = largest_y * 100
189+
190+
# prediction[i, 3] = width_cm
191+
# prediction[i, 4] = height_cm
192+
# prediction[i, 5] = true_w
193+
# prediction[i, 6] = true_h
194+
195+
# print(f'line {i}: predicted w={width_cm:.1f} cm, h={height_cm:.1f} cm, actual w={true_w:.1f} cm, h={true_h:.1f} cm')
196+
197+
# Above: old wrong version
198+
199+
prediction = []
169200
for i, line in enumerate(YOLO_data):
170201
class_id, x_c, y_c, w, h, true_w, true_h = line
171-
prediction[i, 0] = class_id
172-
prediction[i, 1] = x_c
173-
prediction[i, 2] = y_c
174-
175202
if class_id != 0:
176203
print(f"Skipping class {class_id} at line {i}")
177204
continue
178205

179-
# Convert to pixel coordinates
180-
rect_x_estimation = int((x_c-w/2) * camera.resolution_px[0])
181-
rect_y_estimation = int((y_c-h/2) * camera.resolution_px[1])
206+
rect_x_estimation = int((x_c - w / 2) * camera.resolution_px[0])
207+
rect_y_estimation = int((y_c - h / 2) * camera.resolution_px[1])
182208
rect_width_estimation = int(w * camera.resolution_px[0])
183209
rect_height_estimation = int(h * camera.resolution_px[1])
184210

185-
# Estimate physical size in cm
186-
largest_x, largest_y = get_largest_diameters(camera, rect_x_estimation, rect_y_estimation, rect_width_estimation, rect_height_estimation)
211+
largest_x, largest_y = get_largest_diameters(
212+
camera, rect_x_estimation, rect_y_estimation,
213+
rect_width_estimation, rect_height_estimation
214+
)
187215
width_cm = largest_x * 100
188216
height_cm = largest_y * 100
189217

190-
prediction[i, 3] = width_cm
191-
prediction[i, 4] = height_cm
192-
prediction[i, 5] = true_w
193-
prediction[i, 6] = true_h
218+
prediction.append([
219+
class_id, x_c, y_c,
220+
width_cm, height_cm,
221+
true_w, true_h
222+
])
194223

195-
print(f'line {i}: predicted w={width_cm:.1f} cm, h={height_cm:.1f} cm, actual w={true_w:.1f} cm, h={true_h:.1f} cm')
196224

197225
# Now compute error stats
198226
df = pd.DataFrame(prediction, columns=[

tests/test_against_YOLO.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import numpy as np
2+
import pandas as pd
3+
from core_geometry.camera_model import Camera
4+
from core_geometry.intersection import get_largest_diameters
5+
6+
def test_physical_size_estimation_accuracy(include_non_plastic=False):
7+
df = pd.read_csv("data/yolo_groundtruth_data.csv")
8+
9+
if not include_non_plastic:
10+
df = df[df["class"] == 0] # Only class 0
11+
12+
WIDTH, HEIGHT = 192 * 4, 108 * 4
13+
f_mm = 4.6
14+
sensor_w_mm = 5.6
15+
sensor_h_mm = 3.2
16+
CAMERA_HEIGHT = 2.12
17+
18+
camera = Camera((WIDTH, HEIGHT), position=[0.0, CAMERA_HEIGHT, 0.0])
19+
camera.set_focal_length_and_sensor(f_mm / 1000, (sensor_w_mm / 1000, sensor_h_mm / 1000))
20+
camera.yaw_deg = 0.0
21+
camera.pitch_deg = -25.5
22+
23+
predictions = []
24+
25+
for _, row in df.iterrows():
26+
x_c, y_c, w, h, true_w, true_h = row[["x_c", "y_c", "w", "h", "true_width_cm", "true_height_cm"]]
27+
rect_x = int((x_c - w / 2) * camera.resolution_px[0])
28+
rect_y = int((y_c - h / 2) * camera.resolution_px[1])
29+
rect_width = int(w * camera.resolution_px[0])
30+
rect_height = int(h * camera.resolution_px[1])
31+
32+
largest_x, largest_y = get_largest_diameters(camera, rect_x, rect_y, rect_width, rect_height)
33+
pred_w = largest_x * 100
34+
pred_h = largest_y * 100
35+
36+
predictions.append((true_w, true_h, pred_w, pred_h))
37+
38+
# # If we always predict (0,0), we get the following:
39+
# predictions.append((true_w, true_h, 0, 0))
40+
# # MAE Width (cm): 28.31, MAE Height (cm): 7.97
41+
# # Standard Deviation Width (cm): 4.06, Standard Deviation Height (cm): 1.24
42+
# # Average Relative Error Width: 1.00, Average Relative Error Height: 1.00
43+
# # MAE Width (cm): 83.32, MAE Height (cm): 18.61
44+
# # Standard Deviation Width (cm): 92.00, Standard Deviation Height (cm): 17.82
45+
# # Average Relative Error Width: 1.00, Average Relative Error Height: 1.00
46+
# # Hence, the test should at least ensure values lower than these.
47+
48+
arr = np.array(predictions)
49+
err_w = arr[:, 2] - arr[:, 0]
50+
err_h = arr[:, 3] - arr[:, 1]
51+
52+
mae_w = np.mean(np.abs(err_w))
53+
mae_h = np.mean(np.abs(err_h))
54+
std_err_h = np.std(err_h, ddof=1)
55+
std_err_w = np.std(err_w, ddof=1)
56+
avg_rel_err_w = np.mean(np.abs(err_w / arr[:, 0]))
57+
avg_rel_err_h = np.mean(np.abs(err_h / arr[:, 1]))
58+
59+
# # Uncomment if you want to see the results
60+
# print(f"MAE Width (cm): {mae_w:.2f}, MAE Height (cm): {mae_h:.2f}")
61+
# print(f"Standard Deviation Width (cm): {std_err_w:.2f}, Standard Deviation Height (cm): {std_err_h:.2f}")
62+
# print(f"Average Relative Error Width: {np.mean(np.abs(err_w / arr[:, 0])):.2f}, Average Relative Error Height: {np.mean(np.abs(err_h / arr[:, 1])):.2f}")
63+
64+
assert mae_w < 10, "MAE for width too high"
65+
assert mae_h < 5, "MAE for height too high"
66+
assert std_err_w < 15, "Standard deviation for width too high"
67+
assert std_err_h < 5, "Standard deviation for height too high"
68+
assert avg_rel_err_w < 0.15, "Average relative error for width too high"
69+
assert avg_rel_err_h < 0.15, "Average relative error for height too high"
70+
71+
if __name__ == "__main__":
72+
test_physical_size_estimation_accuracy()
73+
test_physical_size_estimation_accuracy(include_non_plastic=True)
74+
print("Test passed successfully, results do not diverge too much from YOLO ground truth data.")

0 commit comments

Comments
 (0)