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

如何将透视网格上的点到墙面距离转换为热力图

问题与解决方案

一、需求与参考信息

核心需求

  1. 将固定相机拍摄图像中的物体位置转换为俯视视角2D区域(仅展示物体名称与位置,无纹理)
  2. 生成热力图,用像素颜色表示网格点到墙面的距离(支持网格扩展至黑色区域)

已知参数与参考图

  • 网格单边长50cm,墙面高度2.5m
  • 基础网格:
    基础网格
  • 透视网格:
    透视网格
  • 相机位置示意图:
    相机位置示意图

附生成网格与透视变换的Python代码:

import cv2
import numpy as np
import imutils


img = np.zeros((480,640),dtype=np.uint8)

size = 40
for i in range(int(img.shape[1]/size)+1):
    img = cv2.line(img, (i*size, 0), (i*size, img.shape[0]), thickness = 2, color = 255)

for i in range(int(img.shape[0]/size)+1):
    img = cv2.line(img, (0, i*size), (img.shape[1], i*size), thickness = 2, color = 255)

cv2.imshow("img",img)
cv2.waitKey(0)

h, w = img.shape
a = [
    [0, 0],
    [h - 1, 0],
    [0, w - 1],
    [h - 1, w - 1]]

pt_A = a[0]
pt_B = a[1]
pt_C = a[2]
pt_D = a[3]

width_AD = np.sqrt(((pt_A[0] - pt_D[0]) ** 2) + ((pt_A[1] - pt_D[1]) ** 2))
width_BC = np.sqrt(((pt_B[0] - pt_C[0]) ** 2) + ((pt_B[1] - pt_C[1]) ** 2))
maxWidth = max(int(width_AD), int(width_BC))
 
 
height_AB = np.sqrt(((pt_A[0] - pt_B[0]) ** 2) + ((pt_A[1] - pt_B[1]) ** 2))
height_CD = np.sqrt(((pt_C[0] - pt_D[0]) ** 2) + ((pt_C[1] - pt_D[1]) ** 2))
maxHeight = max(int(height_AB), int(height_CD))

input_pts = np.float32([pt_A, pt_B, pt_C, pt_D])
output_pts = np.float32([[800, 600], [900, 300], [-300, 500], [100, 200]])

def perspective(img, input_pts=input_pts, output_pts=output_pts, maxWidth=maxWidth, maxHeight=maxHeight):
    M = cv2.getPerspectiveTransform(input_pts,output_pts)

    out = cv2.warpPerspective(img,M,(maxWidth, maxHeight),flags=cv2.INTER_LINEAR)
    out = imutils.resize(out,height=500)
    return out


frame = perspective(img)
# Display image
cv2.imshow('frame', frame)
cv2.waitKey(0)

二、物体位置转俯视视角的实现步骤

1. 校准透视变换矩阵

你当前代码的输出点是手动设定的,无法实现真实场景的坐标映射,需要基于像素-世界坐标对应关系校准:

  • 在真实场景中选取至少4个已知世界坐标的点(比如网格四个角,对应世界坐标如(0,0)、(0,200)、(200,0)、(200,200),单位cm)
  • 在相机拍摄的图像中定位这些点的像素坐标
  • 用真实世界坐标作为输出点,重新计算透视变换矩阵M,后续即可用这个矩阵将图像像素坐标映射到俯视坐标系

2. 物体检测与位置映射

  • 用目标检测工具(YOLO、Faster R-CNN,或简单的轮廓/颜色检测)识别图像中的物体,获取物体的像素边界框或中心坐标
  • 调用cv2.perspectiveTransform将物体的像素坐标转换为俯视视角的世界坐标
  • 在预设的俯视网格图上绘制物体位置(比如用矩形框标注,添加物体名称文本)

三、距离墙面热力图的生成方法

1. 定义墙面的世界坐标

结合相机位置示意图和网格参数,在俯视坐标系中确定墙面的位置(比如墙面为x=0的直线,或特定多边形)

2. 计算网格点到墙面的距离

  • 生成扩展后的网格(覆盖黑色区域),遍历每个网格点的世界坐标
  • 计算点到墙面的最短距离:若墙面是直线,直接用点到直线的距离公式;若为多边形,计算点到多边形边缘的最短距离

3. 绘制热力图

  • 将距离值映射到0-255的灰度范围,再用cv2.applyColorMap转换为热力颜色(比如近墙用红色,远墙用蓝色)
  • 将颜色填充到对应的网格区域,生成最终热力图

四、代码优化示例

1. 校准透视变换矩阵

# 真实场景中四个角的世界坐标(单位:cm)
world_pts = np.float32([[0, 0], [0, 200], [200, 0], [200, 200]])
# 相机图像中对应点的像素坐标(需手动从拍摄图中提取)
image_pts = np.float32([[x1,y1], [x2,y2], [x3,y3], [x4,y4]])
# 计算精准的透视变换矩阵
M = cv2.getPerspectiveTransform(image_pts, world_pts)

2. 生成扩展网格热力图

import cv2
import numpy as np

# 定义扩展网格范围(x、y轴从0到500cm,步长50cm)
grid_x = np.arange(0, 501, 50)
grid_y = np.arange(0, 501, 50)
# 创建热力图画布(每个网格用10x10像素表示)
heatmap = np.zeros((len(grid_y)*10, len(grid_x)*10, 3), dtype=np.uint8)

# 假设墙面位于x=0的直线
wall_line = np.array([[0,0], [0,500]], dtype=np.float32)

for i, y in enumerate(grid_y):
    for j, x in enumerate(grid_x):
        # 计算当前网格点到墙面的距离
        distance = abs(x)  # 墙面在x=0,简化计算
        # 将距离映射到0-255灰度值
        gray = int(np.clip(distance / 500 * 255, 0, 255))
        # 转换为热力颜色
        color = cv2.applyColorMap(np.array([[gray]], dtype=np.uint8), cv2.COLORMAP_JET)[0][0]
        # 填充网格区域
        cv2.rectangle(heatmap, (j*10, i*10), ((j+1)*10, (i+1)*10), color.tolist(), -1)

cv2.imshow("Wall Distance Heatmap", heatmap)
cv2.waitKey(0)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 08:49:56