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_data20\*i+6 * sx), 0)

y1 = max(int(infer_data20\*i+7 * sy), 0)

x2 = max(int(infer_data20\*i+8 * sx), 0)

y2 = max(int(infer_data20\*i+9 * sy), 0)

x3 = max(int(infer_data20\*i+10 * sx), 0)

y3 = max(int(infer_data20\*i+11 * sy), 0)

x4 = max(int(infer_data20\*i+12 * sx), 0)

y4 = max(int(infer_data20\*i+13 * sy), 0)

zh = struct.unpack('!f',int(bin(infer_data20\*i+4)2:,2).to_bytes(4,byteorder='big'))

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

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

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

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

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

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

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

point_dict1"name" = str(struct.unpack('!f',int(bin(infer_data20\*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_data20\*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_alli"delrule" == 0:

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

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

xi1 = point_alli'pointx'0

yi1 = point_alli'pointy'0

xi2 = point_alli'pointx'1

yi2 = point_alli'pointy'1

xj1 = point_allj'pointx'0

yj1 = point_allj'pointy'0

xj2 = point_allj'pointx'1

yj2 = point_allj'pointy'1

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

point_allj"delrule" = 1

for i in range(len(point_all)):

if point_alli"delrule" == 0:

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

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

vec1 =line1\[2-line10,line13-line11]

vec2 =line2\[2-line20,line23-line21]

#计算向量的点积和模长

dot_product = vec10 * vec20 + vec11 * vec21

m1 = math.sqrt(vec10**2 + vec11**2) + 0.000000000001

m2 = math.sqrt(vec20**2 + vec21**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_alli"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. 一张可视化结果(最好能同时给出原图和画图后的图)

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

相关推荐
RisunJan9 小时前
Linux命令-perl (perl语言解释器)
linux·perl
闪电悠米13 小时前
黑马点评-Redis 消息队列-04_stream_seckill_order
数据库·redis·分布式·缓存·oracle·junit·lua
呦呦鹿鸣Rzh14 小时前
Redis Lua 脚本:从入门到避坑指南
redis·junit·lua
清晨00114 小时前
工业互联网实时数据统计一致性保障 — 基于 Redis Lua 的并发安全方案
redis·安全·lua
x***r1511 天前
Postman-win64-7.3.5-Setup安装配置教程(Windows 详细版)
开发语言·lua
我登哥MVP2 天前
Spring Boot 从“会用”到“精通”:内容协商原理
java·spring boot·后端·spring·java-ee·maven·lua
李子琪。3 天前
谷歌“三剑客”与云计算基石:GFS、MapReduce、Bigtable 全栈解析及私有云落地实践
开发语言·编辑器·perl
FFZero14 天前
[mpv脚本系统] (四) 脚本加载与事件循环系统
c语言·音视频·lua·多媒体
多彩电脑4 天前
Lua中的元表里的__index和__newindex
开发语言·lua
zfoo-framework4 天前
通过redis-cli+lua脚本查询redis数据
数据库·redis·lua