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

基于Numpy高度矩阵计算视野(FOV)及生成掩码矩阵的技术问询

实现Numpy高度图的视野(FOV)掩码计算

首先我得先明确两种常见的视野判断逻辑,你可以根据实际需求选择:

逻辑1:仅当像素被高于观测者的物体遮挡时标记为-1

这种逻辑下,观测者能看到所有前方没有高于自己的物体的区域——只要某个方向上出现了比观测者高的像素,该方向上之后的所有像素都会被遮挡;而低于/等于观测者高度的像素,只要前面没有更高的遮挡物,就保持可见。

实现代码

import numpy as np
from math import gcd

def compute_fov_blocked_by_taller(height_map, obs_y, obs_x):
    n, m = height_map.shape
    # 初始化FOV掩码:复制原高度,遮挡的标记为-1
    fov_mask = height_map.copy().astype(np.int32)
    obs_height = height_map[obs_y, obs_x]

    # 生成所有唯一的射线方向(化简后的方向向量)
    directions = set()
    for dy in range(-n + 1, n):
        for dx in range(-m + 1, m):
            if dy == 0 and dx == 0:
                continue
            common_divisor = gcd(abs(dy), abs(dx))
            # 化简方向,避免重复处理同一条射线的不同步长
            dir_dy, dir_dx = dy // common_divisor, dx // common_divisor
            directions.add((dir_dy, dir_dx))

    # 遍历每个方向的射线
    for dir_dy, dir_dx in directions:
        current_y, current_x = obs_y + dir_dy, obs_x + dir_dx
        is_blocked = False
        while 0 <= current_y < n and 0 <= current_x < m:
            if is_blocked:
                # 已被遮挡,标记为-1
                fov_mask[current_y, current_x] = -1
            else:
                # 检查当前像素是否高于观测者,若是则后续都被遮挡
                if height_map[current_y, current_x] > obs_height:
                    is_blocked = True
            # 移动到下一个像素
            current_y += dir_dy
            current_x += dir_dx

    # 观测点自身保留原高度
    fov_mask[obs_y, obs_x] = obs_height
    return fov_mask

逻辑2:像素被任何比它高的前方物体遮挡时标记为-1

这是更贴近真实视觉的逻辑:一个像素可见,当且仅当它比观测点到它之间的所有像素都高。即使前方物体比观测者矮,但比目标像素高,目标像素也会被遮挡。

实现代码

import numpy as np
from math import gcd

def compute_fov_realistic(height_map, obs_y, obs_x):
    n, m = height_map.shape
    fov_mask = height_map.copy().astype(np.int32)
    obs_height = height_map[obs_y, obs_x]

    directions = set()
    for dy in range(-n + 1, n):
        for dx in range(-m + 1, m):
            if dy == 0 and dx == 0:
                continue
            common_divisor = gcd(abs(dy), abs(dx))
            dir_dy, dir_dx = dy // common_divisor, dx // common_divisor
            directions.add((dir_dy, dir_dx))

    for dir_dy, dir_dx in directions:
        current_y, current_x = obs_y + dir_dy, obs_x + dir_dx
        # 记录当前射线方向上遇到的最大高度(初始为观测点高度)
        max_height_so_far = obs_height
        while 0 <= current_y < n and 0 <= current_x < m:
            current_h = height_map[current_y, current_x]
            if current_h <= max_height_so_far:
                # 被前方更高的物体遮挡
                fov_mask[current_y, current_x] = -1
            else:
                # 可见,更新当前最大高度
                max_height_so_far = current_h
            current_y += dir_dy
            current_x += dir_dx

    fov_mask[obs_y, obs_x] = obs_height
    return fov_mask

使用示例

假设我们有一个3x3的高度图,观测点在中心位置:

# 测试高度图
height_map = np.array([
    [1, 3, 2],
    [4, 5, 1],
    [2, 2, 3]
])

# 计算逻辑1的FOV掩码(仅被高于观测者的物体遮挡)
fov1 = compute_fov_blocked_by_taller(height_map, obs_y=1, obs_x=1)
print("逻辑1输出:")
print(fov1)

# 计算逻辑2的FOV掩码(被任何更高的前方物体遮挡)
fov2 = compute_fov_realistic(height_map, obs_y=1, obs_x=1)
print("\n逻辑2输出:")
print(fov2)

输出结果

逻辑1输出:
[[1 3 2]
 [4 5 1]
 [2 2 3]]
# 解释:所有像素都没有被高于观测者(高度5)的物体遮挡,所以全部可见

逻辑2输出:
[[ -1  3  -1]
 [ 4  5  -1]
 [ -1 -1  3]]
# 解释:
# - 左上(0,0)高度1,比观测点到它之间的(0,1)高度3低,被遮挡
# - 右上(0,2)高度2,比中间的(0,1)高度3低,被遮挡
# - 右下(2,2)高度3,是该方向上最高的,可见

优化说明

  • 我们通过化简方向向量避免了重复处理同一条射线(比如步长为2的(2,0)和步长为1的(1,0)是同一条射线,只需要处理一次),大幅减少了计算量。
  • 代码使用Numpy数组操作,比纯Python循环高效得多,适合处理较大的n*m高度图。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 10:37:33