@@ -299,9 +299,27 @@ def compute_depth_bounds(depth_values: np.ndarray) -> Tuple[float, float, float]
299299 Returns:
300300 Tuple of (z_center, z_min, z_max) representing the object's depth
301301 """
302+ # Basic input validation
303+ if not isinstance (depth_values , np .ndarray ):
304+ return 0.0 , 0.0 , 0.0
305+
306+ if len (depth_values ) == 0 :
307+ return 0.0 , 0.0 , 0.0
308+
309+ # Ensure all values are numeric and finite
310+ try :
311+ depth_values = np .asarray (depth_values , dtype = np .float64 )
312+ valid_mask = np .isfinite (depth_values ) & (depth_values > 0 )
313+ depth_values = depth_values [valid_mask ]
314+ except (ValueError , TypeError ):
315+ return 0.0 , 0.0 , 0.0
316+
317+ if len (depth_values ) == 0 :
318+ return 0.0 , 0.0 , 0.0
319+
302320 if len (depth_values ) < 4 :
303- z_center = np .median (depth_values )
304- return z_center , np .min (depth_values ), np .max (depth_values )
321+ z_center = float ( np .median (depth_values ) )
322+ return z_center , float ( np .min (depth_values )), float ( np .max (depth_values ) )
305323
306324 sorted_depths = np .sort (depth_values )
307325 n = len (sorted_depths )
@@ -372,7 +390,7 @@ def compute_depth_bounds(depth_values: np.ndarray) -> Tuple[float, float, float]
372390 z_min = z_center - half_min
373391 z_max = z_center + half_min
374392
375- return z_center , z_min , z_max
393+ return float ( z_center ), float ( z_min ), float ( z_max )
376394
377395 @staticmethod
378396 def _density_based_cluster (
@@ -505,6 +523,12 @@ def convert_bb_to_3d(
505523 @param detection 2D detection to convert
506524 @return 3D bounding box or None if conversion fails
507525 """
526+ # Basic input validations
527+ if depth_image is None or not isinstance (depth_image , np .ndarray ):
528+ return None
529+
530+ if depth_image .size == 0 :
531+ return None
508532
509533 center_x = int (detection .bbox .center .position .x )
510534 center_y = int (detection .bbox .center .position .y )
@@ -541,11 +565,23 @@ def convert_bb_to_3d(
541565 pixel_coords = np .column_stack ([x_grid .flatten (), y_grid .flatten ()])
542566
543567 roi = roi / self .depth_image_units_divisor # Convert to meters
568+
569+ # Validate that division did not produce NaN or inf
570+ if not np .any (np .isfinite (roi )):
571+ return None
572+
544573 if not np .any (roi ):
545574 return None
546575
547576 # Extract valid depth values with their spatial positions
548577 valid_depths = roi .flatten ()
578+
579+ # Ensure correct numeric type
580+ try :
581+ valid_depths = np .asarray (valid_depths , dtype = np .float64 )
582+ except (ValueError , TypeError ):
583+ return None
584+
549585 valid_mask = (valid_depths > 0 ) & np .isfinite (valid_depths )
550586 valid_depths = valid_depths [valid_mask ]
551587 valid_coords = pixel_coords [valid_mask ]
@@ -564,18 +600,26 @@ def convert_bb_to_3d(
564600 valid_depths , spatial_weights
565601 )
566602
567- if z == 0 :
603+ if not np . isfinite ( z ) or z == 0 :
568604 return None
569605
570606 # Compute height (y-axis) statistics from actual 3D points
571607 y_center , y_min , y_max = Detect3DNode ._compute_height_bounds (
572608 valid_coords , valid_depths , spatial_weights , depth_info
573609 )
610+
611+ # Validate results
612+ if not all (np .isfinite ([y_center , y_min , y_max ])):
613+ return None
574614
575615 # Compute width (x-axis) statistics from actual 3D points
576616 x_center , x_min , x_max = Detect3DNode ._compute_width_bounds (
577617 valid_coords , valid_depths , spatial_weights , depth_info
578618 )
619+
620+ # Validate results
621+ if not all (np .isfinite ([x_center , x_min , x_max ])):
622+ return None
579623
580624 # All dimensions come from actual 3D point analysis
581625 x = x_center
@@ -646,6 +690,16 @@ def _compute_height_bounds(
646690 Returns:
647691 Tuple of (y_center, y_min, y_max) in meters
648692 """
693+ # Input validations
694+ try :
695+ valid_depths = np .asarray (valid_depths , dtype = np .float64 )
696+ spatial_weights = np .asarray (spatial_weights , dtype = np .float64 )
697+ except (ValueError , TypeError ):
698+ return 0.0 , 0.0 , 0.0
699+
700+ if len (valid_coords ) == 0 or len (valid_depths ) == 0 :
701+ return 0.0 , 0.0 , 0.0
702+
649703 if len (valid_coords ) < 4 :
650704 # Fallback: just use simple projection
651705 k = depth_info .k
@@ -657,8 +711,17 @@ def _compute_height_bounds(
657711 # Convert pixel coordinates to 3D y-coordinates
658712 k = depth_info .k
659713 py , fy = k [5 ], k [4 ]
714+
715+ # Validate camera parameters
716+ if fy == 0 :
717+ return 0.0 , 0.0 , 0.0
718+
660719 y_coords_pixel = valid_coords [:, 1 ]
661720 y_3d = valid_depths * (y_coords_pixel - py ) / fy
721+
722+ # Validate result
723+ if not np .any (np .isfinite (y_3d )):
724+ return 0.0 , 0.0 , 0.0
662725
663726 # Filter outliers using robust statistics
664727 # Compute weighted median as reference
@@ -728,7 +791,7 @@ def _compute_height_bounds(
728791 y_min = y_center - half_min
729792 y_max = y_center + half_min
730793
731- return y_center , y_min , y_max
794+ return float ( y_center ), float ( y_min ), float ( y_max )
732795
733796 @staticmethod
734797 def _compute_width_bounds (
@@ -750,6 +813,16 @@ def _compute_width_bounds(
750813 Returns:
751814 Tuple of (x_center, x_min, x_max) in meters
752815 """
816+ # Input validations
817+ try :
818+ valid_depths = np .asarray (valid_depths , dtype = np .float64 )
819+ spatial_weights = np .asarray (spatial_weights , dtype = np .float64 )
820+ except (ValueError , TypeError ):
821+ return 0.0 , 0.0 , 0.0
822+
823+ if len (valid_coords ) == 0 or len (valid_depths ) == 0 :
824+ return 0.0 , 0.0 , 0.0
825+
753826 if len (valid_coords ) < 4 :
754827 # Fallback: just use simple projection
755828 k = depth_info .k
@@ -761,8 +834,17 @@ def _compute_width_bounds(
761834 # Convert pixel coordinates to 3D x-coordinates
762835 k = depth_info .k
763836 px , fx = k [2 ], k [0 ]
837+
838+ # Validate camera parameters
839+ if fx == 0 :
840+ return 0.0 , 0.0 , 0.0
841+
764842 x_coords_pixel = valid_coords [:, 0 ]
765843 x_3d = valid_depths * (x_coords_pixel - px ) / fx
844+
845+ # Validate result
846+ if not np .any (np .isfinite (x_3d )):
847+ return 0.0 , 0.0 , 0.0
766848
767849 # Filter outliers using robust statistics
768850 # Compute weighted median as reference
@@ -839,7 +921,7 @@ def _compute_width_bounds(
839921 x_min = x_center - half_min
840922 x_max = x_center + half_min
841923
842- return x_center , x_min , x_max
924+ return float ( x_center ), float ( x_min ), float ( x_max )
843925
844926 @staticmethod
845927 def _compute_depth_bounds_weighted (
@@ -855,9 +937,27 @@ def _compute_depth_bounds_weighted(
855937 Returns:
856938 Tuple of (z_center, z_min, z_max) representing the object's depth
857939 """
940+ # Input validations
941+ try :
942+ depth_values = np .asarray (depth_values , dtype = np .float64 )
943+ spatial_weights = np .asarray (spatial_weights , dtype = np .float64 )
944+ except (ValueError , TypeError ):
945+ return 0.0 , 0.0 , 0.0
946+
947+ if len (depth_values ) == 0 :
948+ return 0.0 , 0.0 , 0.0
949+
950+ # Validate that all values are finite
951+ valid_mask = np .isfinite (depth_values ) & np .isfinite (spatial_weights )
952+ depth_values = depth_values [valid_mask ]
953+ spatial_weights = spatial_weights [valid_mask ]
954+
955+ if len (depth_values ) == 0 :
956+ return 0.0 , 0.0 , 0.0
957+
858958 if len (depth_values ) < 4 :
859- z_center = np .median (depth_values )
860- return z_center , np .min (depth_values ), np .max (depth_values )
959+ z_center = float ( np .median (depth_values ) )
960+ return z_center , float ( np .min (depth_values )), float ( np .max (depth_values ) )
861961
862962 # Step 1: Multi-scale histogram analysis for robust mode detection
863963 depth_range = np .ptp (depth_values )
@@ -988,7 +1088,7 @@ def _compute_depth_bounds_weighted(
9881088 z_min = z_center - half_min
9891089 z_max = z_center + half_min
9901090
991- return z_center , z_min , z_max
1091+ return float ( z_center ), float ( z_min ), float ( z_max )
9921092
9931093 def convert_keypoints_to_3d (
9941094 self ,
@@ -1006,6 +1106,9 @@ def convert_keypoints_to_3d(
10061106 @param detection Detection containing 2D keypoints
10071107 @return Array of 3D keypoints
10081108 """
1109+ # Validate input
1110+ if depth_image is None or not isinstance (depth_image , np .ndarray ):
1111+ return KeyPoint3DArray ()
10091112
10101113 # Build an array of 2D keypoints
10111114 keypoints_2d = np .array (
@@ -1016,8 +1119,20 @@ def convert_keypoints_to_3d(
10161119
10171120 # Sample depth image and project to 3D
10181121 z = depth_image [u , v ]
1122+
1123+ # Validate and convert to float
1124+ try :
1125+ z = np .asarray (z , dtype = np .float64 )
1126+ except (ValueError , TypeError ):
1127+ return KeyPoint3DArray ()
1128+
10191129 k = depth_info .k
10201130 px , py , fx , fy = k [2 ], k [5 ], k [0 ], k [4 ]
1131+
1132+ # Validate camera parameters
1133+ if fx == 0 or fy == 0 :
1134+ return KeyPoint3DArray ()
1135+
10211136 x = z * (v - px ) / fx
10221137 y = z * (u - py ) / fy
10231138 points_3d = (
@@ -1027,11 +1142,11 @@ def convert_keypoints_to_3d(
10271142 # Generate message
10281143 msg_array = KeyPoint3DArray ()
10291144 for p , d in zip (points_3d , detection .keypoints .data ):
1030- if not np .isnan (p ).any ():
1145+ if not np .isnan (p ).any () and np . all ( np . isfinite ( p )) :
10311146 msg = KeyPoint3D ()
1032- msg .point .x = p [0 ]
1033- msg .point .y = p [1 ]
1034- msg .point .z = p [2 ]
1147+ msg .point .x = float ( p [0 ])
1148+ msg .point .y = float ( p [1 ])
1149+ msg .point .z = float ( p [2 ])
10351150 msg .id = d .id
10361151 msg .score = d .score
10371152 msg_array .data .append (msg )
0 commit comments