如何将透视网格上的点到墙面距离转换为热力图
问题与解决方案
一、需求与参考信息
核心需求
- 将固定相机拍摄图像中的物体位置转换为俯视视角2D区域(仅展示物体名称与位置,无纹理)
- 生成热力图,用像素颜色表示网格点到墙面的距离(支持网格扩展至黑色区域)
已知参数与参考图
- 网格单边长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
相关产品推荐
相关产品推荐

