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
调试:同时输出"模型输入尺寸"和"交换W/H"的可视化
DEBUG_DRAW_MODEL_SIZE = True
DEBUG_DRAW_MODEL_SWAP = True
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={}
raw_x1 = max(int(infer_data[20*i+6]), 0)
raw_y1 = max(int(infer_data[20*i+7]), 0)
raw_x2 = max(int(infer_data[20*i+8]), 0)
raw_y2 = max(int(infer_data[20*i+9]), 0)
raw_x3 = max(int(infer_data[20*i+10]), 0)
raw_y3 = max(int(infer_data[20*i+11]), 0)
raw_x4 = max(int(infer_data[20*i+12]), 0)
raw_y4 = max(int(infer_data[20*i+13]), 0)
x1 = max(int(raw_x1 * sx), 0)
y1 = max(int(raw_y1 * sy), 0)
x2 = max(int(raw_x2 * sx), 0)
y2 = max(int(raw_y2 * sy), 0)
x3 = max(int(raw_x3 * sx), 0)
y3 = max(int(raw_y3 * sy), 0)
x4 = max(int(raw_x4 * sx), 0)
y4 = max(int(raw_y4 * 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 DEBUG_DRAW_MODEL_SIZE:
point_dict1["raw_pointx"] = [raw_x1, raw_x2, raw_x3, raw_x4]
point_dict1["raw_pointy"] = [raw_y1, raw_y2, raw_y3, raw_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)
if DEBUG_DRAW_MODEL_SIZE:
im_model = cv2.resize(im0, (MODEL_IN_W, MODEL_IN_H))
for point_i in point_all:
if point_i.get("raw_pointx") is None:
continue
if point_i["delrule"] == 0 and point_i["conf"] > 0.45:
cv2.arrowedLine(im_model, (point_i["raw_pointx"][0], point_i["raw_pointy"][0]), (point_i["raw_pointx"][1], point_i["raw_pointy"][1]), (0, 255, 0), 1, cv2.LINE_AA)
cv2.arrowedLine(im_model, (point_i["raw_pointx"][1], point_i["raw_pointy"][1]), (point_i["raw_pointx"][2], point_i["raw_pointy"][2]), (255, 255, 0), 1, cv2.LINE_AA)
cv2.arrowedLine(im_model, (point_i["raw_pointx"][2], point_i["raw_pointy"][2]), (point_i["raw_pointx"][3], point_i["raw_pointy"][3]), (255, 255, 0), 1, cv2.LINE_AA)
cv2.arrowedLine(im_model, (point_i["raw_pointx"][3], point_i["raw_pointy"][3]), (point_i["raw_pointx"][0], point_i["raw_pointy"][0]), (255, 255, 0), 1, cv2.LINE_AA)
zh_model = "/ai/TopViewMul/4/psd_out/" + tensorFile.split('/')[-1][:-8] + '_model.bmp'
cv2.imwrite(zh_model, im_model)
if DEBUG_DRAW_MODEL_SWAP:
im_model_swap = cv2.resize(im0, (MODEL_IN_H, MODEL_IN_W))
for point_i in point_all:
if point_i.get("raw_pointx") is None:
continue
if point_i["delrule"] == 0 and point_i["conf"] > 0.45:
cv2.arrowedLine(im_model_swap, (point_i["raw_pointx"][0], point_i["raw_pointy"][0]), (point_i["raw_pointx"][1], point_i["raw_pointy"][1]), (0, 255, 0), 1, cv2.LINE_AA)
cv2.arrowedLine(im_model_swap, (point_i["raw_pointx"][1], point_i["raw_pointy"][1]), (point_i["raw_pointx"][2], point_i["raw_pointy"][2]), (255, 255, 0), 1, cv2.LINE_AA)
cv2.arrowedLine(im_model_swap, (point_i["raw_pointx"][2], point_i["raw_pointy"][2]), (point_i["raw_pointx"][3], point_i["raw_pointy"][3]), (255, 255, 0), 1, cv2.LINE_AA)
cv2.arrowedLine(im_model_swap, (point_i["raw_pointx"][3], point_i["raw_pointy"][3]), (point_i["raw_pointx"][0], point_i["raw_pointy"][0]), (255, 255, 0), 1, cv2.LINE_AA)
zh_model_swap = "/ai/TopViewMul/4/psd_out/" + tensorFile.split('/')[-1][:-8] + '_model_swap.bmp'
cv2.imwrite(zh_model_swap, im_model_swap)
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)
------------------------------------------------
版权声明:本文为CSDN博主「weixin_39544891」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_39544891/article/details/157259451
我已经在 draw_tensor2psd.py 里加了调试输出,现在会额外生成一张"模型输入尺寸坐标系"的可视化图,文件名是 *_model.bmp(跟原输出同目录)。这张图直接用原始坐标(未缩放)画在 608×736 的图上,用来判断"坐标本身是否正确"。
你现在遇到"仍不对",请按这个顺序排查:
1) 先看 _model.bmp 是否正确(最关键)
- 如果 _model.bmp 是正确的
→ 说明解码坐标没问题,问题一定在"映射回原图"
→ 下一步只需要检查:
- 原图尺寸是否真的是 480×544
- MODEL_IN_W/H 是否确认为 608×736
- 是否存在"用错了原图文件"的情况(图不是推理时用的那张)
- 如果 _model.bmp 也不正确
→ 说明问题在下位机解码/尺寸理解
→ 需要继续检查 inWidth/inHeight 是否与真实模型输入一致
→ 或者 inWidth/inHeight 在下位机实际是"反过来的"(W/H 颠倒)
2) 确认下位机实际输入尺寸
在 main.c 的 readInput() 里,已经打印了:
Image Pre processing for image of size %d x %d
你要确认输出里是:
- 原图:480×544
- 模型输入:608×736
如果这里打印的原图不是 480×544,说明你画的原图和推理用的原图不是同一张。
3) 快速验证 W/H 是否颠倒
你可以临时改一下:
MODEL_IN_W = 736
MODEL_IN_H = 608
如果这样 _model.bmp 反而更对,说明 W/H 在某处被当成 H/W 了(常见于配置或导出阶段)。
4) 验证 raw 坐标范围
在 draw_tensor2psd.py 里随便打印一个框的 raw 坐标:
if i == 0:
print("raw:", raw_x1, raw_y1, raw_x2, raw_y2, raw_x3, raw_y3, raw_x4, raw_y4)
正常情况下,raw 坐标应该落在:
- x ∈ [0, 608]
- y ∈ [0, 736]
如果超出很多,解码逻辑或尺度还不对。
5) 请你回传这两张图
- 原输出(缩放到原图)
- _model.bmp 输出
我可以直接对比两张图判断问题在哪一层。
如果你愿意,我也可以把脚本再升级成:
一次输出三张图(原图、模型输入图、W/H 交换图),这样一眼就能判断错在哪里。
已升级:现在会输出 三张图,用于快速定位 W/H 是否颠倒或映射有误。
输出文件:
- 原图坐标(已缩放回原图):*_psd.bmp(原逻辑)
- 模型输入坐标:*_model.bmp(608×736)
- 交换 W/H 坐标:*_model_swap.bmp(736×608)
只要对比 _model.bmp 和 _model_swap.bmp 哪张更像"正确结果",就能判断 W/H 是否被某个环节搞反。
你明天跑完后,把三张图的效果描述或截图发我,我帮你继续定位。
下面是明天白天你在公司可以独立完成的排查清单,按优先级从"最有效"到"次要"排,尽量让你一次跑完把关键证据拿全:
1) 产出三张图(你现在的脚本已支持)
- *_psd.bmp(原图坐标)
- *_model.bmp(模型输入坐标 608×736)
- *_model_swap.bmp(交换 W/H)
目标:判断坐标本身是否正确、是否 W/H 被反、是否只是映射问题。
2) 打印输入/输出的真实尺寸(主证据)
在下位机运行时,记录以下日志(main.c 里已有):
- 原图尺寸:Image Pre processing for image of size W x H
- 网络输入尺寸:inWidth/inHeight
- 输出张量尺寸:outWidth/outHeight/outNumChannels
目标:确认"实际运行尺寸"和"你设定的尺寸"一致。
3) 验证 raw 坐标范围(最直观)
在 draw_tensor2psd.py 里临时加一行,只打印第一个检测框的 raw 坐标:
if i == 0:
print("raw:", raw_x1, raw_y1, raw_x2, raw_y2, raw_x3, raw_y3, raw_x4, raw_y4)
预期:
x 在 0~608、y 在 0~736 之间(如果不是,说明解码或尺寸理解仍不对)。
4) 排除"图像不是同一张"的问题
确认:
- draw_tensor2psd.py 读取的图片名
和
- 下位机推理使用的图片名
必须一致,否则映射一定错。
5) 快速排除 W/H 颠倒
你可以临时设置:
MODEL_IN_W = 736
MODEL_IN_H = 608
跑一张图看 _model_swap.bmp 是否明显更对。
6) 校验 bin 输出结构是否正常
你的 bin 每个目标 20 个 int(fwrite(&num0, 4, 20, fp)),所以:
- len(infer_data) % 20 == 0
- soltnum = len(infer_data)/20 正常
如果不是 20 的倍数,说明输出结构与解析不一致。
7) 如果还是不准,拿到"对照组"
同一张图在 PC 端(上位机)推理可视化一次,和下位机结果对比。
- 若上位机对,下位机错 → 说明下位机解码流程不一致
- 若上位机也错 → 说明训练/导出或 anchor/输出格式不一致
8) 若有时间:固定一张样本做最小复现
- 只跑一张图
- 保存原图、bin、三张可视化图
这样第二天我们直接定位不用再复现场景。
你明天做完后,只要把这四样信息发我,就能继续快速定位:
-
三张图中哪张最正确(psd / model / swap)
-
下位机日志:原图尺寸 & inWidth/inHeight
-
raw 坐标范围(打印一条)
-
你确认的"图片名是否一致"
这样我们大概率能一次定位到问题根因。