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