20
20
from collections import Counter
21
21
from abc import ABC , abstractmethod
22
22
23
+
24
+ AVERAGE_HEAD_WIDTH : float = 0.16 + 0.10 # 16cm + Margin Compensation
25
+
23
26
BOX_COLORS = [
24
27
[(216 , 67 , 21 ),"Front" ],
25
28
[(255 , 87 , 34 ),"Right-Front" ],
@@ -1029,6 +1032,13 @@ def check_positive(value):
1029
1032
help = \
1030
1033
'Enable depth map overlay. (Press D on the keyboard to switch modes)' ,
1031
1034
)
1035
+ parser .add_argument (
1036
+ '-ehd' ,
1037
+ '--enable_head_distance_measurement' ,
1038
+ action = 'store_true' ,
1039
+ help = \
1040
+ 'Enable Head distance measurement. (Press M on the keyboard to switch modes)' ,
1041
+ )
1032
1042
parser .add_argument (
1033
1043
'-oyt' ,
1034
1044
'--output_yolo_format_text' ,
@@ -1044,6 +1054,14 @@ def check_positive(value):
1044
1054
help = \
1045
1055
'Bounding box line width. Default: 2' ,
1046
1056
)
1057
+ parser .add_argument (
1058
+ '-chf' ,
1059
+ '--camera_horizontal_fov' ,
1060
+ type = int ,
1061
+ default = 90 ,
1062
+ help = \
1063
+ 'Camera horizontal FOV. Default: 90' ,
1064
+ )
1047
1065
args = parser .parse_args ()
1048
1066
1049
1067
# runtime check
@@ -1080,11 +1098,13 @@ def check_positive(value):
1080
1098
disable_render_classids : List [int ] = args .disable_render_classids
1081
1099
enable_face_mosaic : bool = args .enable_face_mosaic
1082
1100
enable_depth_map_overlay : bool = args .enable_depth_map_overlay
1101
+ enable_head_distance_measurement : bool = args .enable_head_distance_measurement
1083
1102
output_yolo_format_text : bool = args .output_yolo_format_text
1084
1103
execution_provider : str = args .execution_provider
1085
1104
inference_type : str = args .inference_type
1086
1105
inference_type = inference_type .lower ()
1087
1106
bounding_box_line_width : int = args .bounding_box_line_width
1107
+ camera_horizontal_fov : int = args .camera_horizontal_fov
1088
1108
providers : List [Tuple [str , Dict ] | str ] = None
1089
1109
1090
1110
if execution_provider == 'cpu' :
@@ -1461,6 +1481,45 @@ def check_positive(value):
1461
1481
cv2 .LINE_AA ,
1462
1482
)
1463
1483
1484
+ # Head distance
1485
+ if enable_head_distance_measurement and classid == 7 :
1486
+ focalLength : float = 0.0
1487
+ if (camera_horizontal_fov > 90 ):
1488
+ # Fisheye Camera (Equidistant Model)
1489
+ focalLength = debug_image_w / (camera_horizontal_fov * (math .pi / 180 ))
1490
+ else :
1491
+ # Normal camera (Pinhole Model)
1492
+ focalLength = debug_image_w / (2 * math .tan ((camera_horizontal_fov / 2 ) * (math .pi / 180 )))
1493
+ # Meters
1494
+ distance = (AVERAGE_HEAD_WIDTH * focalLength ) / abs (box .x2 - box .x1 )
1495
+
1496
+ cv2 .putText (
1497
+ debug_image ,
1498
+ f'{ distance :.3f} m' ,
1499
+ (
1500
+ box .x1 + 5 if box .x1 < debug_image_w else debug_image_w - 50 ,
1501
+ box .y1 + 20 if box .y1 - 5 > 0 else 20
1502
+ ),
1503
+ cv2 .FONT_HERSHEY_SIMPLEX ,
1504
+ 0.7 ,
1505
+ (255 , 255 , 255 ),
1506
+ 2 ,
1507
+ cv2 .LINE_AA ,
1508
+ )
1509
+ cv2 .putText (
1510
+ debug_image ,
1511
+ f'{ distance :.3f} m' ,
1512
+ (
1513
+ box .x1 + 5 if box .x1 < debug_image_w else debug_image_w - 50 ,
1514
+ box .y1 + 20 if box .y1 - 15 > 0 else 20
1515
+ ),
1516
+ cv2 .FONT_HERSHEY_SIMPLEX ,
1517
+ 0.7 ,
1518
+ (10 , 10 , 10 ),
1519
+ 1 ,
1520
+ cv2 .LINE_AA ,
1521
+ )
1522
+
1464
1523
# cv2.putText(
1465
1524
# debug_image,
1466
1525
# f'{box.score:.2f}',
@@ -1558,6 +1617,8 @@ def check_positive(value):
1558
1617
enable_face_mosaic = not enable_face_mosaic
1559
1618
elif key == 100 : # D, Depth map overlay mode switch
1560
1619
enable_depth_map_overlay = not enable_depth_map_overlay
1620
+ elif key == 109 : # M, Head distance measurement mode switch
1621
+ enable_head_distance_measurement = not enable_head_distance_measurement
1561
1622
1562
1623
if video_writer is not None :
1563
1624
video_writer .release ()
0 commit comments