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

如何修正长方体(四点定义)的相机视锥体视野检测代码?

如何修正长方体(四点定义)的相机视锥体视野检测代码?

我帮你排查了代码里的几个核心问题,现在一步步给你说明修正思路和最终代码:

核心问题分析

  1. 向量变换方向错误:视锥体的本地方向向量转世界坐标系时,矩阵乘法顺序搞反了,导致视锥体朝向完全错误。
  2. 核心向量计算不准确:用视锥体向量的平均推导相机前向/上下右向量,不如直接从相机姿态矩阵提取准确,还能避免额外计算误差。
  3. 深度判断逻辑完全错误:你把点相对相机的向量归一化后,用余弦值和实际距离(0.3米)比较,两者量级完全不匹配,没法正确判断点是否在相机后方或过近。
  4. 视锥体边界未结合深度:视锥体的横纵向边界是随深度变化的(近小远大),原代码用固定的近平面边界判断所有深度的点,逻辑错误。

修正后的完整代码

import numpy as np
from typing import Tuple


class CameraFrustum:
    def __init__(
        self, d_dist: float = 0.3, fov: Tuple[float, float] = (50, 40)
    ):
        self.d_dist = d_dist  # 近裁剪面距离
        self.fov = fov
        # 预计算半视场角的正切值,避免重复计算
        self.half_fov_h = np.tan(np.radians(fov[0] / 2))
        self.half_fov_v = np.tan(np.radians(fov[1] / 2))
        
        # 相机世界坐标系下的核心参数
        self.cam_pos = None
        self.forward = None  # 相机前向单位向量
        self.right = None    # 相机右向单位向量
        self.up = None       # 相机上向单位向量

    def compute_frustum_params(self, cam_pose: np.ndarray):
        # 提取相机在世界坐标系中的位置
        self.cam_pos = cam_pose[:3, 3]
        # 提取相机旋转矩阵(相机坐标系到世界坐标系的变换)
        cam_rot = cam_pose[:3, :3]
        # 从旋转矩阵直接获取相机的三个核心向量(标准姿态定义)
        self.right = cam_rot[:, 0]
        self.up = cam_rot[:, 1]
        self.forward = cam_rot[:, 2]

    def is_point_in_frustum(self, p_point: np.ndarray) -> bool:
        # 确保先计算相机视锥体参数
        if self.forward is None:
            raise ValueError("请先调用compute_frustum_params传入相机姿态!")
        
        # 计算点相对于相机的世界坐标系向量
        point_rel_cam = p_point - self.cam_pos
        
        # 1. 判断点是否在相机前方
        depth_forward = np.dot(point_rel_cam, self.forward)
        if depth_forward <= 0:
            print("点在相机后方")
            return False
        
        # 2. 判断点是否小于近裁剪面距离
        if depth_forward < self.d_dist:
            print("点距离相机过近")
            return False
        
        # 3. 计算点在相机左右/上下方向的投影长度
        proj_right = np.dot(point_rel_cam, self.right)
        proj_up = np.dot(point_rel_cam, self.up)
        
        # 4. 计算当前深度下的视锥体动态边界
        half_width = depth_forward * self.half_fov_h
        half_height = depth_forward * self.half_fov_v
        
        # 5. 判断是否在横向范围内
        if not (-half_width <= proj_right <= half_width):
            return False
        
        # 6. 判断是否在纵向范围内
        if not (-half_height <= proj_up <= half_height):
            return False
        
        return True


# 测试代码
cam_frustum = CameraFrustum()

# 目标检测点
pts = np.array(
    [
        [1.54320189, -0.35068437, -0.48266792],
        [1.52144436, 0.44898697, -0.48990338],
        [0.32197813, 0.41622155, -0.50429738],
        [0.34373566, -0.38344979, -0.49706192],
    ]
)

# 相机姿态矩阵(世界坐标系)
cam_pose = np.array(
    [
        [-0.02719692, 0.9447125, -0.3271947, 1.25978471],
        [0.99958918, 0.02274412, 0.0, 0.03276859],
        [-0.00904433, -0.32711006, -0.94495695, 0.4514743],
        [0.0, 0.0, 0.0, 1.0],
    ]
)

# 预先计算相机视锥体参数
cam_frustum.compute_frustum_params(cam_pose)

# 逐个判断点是否在视锥体内
for idx, pt in enumerate(pts):
    res = cam_frustum.is_point_in_frustum(pt)
    print(f"点{idx+1}是否在视锥体内: {res}")

关键修正说明

  1. 核心向量直接提取:从相机姿态矩阵的前3列直接获取右、上、前向向量,这是相机姿态的标准定义,比视锥体向量平均的方式更准确且高效。
  2. 深度判断逻辑修复:使用未归一化的点相对向量与前向向量的点积,得到点在相机前向的实际深度,正确判断点是否在后方或过近。
  3. 动态边界计算:根据点的实际深度,计算该深度下视锥体的半宽/半高,完全符合透视投影的视锥体特性。
  4. 代码结构优化:拆分了参数计算和点判断的方法,逻辑更清晰,避免了重复计算和状态混乱。

运行修正后的代码,就能正确区分你的4个点中哪些在视锥体内哪些在外了。

备注:内容来源于stack exchange,提问作者bhomaidan90

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 14:27:58