draw_tensor2psd.py_cursor

import cv2

import numpy as np

import math

import os

import struct

from tqdm import tqdm

from glob import glob

PALETTE = np.random.randint(0, 255, [255, 3], dtype=np.uint32)

模型输入尺寸(W, H),用于把模型坐标缩放回原图

MODEL_IN_W = 608

MODEL_IN_H = 736

zh

imagespath = "/ai/DataSets/OD_FSD_zh/TI_test/rm/4/image/"

imagespath = "/ai/DataSets/OD_FSD_zh/TI_test/ppchen/DVR-20250804152834-2382380-PLR/image/"

savepath = "/ai/zhdata/multiyolov5_point_v2/test_images/out"

zh1 = 0

def readTensor(tensorFile):

global zh1

tensor = open(tensorFile,'rb')

infer_data = np.fromfile(tensor, dtype=np.int32)

print(infer_data.shape)

soltnum = int(len(infer_data) / 20)

im0 = cv2.imread(imagespath + tensorFile.split('/')[-1][:-8] + '.bmp')

if im0 is None:

print("读取图片失败:", tensorFile)

return

h0, w0 = im0.shape[:2]

sx = w0 / float(MODEL_IN_W)

sy = h0 / float(MODEL_IN_H)

point_all =[]

for i in range(soltnum):

point_dict1={}

x1 = max(int(infer_data[20*i+6] * sx), 0)

y1 = max(int(infer_data[20*i+7] * sy), 0)

x2 = max(int(infer_data[20*i+8] * sx), 0)

y2 = max(int(infer_data[20*i+9] * sy), 0)

x3 = max(int(infer_data[20*i+10] * sx), 0)

y3 = max(int(infer_data[20*i+11] * sy), 0)

x4 = max(int(infer_data[20*i+12] * sx), 0)

y4 = max(int(infer_data[20*i+13] * sy), 0)

zh = struct.unpack('!f',int(bin(infer_data[20*i+4])[2:],2).to_bytes(4,byteorder='big'))

point_dict1["conf"] = struct.unpack('!f',int(bin(infer_data[20*i+4])[2:],2).to_bytes(4,byteorder='big'))[0]

point_dict1["isOccupied"] = struct.unpack('!f',int(bin(infer_data[20*i+14])[2:],2).to_bytes(4,byteorder='big'))[0]

point_dict1["isVIP"] = struct.unpack('!f',int(bin(infer_data[20*i+15])[2:],2).to_bytes(4,byteorder='big'))[0]

point_dict1["iswoman"] = struct.unpack('!f',int(bin(infer_data[20*i+16])[2:],2).to_bytes(4,byteorder='big'))[0]

point_dict1["isdisabled"] = struct.unpack('!f',int(bin(infer_data[20*i+17])[2:],2).to_bytes(4,byteorder='big'))[0]

point_dict1["ischarging"] = struct.unpack('!f',int(bin(infer_data[20*i+18])[2:],2).to_bytes(4,byteorder='big'))[0]

point_dict1["step"] = struct.unpack('!f',int(bin(infer_data[20*i+19])[2:],2).to_bytes(4,byteorder='big'))[0]

point_dict1["name"] = str(struct.unpack('!f',int(bin(infer_data[20*i+5])[2:],2).to_bytes(4,byteorder='big'))[0])

point_dict1["delrule"] = 0

point_dict1["pointx"] = [x1,x2,x3,x4]

point_dict1["pointy"] = [y1,y2,y3,y4]

if x3 > 1000 or x4 > 1000 or x1 > 1000 or x2 > 1000 or y3 > 1000 or y4 > 1000 or y1 > 1000 or y2 > 1000:

zh1 +=1

kk = struct.unpack('!f',int(bin(infer_data[20*i+17])[2:],2).to_bytes(4,byteorder='big'))[0]

print("数据解析错误"+ tensorFile + str(x3) + '--'+ str(zh1))

break

point_all.append(point_dict1)

end = len(point_all)

for i in range(len(point_all)):

if point_all[i]["delrule"] == 0:

for j in range(i+1,end):

#简单就是求入口顶点之间的距离

xi1 = point_all[i]['pointx'][0]

yi1 = point_all[i]['pointy'][0]

xi2 = point_all[i]['pointx'][1]

yi2 = point_all[i]['pointy'][1]

xj1 = point_all[j]['pointx'][0]

yj1 = point_all[j]['pointy'][0]

xj2 = point_all[j]['pointx'][1]

yj2 = point_all[j]['pointy'][1]

if (abs(xi1 - xj1) + abs(yi1 - yj1)) < 40 or (abs(xi2 - xj2) + abs(yi2 - yj2)) < 40:

point_all[j]["delrule"] = 1

for i in range(len(point_all)):

if point_all[i]["delrule"] == 0:

line1 = [point_all[i]['pointx'][0],point_all[i]['pointy'][0],point_all[i]['pointx'][3],point_all[i]['pointy'][3]]

line2 = [point_all[i]['pointx'][1],point_all[i]['pointy'][1],point_all[i]['pointx'][2],point_all[i]['pointy'][2]]

vec1 =[line1[2]-line1[0],line1[3]-line1[1]]

vec2 =[line2[2]-line2[0],line2[3]-line2[1]]

#计算向量的点积和模长

dot_product = vec1[0] * vec2[0] + vec1[1] * vec2[1]

m1 = math.sqrt(vec1[0]**2 + vec1[1]**2) + 0.000000000001

m2 = math.sqrt(vec2[0]**2 + vec2[1]**2) + 0.000000000001

val = dot_product/(m1 * m2)

if val > 1:

val = 1

if val < -1:

val = -15

radians = math.acos(val)

du = math.degrees(radians)

if du > 20:

point_all[i]["delrule"] = 2

if 1:

for point_i in point_all:

if point_i["delrule"] == 0:

if point_i["conf"] > 0.45:#0.45

print(point_i["conf"])

cv2.putText(im0, f'{point_i["conf"]:.3f}',

(point_i["pointx"][0] + 6, point_i["pointy"][0] + 6),

cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 255, 0),2) #置信度

cv2.putText(im0, point_i["name"],

(point_i["pointx"][0] + 6, point_i["pointy"][0] + 30),

cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 255, 0),2) #类别

if float(point_i["isOccupied"])> 0.1: #0.5

cv2.putText(im0, "Occ :" + f'{point_i["isOccupied"]:.3f}',

(point_i["pointx"][0] + 6, point_i["pointy"][0] + 54),

cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 255, 0),2) #是否被占用

if float(point_i["isVIP"]) > 0.5:

cv2.putText(im0, "VIP :" + f'{point_i["isVIP"]:.3f}',

(point_i["pointx"][0] + 6, point_i["pointy"][0] + 78),

cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 255, 0),2) #是否VIP车位

if float(point_i["iswoman"]) > 0.5:

cv2.putText(im0, "woman :" + f'{point_i["iswoman"]:.3f}',

(point_i["pointx"][0] + 6, point_i["pointy"][0] + 102),

cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 255, 0),2) #是否女性车位

if float(point_i["isdisabled"]) > 0.5:

cv2.putText(im0, "disab :" + f'{point_i["isdisabled"]:.3f}',

(point_i["pointx"][0] + 6, point_i["pointy"][0] + 126),

cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 255, 0),2) #是否残疾人车位

if float(point_i["ischarging"]) > 0.5:

cv2.putText(im0, "charg :" + f'{point_i["ischarging"]:.3f}',

(point_i["pointx"][0] + 6, point_i["pointy"][0] + 150),

cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 255, 0),2) #是否充电车位

if float(point_i["step"]) > 0.5:

cv2.putText(im0, "step :" + f'{point_i["step"]:.3f}',

(point_i["pointx"][0] + 6, point_i["pointy"][0] + 174),

cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 255, 0),2) #是否阶梯形车位

cv2.arrowedLine(im0, (point_i["pointx"][0], point_i["pointy"][0]),(point_i["pointx"][1], point_i["pointy"][1]), (0, 255, 0), 1, cv2.LINE_AA)

cv2.arrowedLine(im0, (point_i["pointx"][1], point_i["pointy"][1]),(point_i["pointx"][2], point_i["pointy"][2]), (255, 255, 0), 1, cv2.LINE_AA)

cv2.arrowedLine(im0, (point_i["pointx"][2], point_i["pointy"][2]),(point_i["pointx"][3], point_i["pointy"][3]), (255, 255, 0), 1, cv2.LINE_AA)

cv2.arrowedLine(im0, (point_i["pointx"][3], point_i["pointy"][3]),(point_i["pointx"][0], point_i["pointy"][0]), (255, 255, 0), 1, cv2.LINE_AA)

else:

cv2.putText(im0, f'{point_i["conf"]:.3f}',

(point_i["pointx"][0] + 6, point_i["pointy"][0] + 6),

cv2.FONT_HERSHEY_PLAIN, 2, (0, 0, 255),3)

cv2.arrowedLine(im0, (point_i["pointx"][0], point_i["pointy"][0]),(point_i["pointx"][1], point_i["pointy"][1]), (0, 0, 255), 1, cv2.LINE_AA)

cv2.arrowedLine(im0, (point_i["pointx"][1], point_i["pointy"][1]),(point_i["pointx"][2], point_i["pointy"][2]), (0, 0, 255), 1, cv2.LINE_AA)

cv2.arrowedLine(im0, (point_i["pointx"][2], point_i["pointy"][2]),(point_i["pointx"][3], point_i["pointy"][3]), (0, 0, 255), 1, cv2.LINE_AA)

cv2.arrowedLine(im0, (point_i["pointx"][3], point_i["pointy"][3]),(point_i["pointx"][0], point_i["pointy"][0]), (0, 0, 255), 1, cv2.LINE_AA)

if point_i["delrule"] == 1:

cv2.putText(im0, f'{point_i["conf"]:.3f}',

(point_i["pointx"][0] + 6, point_i["pointy"][0] + 6),

cv2.FONT_HERSHEY_PLAIN, 2, (0, 0, 255),3)

cv2.arrowedLine(im0, (point_i["pointx"][0], point_i["pointy"][0]),(point_i["pointx"][1], point_i["pointy"][1]), (0, 0, 0), 1, cv2.LINE_AA)

cv2.arrowedLine(im0, (point_i["pointx"][1], point_i["pointy"][1]),(point_i["pointx"][2], point_i["pointy"][2]), (0, 0, 0), 1, cv2.LINE_AA)

cv2.arrowedLine(im0, (point_i["pointx"][2], point_i["pointy"][2]),(point_i["pointx"][3], point_i["pointy"][3]), (0, 0, 0), 1, cv2.LINE_AA)

cv2.arrowedLine(im0, (point_i["pointx"][3], point_i["pointy"][3]),(point_i["pointx"][0], point_i["pointy"][0]), (0, 0, 0), 1, cv2.LINE_AA)

if point_i["delrule"] == 2:

cv2.putText(im0, f'{point_i["conf"]:.3f}',

(point_i["pointx"][0] + 6, point_i["pointy"][0] + 6),

cv2.FONT_HERSHEY_PLAIN, 2, (0, 0, 255),3)

cv2.arrowedLine(im0, (point_i["pointx"][0], point_i["pointy"][0]),(point_i["pointx"][1], point_i["pointy"][1]), (0, 0, 0), 1, cv2.LINE_AA)

cv2.arrowedLine(im0, (point_i["pointx"][1], point_i["pointy"][1]),(point_i["pointx"][2], point_i["pointy"][2]), (0, 0, 0), 1, cv2.LINE_AA)

cv2.arrowedLine(im0, (point_i["pointx"][2], point_i["pointy"][2]),(point_i["pointx"][3], point_i["pointy"][3]), (0, 0, 0), 1, cv2.LINE_AA)

cv2.arrowedLine(im0, (point_i["pointx"][3], point_i["pointy"][3]),(point_i["pointx"][0], point_i["pointy"][0]), (0, 0, 0), 1, cv2.LINE_AA)

zh = "/ai/TopViewMul/4/psd_out/" + tensorFile.split('/')[-1][:-8] + '.bmp'

print(zh)

cv2.imwrite(zh, im0)

zh

for binpath in tqdm(glob(os.path.join("/ai/DataSets/OD_FSD_zh/TI_test/rm/2/psd/",'*.bin'))):

readTensor(binpath)

num=0

for binpath in tqdm(glob(os.path.join("/ai/TopViewMul/4/out_480_544_2039/psd/",'*.bin'))):

readTensor(binpath)

num+=1

if num==100:

print('exit')

exit(0)

从你现在这张"修改后"的图看,框已经不集中在左上角了,但仍明显偏向左边。这类现象更像是可视化坐标系和真实图像尺寸不一致,而不是解码本身的问题。

关键原因(结合你的工程):

  1. 下位机推理的输入会被强制 resize 到模型输入尺寸

在 main.c 的 readInput() 里,直接把原始 BMP resize 到 ioBufDesc->inWidth/Height:

  • 也就是说,模型输出坐标一定是"模型输入尺寸坐标系",而不是原图尺寸坐标系。
  1. draw_tensor2psd.py 直接把坐标画到原图

脚本没有做任何缩放,默认坐标就是原图像素。

如果原图是大分辨率(比如 1472×1216),而模型输入是 608×736,那么坐标会被压缩到左上角区域。

  1. 你这套模型的输入尺寸其实是 W=608, H=736
  • train_608_736.py 里 img-size 标注为 HW,即 H=736, W=608
  • TIDL 配置 inWidth=608 inHeight=736 也一致

如果你在可视化里当成 736×608(W=736),横向缩放会变小,框会偏左。


结论

现在剩下的主要问题很可能在可视化脚本:

需要把输出点坐标从"模型输入尺寸坐标系"缩放到"原图尺寸坐标系"。

你可以在 draw_tensor2psd.py 里这样做(逻辑示意):

假设模型输入尺寸(一定要用 W=608, H=736)

in_w, in_h = 608, 736

原图尺寸

h0, w0 = im0.shape[:2]

sx = w0 / in_w

sy = h0 / in_h

x1 = int(x1 * sx); y1 = int(y1 * sy)

x2 = int(x2 * sx); y2 = int(y2 * sy)

x3 = int(x3 * sx); y3 = int(y3 * sy)

x4 = int(x4 * sx); y4 = int(y4 * sy)

或者更简单:

把 im0 换成和模型输入一致的 608×736 图,这样就无需缩放。


为什么这很符合你的现象

  • 修改后"不再聚左上角",说明解码坐标已基本正确
  • 但仍偏左,说明坐标系仍然比原图小(典型就是 608×736 画在大图)

如果你方便,再补充两点我可以进一步确认:

  • 这张图的原始 BMP 实际尺寸(宽、高)
  • 你想把结果画在原图还是模型输入图

我也可以直接帮你把 draw_tensor2psd.py 改成自适应缩放版本。

已改好 draw_tensor2psd.py,现在会把模型输出坐标缩放回原图再画:

  • 增加 MODEL_IN_W/ MODEL_IN_H(默认 608×736)
  • 读取原图尺寸后计算 sx/sy,对四个点坐标做缩放
  • 增加了图片读取失败的保护

你现在只需要确认:

模型输入尺寸是否确实是 W=608, H=736(从你的 TIDL 配置和训练脚本看是对的)。

如果不是,改这两个常量就行。

建议你再跑一张图验证位置是否对齐。

如果还有偏移,我可以继续根据你的原图尺寸和输入尺寸做更精细的映射(比如考虑裁剪或 letterbox)。

下面给你一套到公司后可直接照做的调试思路,按优先级从"最可能"到"次可能"排:


1) 先确认坐标系是否一致(最常见)

目标:验证"模型输出坐标"是基于哪张图的尺寸。

检查点:

  • 原图尺寸 W0,H0(BMP 实际大小)
  • 模型输入尺寸 Win,Hin(TIDL inWidth/inHeight)
  • draw_tensor2psd.py 里 MODEL_IN_W/H 是否与 Win/Hin 一致
  • 训练脚本 img-size 标注为 HW,所以输入是 W=608, H=736,不要弄反

快速验证:

  • 把 draw_tensor2psd.py 临时改成直接画在 resize 后的图上(把原图 resize 到 608×736 再画),如果这样位置正确,说明问题就是"原图坐标系映射",不是模型输出问题。

2) 判断是不是"缩放比例 + 误差"

如果框整体偏左/偏上/偏小:

  • 打印 sx = W0/Win, sy = H0/Hin
  • 观察是否 水平和垂直比例不同(W0/H0 不是 608/736 的等比)
  • 如果图像原始比例和模型输入比例不一致,不做 letterbox,直接 resize,会造成几何扭曲;你现在的映射应与这个扭曲一致(用不同的 sx/sy),否则会偏。

3) 检查是否存在 letterbox / padding

你当前下位机预处理是 直接 resize,没有 letterbox。

但如果你在上位机或训练时用了 letterbox,且模型输出是基于 letterbox 坐标,那么必须考虑 padding 偏移。

验证方法:

  • 在下位机 readInput() 里确认是 resizeImage(你当前确实是 resize)
  • 如果以后切换成 letterbox,draw_tensor2psd.py 需增加 padX/padY 的反向补偿

4) 校验 bin 输出是否是"输入尺度"

最直接的方法:

  • 在下位机输出前打印 一个 bbox 的点坐标范围(比如 min/max)
  • 如果输出点范围接近 Win/Hin,说明坐标是输入尺度
  • 如果输出点范围接近 W0/H0,说明已经是原图尺度,那你就不该再缩放

5) 排除 W/H 颠倒

极易踩坑:

一秒验证:

  • 把 MODEL_IN_W/H 交换试一次

如果交换后框明显"更接近",说明之前 W/H 搞反了。


6) 逐步定位到"一个样本"

建议用一张固定样本,不要批量。

把这 4 个值记下来:

  • 原图大小 W0/H0
  • 模型输入 Win/Hin
  • 任意一个输出点 x1,y1
  • 画到图上后的 x1',y1'

确认映射公式:

x' = x1 * W0/Win

y' = y1 * H0/Hin


7) 如果仍不对,排查输出解码

可能是:

  • 某个 head 的 inWidth/inHeight 仍然没设置
  • 输出张量顺序/通道顺序与模型不一致(虽然你已确认 head 索引,但通道组织也可能变)
  • 量化 scale 不一致导致数值偏差(一般不会全局偏移这么明显)

验证:

  • 打印 yolov5params.inWidth[]/inHeight[](每个 head)
  • 打印 ioBufDesc.outWidth/outHeight/outNumChannels 是否与训练期模型一致

如果你明天运行后仍不对,直接把以下三项发我,我可以继续定位:

  1. 原图尺寸 W0×H0

  2. 模型输入尺寸 Win×Hin

  3. 一张可视化结果(最好能同时给出原图和画图后的图)

我可以继续帮你一步步定位到底是"坐标系问题"还是"解码问题"。

相关推荐
小李云雾1 天前
FastAPI 后端开发:文件上传 + 表单提交
开发语言·python·lua·postman·fastapi
曼巴UE51 天前
Unlua 官方案例
c++·ue5·lua·ue
列星随旋2 天前
基于 Redis + Lua,实现“多维度原子限流”(令牌桶 + 滑动窗口)
java·redis·lua
上海合宙LuatOS2 天前
LuatOS扩展库API——【exgnss】GNSS定位
物联网·lua·luatos
0xDevNull2 天前
Redis Lua 脚本详细教程
redis·缓存·lua
上海合宙LuatOS2 天前
LuatOS扩展库API——【exlcd】显示屏控制
物联网·lua·luatos
0xDevNull2 天前
Spring Boot 中使用 Redis Lua 脚本详细教程
spring boot·redis·lua
阿沁QWQ3 天前
docker使用
docker·容器·perl
DJ斯特拉4 天前
Redis使用lua脚本
junit·单元测试·lua
Aktx20FNz4 天前
OpenClaw中级到高级教程
lua