基于立体图像视差图计算物体实际距离的两类技术问题咨询
Hey, let's break down your two questions step by step, using your code as a reference:
1. Why is my calculated Depth negative?
There are two main reasons for negative depth values in your implementation:
- OpenCV StereoBM's disparity output format: The
stereo.compute()method returns a 16-bit signed integer disparity map. Actual valid disparity values are stored asdisparity_value / 16, and failed matches will result in negative values. You’re using raw integer values directly in your depth calculation, so negative disparities lead to negative depths. - Left/right image order mismatch:
StereoBM.compute()requires the first parameter to be the left image and the second to be the right image. If you swapped them, disparity would be calculated asright_x - left_x(instead of the correctleft_x - right_x), resulting in negative values across the board.
To fix this, normalize the disparity map and filter out invalid values first. Here’s adjusted code:
import numpy as np import cv2 from matplotlib import pyplot as plt %matplotlib inline imgL = cv2.imread('C:/Users/Akash Jain/Documents/ZED/LeftDepth/left000005.png', 0) imgR = cv2.imread('C:/Users/Akash Jain/Documents/ZED/RightDepth/right000005.png', 0) stereo = cv2.StereoBM_create(numDisparities=16, blockSize=5) disparity = stereo.compute(imgL, imgR) # Convert to float and restore actual disparity values (divide by 16) disparity = disparity.astype(np.float32) / 16.0 # Filter out invalid (negative/zero) disparities valid_mask = disparity > 0.0 # Calculate depth only for valid pixels baseline = 0.12 # ZED's baseline is 12cm = 0.12m focal_length_pix = 672 # Use your actual pixel focal length D = np.zeros_like(disparity) D[valid_mask] = (baseline * focal_length_pix) / disparity[valid_mask] print("Disparity:", disparity) print("Depth:", D) plt.imshow(disparity, 'gray') plt.show()
2. How to get the actual object distance (in meters) from the Depth matrix?
The Depth matrix gives per-pixel distance values, so you need to isolate the pixels corresponding to your target object first, then compute a representative value (average or median works best) for that region. Here are two practical approaches:
Option 1: Manual ROI selection (simple for testing)
If you know the object’s approximate position, define a Region of Interest (ROI) and calculate the average depth in that area:
# Adjust these coordinates to match your object's position in the image x1, y1 = 100, 200 # Top-left corner x2, y2 = 300, 400 # Bottom-right corner # Extract ROI from depth matrix roi_depth = D[y1:y2, x1:x2] # Filter out invalid depth values valid_roi_depth = roi_depth[roi_depth > 0] # Use median for robustness against outliers, or mean for simplicity object_distance = np.median(valid_roi_depth) print(f"Object distance to camera: {object_distance:.2f} meters")
Option 2: Automatic object detection (for real-world use)
Use image segmentation or contour detection to automatically isolate the object’s pixels:
# Threshold the left image to highlight the object (adjust threshold value as needed) ret, thresh = cv2.threshold(imgL, 127, 255, cv2.THRESH_BINARY_INV) # Find object contours contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if contours: # Assume the largest contour is your target object max_contour = max(contours, key=cv2.contourArea) # Create a mask for the object mask = np.zeros_like(D) cv2.drawContours(mask, [max_contour], 0, 255, -1) # Extract valid depth values from the masked region valid_depth = D[mask == 255] valid_depth = valid_depth[valid_depth > 0] if len(valid_depth) > 0: object_distance = np.median(valid_depth) print(f"Object distance to camera: {object_distance:.2f} meters") else: print("No valid depth values found for the object.") else: print("No object contours detected.")
Critical parameter check
Ensure your focal length value is correct: The formula Depth = (Baseline * Focal Length) / Disparity requires the focal length to be in pixel units (not physical units like meters). For ZED cameras, get the exact pixel focal length from the ZED SDK or camera calibration data—your current 0.70 * 672 seems off, so double-check this to guarantee meter-scale accuracy.
内容的提问来源于stack exchange,提问作者Akash

