Как измерять объекты с помощью Python и библиотеки pyorbbecsdk с камерами глубины?Python

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Как измерять объекты с помощью Python и библиотеки pyorbbecsdk с камерами глубины?

Сообщение Anonymous »

У меня есть камера глубины FemtoMega, которая поддерживается SDK orbbec, который также имеет оболочку Python: https://github.com/orbbec/pyorbbecsdk. Я пытаюсь создать программу на Python, которая может измерять длину, ширину и высоту объектов (которые всегда будут квадратными/прямоугольными). Ниже приводится то, что мне удалось сделать, используя примеры из SDK и помощь ChatGPT, но я не могу сфокусироваться на одном объекте — я не знаю, что на самом деле измеряет камера. Может ли кто-нибудь помочь мне с этим? Информации о том, как сделать что-то подобное, очень мало, и исходя из опыта работы с JS, я не знаю, как действовать.
import time
import cv2
import numpy as np
from pyorbbecsdk import Config, OBSensorType, Pipeline, ColorFrame, FrameSet

ESC_KEY = 27
PRINT_INTERVAL = 1 # seconds
MIN_DEPTH = 20 # 20mm
MAX_DEPTH = 10000 # 10000mm

class TemporalFilter:
def __init__(self, alpha):
self.alpha = alpha
self.previous_frame = None

def process(self, frame):
if self.previous_frame is None:
result = frame
else:
result = cv2.addWeighted(frame, self.alpha, self.previous_frame, 1 - self.alpha, 0)
self.previous_frame = result
return result

def get_stream_dimensions(pipeline, sensor_type=OBSensorType.DEPTH_SENSOR):
"""
Retrieves the dimensions (width, height) of the specified sensor's stream.

:param pipeline: The Pipeline object.
:param sensor_type: The sensor type (default is DEPTH_SENSOR).
:return: Tuple (width, height) if successful, else (None, None).
"""
profile_list = pipeline.get_stream_profile_list(sensor_type)
if profile_list is None:
print(f"No stream profiles found for sensor type: {sensor_type}")
return None, None

stream_profile = profile_list.get_default_video_stream_profile()
if stream_profile is None:
print(f"No default video stream profile found for sensor type: {sensor_type}")
return None, None

# Use getter methods instead of direct attribute access
width = stream_profile.get_width()
height = stream_profile.get_height()
print(f"Stream Dimensions: {width}x{height}")
return width, height

def print_sample_depth_values(depth_data, width, height):
"""
Prints sample depth values from different regions of the frame.

:param depth_data: Numpy array of depth data.
:param width: Width of the depth frame.
:param height: Height of the depth frame.
"""
sample_points = [
(0, 0), # Top-left corner
(height // 2, width // 2), # Center
(height - 1, width - 1), # Bottom-right corner
(height // 4, width // 4), # Quarter position
(3 * height // 4, 3 * width // 4) # Three-quarters position
]

print("Sample Depth Values:")
for y, x in sample_points:
distance = depth_data[y, x]
print(f" Point ({x}, {y}): {distance} mm")

def preprocess_depth_data(depth_data, lower_bound=MIN_DEPTH, upper_bound=MAX_DEPTH):
"""
Applies preprocessing steps to the depth data, including thresholding.

:param depth_data: Numpy array of raw depth data.
:param lower_bound: Minimum depth to consider (in mm).
:param upper_bound: Maximum depth to consider (in mm).
:return: Preprocessed binary image for contour detection.
"""
# Apply Gaussian Blur to reduce noise
blurred = cv2.GaussianBlur(depth_data, (5, 5), 0)

# Apply binary thresholding based on depth bounds
thresh = cv2.inRange(blurred, lower_bound, upper_bound)

return thresh

def preprocess_color_data(color_frame):
"""
Converts color frame to HSV and creates a mask to filter out the pallet.

:param color_frame: ColorFrame object.
:return: Binary mask where the pallet is masked out.
"""
color_data = np.frombuffer(color_frame.get_data(), dtype=np.uint8)
color_data = color_data.reshape((color_frame.get_height(), color_frame.get_width(), 3))
hsv = cv2.cvtColor(color_data, cv2.COLOR_BGR2HSV)

# Define the color range for the pallet (e.g., brown)
lower_brown = np.array([10, 100, 20])
upper_brown = np.array([20, 255, 200])

# Create mask to exclude the pallet
mask = cv2.inRange(hsv, lower_brown, upper_brown)
mask_inv = cv2.bitwise_not(mask)

return mask_inv

def detect_and_calculate_dimensions(depth_data, depth_scale, min_contour_area=500):
"""
Detects the largest object in the depth data and calculates its dimensions.

:param depth_data: Numpy array of depth data.
:param depth_scale: Scale factor to convert depth units to millimeters.
:param min_contour_area: Minimum area to consider a contour valid.
:return: Tuple containing dimensions dictionary and largest contour or None.
"""
# Preprocess depth data
thresh = preprocess_depth_data(depth_data)

# Find contours to detect objects
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

if contours:
# Filter out small contours based on area
valid_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > min_contour_area]
if not valid_contours:
print("No valid contours detected.")
return None

# Assume the largest valid contour corresponds to the object
largest_contour = max(valid_contours, key=cv2.contourArea)
x, y, w, h = cv2.boundingRect(largest_contour)

# Calculate center distance based on the bounding box center
center_y = y + h // 2
center_x = x + w // 2
center_distance = depth_data[center_y, center_x]

# Calculate object dimensions in millimeters
object_width = w * depth_scale
object_height = h * depth_scale

dimensions = {
"center_distance_mm": center_distance,
"width_mm": object_width,
"height_mm": object_height,
"bounding_box": (x, y, w, h)
}

return dimensions, largest_contour
else:
print("No contours found.")
return None

def main():
config = Config()
pipeline = Pipeline()
temporal_filter = TemporalFilter(alpha=0.5)
try:
# Retrieve and enable the depth stream profile
width, height = get_stream_dimensions(pipeline, OBSensorType.DEPTH_SENSOR)
if width is None or height is None:
print("Failed to get stream dimensions.")
return

profile_list = pipeline.get_stream_profile_list(OBSensorType.DEPTH_SENSOR)
depth_profile = profile_list.get_default_video_stream_profile()
print("Depth profile: ", depth_profile)

# Use the retrieved stream profile to enable the stream
config.enable_stream(depth_profile)
except Exception as e:
print(f"Error during stream configuration: {e}")
return

try:
pipeline.start(config)
last_print_time = time.time()
while True:
try:
frames = pipeline.wait_for_frames(1000)
if frames is None:
continue
depth_frame = frames.get_depth_frame()
if depth_frame is None:
continue

# Convert depth frame data to numpy array
depth_data = np.frombuffer(depth_frame.get_data(), dtype=np.uint16)
depth_data = depth_data.reshape((height, width))

# Apply scaling and filtering
depth_scale = depth_frame.get_depth_scale()
depth_data = depth_data.astype(np.float32) * depth_scale
depth_data = np.where((depth_data > MIN_DEPTH) & (depth_data < MAX_DEPTH), depth_data, 0)
depth_data = depth_data.astype(np.uint16)

# Apply temporal filtering
depth_data = temporal_filter.process(depth_data)

# Detect object and calculate dimensions
result = detect_and_calculate_dimensions(depth_data, depth_scale)
if result:
dimensions, largest_contour = result
center_distance = dimensions["center_distance_mm"]
object_width = dimensions["width_mm"]
object_height = dimensions["height_mm"]

# Print dimensions at defined intervals
current_time = time.time()
if current_time - last_print_time >= PRINT_INTERVAL:
print(f"Center distance: {center_distance} mm")
print(f"Object Width: {object_width:.2f} mm")
print(f"Object Height: {object_height:.2f} mm")
last_print_time = current_time

# Draw bounding box and center point on the depth image
depth_image = cv2.normalize(depth_data, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
depth_image = cv2.applyColorMap(depth_image, cv2.COLORMAP_JET)
x, y, w, h = dimensions["bounding_box"]
cv2.rectangle(depth_image, (x, y), (x + w, y + h), (0, 255, 0), 2)
center_y = y + h // 2
center_x = x + w // 2
cv2.circle(depth_image, (center_x, center_y), 5, (255, 0, 0), -1)
else:
center_distance = 0
print("No objects detected.")

# Display the depth image with annotations
cv2.imshow("Depth Viewer", depth_image)
key = cv2.waitKey(1)
if key == ord('q') or key == ESC_KEY:
print("Exiting the program.")
break
except KeyboardInterrupt:
print("Interrupted by user.")
break
except Exception as e:
print(f"An error occurred during streaming: {e}")
finally:
pipeline.stop()
cv2.destroyAllWindows()
print("Pipeline stopped and windows closed.")

if __name__ == "__main__":
main()



Подробнее здесь: https://stackoverflow.com/questions/792 ... epth-camer
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»