cargo_height_measure.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import time
  2. import cv2
  3. import numpy as np
  4. from pyorbbecsdk import *
  5. ESC_KEY = 27
  6. PRINT_INTERVAL = 1 # seconds
  7. MIN_DEPTH = 500 # mm
  8. MAX_DEPTH = 4000 # mm
  9. ROI_WIDTH_CM = 10.0 # cm
  10. ROI_HEIGHT_CM = 12.0 # cm
  11. MEDIAN_BLUR_KSIZE = 5 # odd number, 0 to disable
  12. MORPH_OPEN_KSIZE = 3 # odd number, 0 to disable
  13. NEAREST_PERCENTILE = 5 # use low percentile to suppress isolated noise (0 for raw min)
  14. class TemporalFilter:
  15. def __init__(self, alpha):
  16. self.alpha = alpha
  17. self.previous_frame = None
  18. def process(self, frame):
  19. if self.previous_frame is None:
  20. result = frame
  21. else:
  22. result = cv2.addWeighted(frame, self.alpha, self.previous_frame, 1 - self.alpha, 0)
  23. self.previous_frame = result
  24. return result
  25. def main():
  26. config = Config()
  27. pipeline = Pipeline()
  28. temporal_filter = TemporalFilter(alpha=0.5)
  29. try:
  30. profile_list = pipeline.get_stream_profile_list(OBSensorType.DEPTH_SENSOR)
  31. assert profile_list is not None
  32. depth_profile = profile_list.get_default_video_stream_profile()
  33. assert depth_profile is not None
  34. print("depth profile: ", depth_profile)
  35. depth_intrinsics = depth_profile.get_intrinsic()
  36. config.enable_stream(depth_profile)
  37. except Exception as e:
  38. print(e)
  39. return
  40. pipeline.start(config)
  41. last_print_time = time.time()
  42. while True:
  43. try:
  44. frames = pipeline.wait_for_frames(100)
  45. if frames is None:
  46. continue
  47. depth_frame = frames.get_depth_frame()
  48. if depth_frame is None:
  49. continue
  50. depth_format = depth_frame.get_format()
  51. if depth_format != OBFormat.Y16:
  52. print("depth format is not Y16")
  53. continue
  54. width = depth_frame.get_width()
  55. height = depth_frame.get_height()
  56. scale = depth_frame.get_depth_scale()
  57. depth_data = np.frombuffer(depth_frame.get_data(), dtype=np.uint16)
  58. depth_data = depth_data.reshape((height, width))
  59. depth_data = depth_data.astype(np.float32) * scale
  60. depth_data = np.where((depth_data > MIN_DEPTH) & (depth_data < MAX_DEPTH), depth_data, 0)
  61. depth_data = depth_data.astype(np.uint16)
  62. if MEDIAN_BLUR_KSIZE and MEDIAN_BLUR_KSIZE % 2 == 1:
  63. depth_data = cv2.medianBlur(depth_data, MEDIAN_BLUR_KSIZE)
  64. if MORPH_OPEN_KSIZE and MORPH_OPEN_KSIZE % 2 == 1:
  65. kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (MORPH_OPEN_KSIZE, MORPH_OPEN_KSIZE))
  66. valid_mask = (depth_data > 0).astype(np.uint8)
  67. valid_mask = cv2.morphologyEx(valid_mask, cv2.MORPH_OPEN, kernel)
  68. depth_data = np.where(valid_mask > 0, depth_data, 0).astype(np.uint16)
  69. # Apply temporal filtering
  70. depth_data = temporal_filter.process(depth_data)
  71. center_y = height // 2
  72. center_x = width // 2
  73. center_distance = depth_data[center_y, center_x]
  74. if center_distance == 0:
  75. continue
  76. center_distance_m = center_distance / 1000.0
  77. half_width_m = (ROI_WIDTH_CM / 100.0) / 2.0
  78. half_height_m = (ROI_HEIGHT_CM / 100.0) / 2.0
  79. half_width_px = int(depth_intrinsics.fx * half_width_m / center_distance_m)
  80. half_height_px = int(depth_intrinsics.fy * half_height_m / center_distance_m)
  81. if half_width_px <= 0 or half_height_px <= 0:
  82. continue
  83. half_width_px = min(half_width_px, center_x, width - center_x - 1)
  84. half_height_px = min(half_height_px, center_y, height - center_y - 1)
  85. if half_width_px <= 0 or half_height_px <= 0:
  86. continue
  87. x_start = center_x - half_width_px
  88. x_end = center_x + half_width_px + 1
  89. y_start = center_y - half_height_px
  90. y_end = center_y + half_height_px + 1
  91. roi = depth_data[y_start:y_end, x_start:x_end]
  92. valid_values = roi[(roi >= MIN_DEPTH) & (roi <= MAX_DEPTH)]
  93. if valid_values.size == 0:
  94. nearest_distance = 0
  95. else:
  96. if NEAREST_PERCENTILE and 0 < NEAREST_PERCENTILE < 100:
  97. nearest_distance = int(np.percentile(valid_values, NEAREST_PERCENTILE))
  98. else:
  99. nearest_distance = int(valid_values.min())
  100. # Find nearest point in ROI for visualization
  101. nearest_point = None
  102. if nearest_distance > 0:
  103. roi_mask = (roi >= MIN_DEPTH) & (roi <= MAX_DEPTH)
  104. roi_candidate = np.where(roi_mask, roi, np.iinfo(np.uint16).max)
  105. if NEAREST_PERCENTILE and 0 < NEAREST_PERCENTILE < 100:
  106. roi_candidate = np.where(roi_candidate <= nearest_distance, roi_candidate, np.iinfo(np.uint16).max)
  107. min_idx = np.argmin(roi_candidate)
  108. min_val = roi_candidate.flat[min_idx]
  109. if min_val != np.iinfo(np.uint16).max:
  110. min_y, min_x = np.unravel_index(min_idx, roi_candidate.shape)
  111. nearest_point = (x_start + min_x, y_start + min_y)
  112. current_time = time.time()
  113. if current_time - last_print_time >= PRINT_INTERVAL:
  114. print(f"nearest distance in {ROI_WIDTH_CM}cm x {ROI_HEIGHT_CM}cm area: ", nearest_distance)
  115. last_print_time = current_time
  116. depth_image = cv2.normalize(depth_data, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
  117. depth_image = cv2.applyColorMap(depth_image, cv2.COLORMAP_JET)
  118. cv2.rectangle(
  119. depth_image,
  120. (x_start, y_start),
  121. (x_end - 1, y_end - 1),
  122. (0, 255, 0),
  123. 2,
  124. )
  125. if nearest_point is not None:
  126. cv2.circle(depth_image, nearest_point, 4, (0, 0, 0), -1)
  127. cv2.circle(depth_image, nearest_point, 6, (0, 255, 255), 2)
  128. label = f"nearest: {nearest_distance} mm"
  129. cv2.putText(
  130. depth_image,
  131. label,
  132. (10, 30),
  133. cv2.FONT_HERSHEY_SIMPLEX,
  134. 0.8,
  135. (255, 255, 255),
  136. 2,
  137. cv2.LINE_AA,
  138. )
  139. center_label = f"center: {int(center_distance)} mm"
  140. cv2.putText(
  141. depth_image,
  142. center_label,
  143. (10, 60),
  144. cv2.FONT_HERSHEY_SIMPLEX,
  145. 0.8,
  146. (255, 255, 255),
  147. 2,
  148. cv2.LINE_AA,
  149. )
  150. cv2.imshow("Depth Viewer", depth_image)
  151. key = cv2.waitKey(1)
  152. if key == ord('q') or key == ESC_KEY:
  153. break
  154. except KeyboardInterrupt:
  155. break
  156. cv2.destroyAllWindows()
  157. pipeline.stop()
  158. if __name__ == "__main__":
  159. main()