You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python+OpenCV测量视频中不同平面两物体的欧氏距离

跨平面物体欧氏距离测量实现(Python+OpenCV)

核心思路

跨平面测量的关键是获取两个物体的真实3D世界坐标,再计算欧氏距离。针对单目/双目场景,分别给出可行方案:


1. 单目相机方案(低成本,依赖参考尺寸)

如果只有单目相机,必须利用已知真实尺寸的物体(比如乙炔/氧气钢瓶的标准直径)作为参考,结合相机内参完成像素到真实3D坐标的转换。

步骤1:相机标定(获取内参)

先通过棋盘格完成相机标定,得到内参矩阵K和畸变系数dist,这是所有3D计算的基础。
示例代码:

import cv2
import numpy as np

# 棋盘格参数(根据实际棋盘格调整)
chessboard_size = (9,6)
objp = np.zeros((chessboard_size[0]*chessboard_size[1],3), np.float32)
objp[:,:2] = np.mgrid[0:chessboard_size[0],0:chessboard_size[1]].T.reshape(-1,2)

objpoints = []  # 世界空间点集合
imgpoints = []  # 图像空间点集合

# 读取标定图片(替换为你的标定图路径)
images = [cv2.imread(f'calib_img_{i}.jpg') for i in range(10)]
for img in images:
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None)
    if ret:
        objpoints.append(objp)
        imgpoints.append(corners)

# 执行标定
ret, K, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)

步骤2:基于参考物体计算3D坐标

假设已知钢瓶的真实直径为real_diameter(比如0.2米),先检测钢瓶的像素直径pixel_diameter(通过目标识别的外接矩形宽度/高度),推导3D坐标后计算距离:

def get_3d_coords(center_pixel, pixel_diameter, real_diameter, K):
    # 计算深度Z:利用相似三角形原理
    Z = (real_diameter * K[0][0]) / pixel_diameter
    # 像素坐标转归一化相机坐标
    u, v = center_pixel
    cx, cy = K[0][2], K[1][2]
    fx, fy = K[0][0], K[1][1]
    X = (u - cx) * Z / fx
    Y = (v - cy) * Z / fy
    return np.array([X, Y, Z])

# 假设已通过目标识别得到以下参数
cylinder1_center = (250, 300)
cylinder1_pixel_d = 80
cylinder2_center = (450, 350)
cylinder2_pixel_d = 60
real_d = 0.2  # 钢瓶真实直径,单位米

# 获取两个钢瓶的3D坐标
coord1 = get_3d_coords(cylinder1_center, cylinder1_pixel_d, real_d, K)
coord2 = get_3d_coords(cylinder2_center, cylinder2_pixel_d, real_d, K)

# 计算欧氏距离
distance = np.linalg.norm(coord1 - coord2)
print(f"两钢瓶欧氏距离:{distance:.2f}米")

2. 双目相机方案(高精度,无需参考物)

如果能部署双目相机,可通过视差直接计算深度,无需依赖参考物体,测量精度更高。

步骤1:双目标定与立体校正

先完成双目相机的标定,获取左右相机的内参、外参及立体校正映射:

# 假设已完成单目标定,得到左右相机内参K1/K2、畸变dist1/dist2,以及旋转矩阵R、平移矩阵T
R1, R2, P1, P2, Q, _, _ = cv2.stereoRectify(K1, dist1, K2, dist2, gray.shape[::-1], R, T)
map1x, map1y = cv2.initUndistortRectifyMap(K1, dist1, R1, P1, gray.shape[::-1], cv2.CV_32FC1)
map2x, map2y = cv2.initUndistortRectifyMap(K2, dist2, R2, P2, gray.shape[::-1], cv2.CV_32FC1)

步骤2:计算视差图与3D坐标

通过立体匹配得到视差图,再利用重投影矩阵Q计算3D坐标:

# 读取左右帧(替换为你的视频帧路径)
left_img = cv2.imread('left_frame.jpg')
right_img = cv2.imread('right_frame.jpg')

# 立体校正
left_rect = cv2.remap(left_img, map1x, map1y, cv2.INTER_LINEAR)
right_rect = cv2.remap(right_img, map2x, map2y, cv2.INTER_LINEAR)

# 计算视差图(使用SGBM算法,参数可根据场景调整)
sgbm = cv2.StereoSGBM_create(minDisparity=0, numDisparities=16*5, blockSize=5)
disparity = sgbm.compute(cv2.cvtColor(left_rect, cv2.COLOR_BGR2GRAY), cv2.cvtColor(right_rect, cv2.COLOR_BGR2GRAY))

# 视差图转3D坐标
points_3d = cv2.reprojectImageTo3D(disparity, Q)

# 提取两个钢瓶中心对应的3D坐标
u1, v1 = cylinder1_center
u2, v2 = cylinder2_center
coord1 = points_3d[v1][u1]
coord2 = points_3d[v2][u2]

# 计算欧氏距离
distance = np.linalg.norm(coord1 - coord2)
print(f"两钢瓶欧氏距离:{distance:.2f}米")

关键注意事项

  • 相机稳定性:若相机固定,上述方案直接可用;若相机移动,需结合SLAM算法(如ORB-SLAM)估计相机姿态,否则3D坐标会出现偏移。
  • 目标检测精度:钢瓶中心/特征点的检测误差会直接影响距离计算结果,建议用最小外接矩形中心或轮廓矩中心作为特征点。
  • 畸变校正:所有输入图像必须先做畸变校正,否则会导致像素坐标偏差,影响3D计算精度。

内容的提问来源于stack exchange,提问作者BEAN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 09:14:56