This commit is contained in:
王庆刚
2025-03-13 15:36:29 +08:00
parent 0efe8892f3
commit 9b5b135fa3
21 changed files with 837 additions and 258 deletions

View File

@ -58,6 +58,7 @@ from feat_extract.inference import FeatsInterface
from utils.event import ShoppingEvent, save_data
from genfeats import gen_bcd_features
from event_test import calc_simil
from one2n_contrast import init_eventDict
@ -271,8 +272,12 @@ def build_std_evt_dict():
evtDict = {}
for evtname, barcode in evtList:
evtpath = os.path.join(eventDataPath, evtname+'.pickle')
with open(evtpath, 'rb') as f:
evtdata = pickle.load(f)
try:
with open(evtpath, 'rb') as f:
evtdata = pickle.load(f)
except Exception as e:
print(evtname)
evtDict[evtname] = evtdata
return evtList, evtDict, stdDict
@ -300,7 +305,8 @@ def one2SN_pr(evtList, evtDict, stdDict):
event = evtDict[evtname]
## 无轨迹判断
if len(event.front_feats)+len(event.back_feats)==0:
print(evtname)
errorFile_one2SN.append(evtname)
print(f"No trajectory: {evtname}")
continue
barcodes, similars = [], []
@ -351,10 +357,10 @@ def one2SN_pr(evtList, evtDict, stdDict):
FNX = sum(np.array(fn_simi) < th)
TNX = sum(np.array(tn_simi) < th)
PPreciseX.append(TPX/(TPX+FPX+1e-6))
PRecallX.append(TPX/(len(tp_simi)+len(fn_simi)+1e-6))
PRecallX.append(TPX/(TPX+FNX+1e-6))
NPreciseX.append(TNX/(TNX+FNX+1e-6))
NRecallX.append(TNX/(len(tn_simi)+len(fp_simi)+1e-6))
NRecallX.append(TNX/(TNX+FPX+1e-6))
fig, ax = plt.subplots()
ax.plot(Thresh, PPreciseX, 'r', label='Precise_Pos: TP/TPFP')
@ -363,9 +369,11 @@ def one2SN_pr(evtList, evtDict, stdDict):
ax.plot(Thresh, NRecallX, 'c', label='Recall_Neg: TN/TNFN')
ax.set_xlim([0, 1])
ax.set_ylim([0, 1])
ax.grid(True)
ax.set_xticks(np.arange(0, 1, 0.1))
ax.set_yticks(np.arange(0, 1, 0.1))
ax.grid(True, linestyle='--')
ax.set_title('1:SN Precise & Recall')
ax.set_xlabel(f"Event Num: {len(evtList)}")
ax.set_xlabel(f"Event Num: {len(tp_events) + len(fn_events)}")
ax.legend()
plt.show()
## ============================= 1:N 展厅 直方图'''
@ -403,10 +411,14 @@ def one2one_simi(evtList, evtDict, stdDict):
'''======2 计算事件、标准特征集相似度 =================='''
rltdata = []
errorFile_one2one = []
for i in range(len(mergePairs)):
evtname, stdbcd, label = mergePairs[i]
event = evtDict[evtname]
if len(event.feats_compose)==0: continue
if len(event.feats_compose)==0:
errorFile_one2one.append(evtname)
continue
stdfeat = stdDict[stdbcd] # float32
@ -418,11 +430,16 @@ def one2one_simi(evtList, evtDict, stdDict):
'''================ float32、16、int8 精度比较与存储 ============='''
# data_precision_compare(stdfeat, evtfeat, mergePairs[i], save=True)
return rltdata
errorFile_one2one = list(set(errorFile_one2one))
return rltdata, errorFile_one2one
def one2one_pr(rltdata):
def one2one_pr(evtList, evtDict, stdDict):
rltdata, errorFile_one2one = one2one_simi(evtList, evtDict, stdDict)
Same, Cross = [], []
for label, stdbcd, evtname, simi_mean, simi_max, simi_mft in rltdata:
if label == "same":
@ -451,27 +468,41 @@ def one2one_pr(rltdata):
Correct = []
Thresh = np.linspace(-0.2, 1, 100)
for th in Thresh:
TP = np.sum(Same > th)
FN = TPFN - TP
TP = np.sum(Same >= th)
FN = np.sum(Same < th)
# FN = TPFN - TP
TN = np.sum(Cross < th)
FP = TNFP - TN
FP = np.sum(Cross >= th)
# FP = TNFP - TN
Recall_Pos.append(TP/TPFN)
Recall_Neg.append(TN/TNFP)
Precision_Pos.append(TP/(TP+FP+1e-6))
Precision_Neg.append(TN/(TN+FN+1e-6))
Recall_Pos.append(TP/(TP+FN+1e-6))
Recall_Neg.append(TN/(TN+FP+1e-6))
# Recall_Pos.append(TP/TPFN)
# Recall_Neg.append(TN/TNFP)
Correct.append((TN+TP)/(TPFN+TNFP))
fig, ax = plt.subplots()
ax.plot(Thresh, Correct, 'r', label='Correct: (TN+TP)/(TPFN+TNFP)')
ax.plot(Thresh, Precision_Pos, 'r', label='Precision_Pos: TP/(TP+FP)')
ax.plot(Thresh, Recall_Pos, 'b', label='Recall_Pos: TP/TPFN')
ax.plot(Thresh, Recall_Neg, 'g', label='Recall_Neg: TN/TNFP')
ax.plot(Thresh, Precision_Pos, 'c', label='Precision_Pos: TP/(TP+FP)')
ax.plot(Thresh, Correct, 'c', label='Correct: (TN+TP)/(TPFN+TNFP)')
ax.plot(Thresh, Precision_Neg, 'm', label='Precision_Neg: TN/(TN+FN)')
ax.set_xlim([0, 1])
ax.set_ylim([0, 1])
ax.grid(True)
ax.set_xticks(np.arange(0, 1, 0.1))
ax.set_yticks(np.arange(0, 1, 0.1))
ax.grid(True, linestyle='--')
ax.set_title('PrecisePos & PreciseNeg')
ax.set_xlabel(f"Same Num: {TPFN}, Cross Num: {TNFP}")
ax.legend()
@ -506,23 +537,17 @@ def gen_eventdict(sourcePath, saveimg=True):
## 兼容事件的两种情况:文件夹 和 Yolo-Resnet-Tracker 的输出
if os.path.isfile(source_path):
bname, ext = os.path.splitext(bname)
evt = bname.split("_")
# evt = bname.split("_")
evt = bname.split('_')
condt = len(evt)>=2 and evt[-1].isdigit() and len(evt[-1])>=10
if not condt: continue
# bname = r"20241126-135911-bdf91cf9-3e9a-426d-94e8-ddf92238e175_6923555210479"
# source_path = os.path.join(evtpath, bname)
# 如果已完成事件生成,则不执行
pickpath = os.path.join(eventDataPath, f"{bname}.pickle")
if os.path.isfile(pickpath): continue
# event = ShoppingEvent(source_path, stype=source_type)
# with open(pickpath, 'wb') as f:
# pickle.dump(event, f)
try:
event = ShoppingEvent(source_path, stype=source_type)
# save_data(event, resultPath)
@ -538,16 +563,44 @@ def gen_eventdict(sourcePath, saveimg=True):
# if k==1:
# break
errfile = os.path.join(resultPath, 'error_events.txt')
# with open(errfile, 'w', encoding='utf-8') as f:
# for line in errEvents:
# f.write(line + '\n')
def init_std_evt_dict():
'''==== 0. 生成事件列表和对应的 Barcodes列表 ==========='''
bcdList, event_spath = [], []
# def init_std_evt_dict():
# '''==== 0. 生成事件列表和对应的 Barcodes列表 ==========='''
# bcdList, event_spath = [], []
# for evtname in os.listdir(eventSourcePath):
# bname, ext = os.path.splitext(evtname)
# ## 处理事件的两种情况:文件夹 和 Yolo-Resnet-Tracker 的输出
# fpath = os.path.join(eventSourcePath, evtname)
# if os.path.isfile(fpath) and (ext==".pkl" or ext==".pickle"):
# evt = bname.split('_')
# elif os.path.isdir(fpath):
# evt = evtname.split('_')
# else:
# continue
# if len(evt)>=2 and evt[-1].isdigit() and len(evt[-1])>=10:
# bcdList.append(evt[-1])
# event_spath.append(fpath)
# '''==== 1. 生成标准特征集, 只需运行一次, 在 genfeats.py 中实现 ==========='''
# bcdSet = set(bcdList)
# gen_bcd_features(stdSamplePath, stdBarcodePath, stdFeaturePath, bcdSet)
# print("stdFeats have generated and saved!")
# '''==== 2. 生成事件字典, 只需运行一次 ==============='''
# gen_eventdict(event_spath)
# print("eventList have generated and saved!")
def get_evtList():
'''==== 0. 生成事件列表和对应的 Barcodes 集合 ==========='''
bcdList, evtpaths = [], []
for evtname in os.listdir(eventSourcePath):
bname, ext = os.path.splitext(evtname)
@ -562,46 +615,73 @@ def init_std_evt_dict():
if len(evt)>=2 and evt[-1].isdigit() and len(evt[-1])>=10:
bcdList.append(evt[-1])
event_spath.append(fpath)
'''==== 1. 生成标准特征集, 只需运行一次, 在 genfeats.py 中实现 ==========='''
bcdSet = set(bcdList)
gen_bcd_features(stdSamplePath, stdBarcodePath, stdFeaturePath, bcdSet)
print("stdFeats have generated and saved!")
'''==== 2. 生成事件字典, 只需运行一次 ==============='''
gen_eventdict(event_spath)
print("eventList have generated and saved!")
evtpaths.append(fpath)
bcdSet = set(bcdList)
return evtpaths, bcdSet
def test_one2one():
# def init_stdDict():
# evtpaths, bcdSet = get_evtList()
# gen_bcd_features(stdSamplePath, stdBarcodePath, stdFeaturePath, bcdSet)
# print("stdFeats have generated and saved!")
# def init_evtDict():
# '''==== 0. 生成事件列表和对应的 Barcodes列表 ==========='''
# bcdList, event_spath = [], []
# for evtname in os.listdir(eventSourcePath):
# bname, ext = os.path.splitext(evtname)
# ## 处理事件的两种情况:文件夹 和 Yolo-Resnet-Tracker 的输出
# fpath = os.path.join(eventSourcePath, evtname)
# if os.path.isfile(fpath) and (ext==".pkl" or ext==".pickle"):
# evt = bname.split('_')
# elif os.path.isdir(fpath):
# evt = evtname.split('_')
# else:
# continue
# if len(evt)>=2 and evt[-1].isdigit() and len(evt[-1])>=10:
# bcdList.append(evt[-1])
# event_spath.append(fpath)
# '''==== 2. 生成事件字典, 只需运行一次 ==============='''
# gen_eventdict(event_spath)
# print("eventList have generated and saved!")
def test_one2one_one2SN():
'''1:1性能评估'''
# 1. 只需运行一次,生成事件字典和相应的标准特征库字典
# init_std_evt_dict()
# evtpaths, bcdSet = get_evtList()
# 2. 基于事件barcode集和标准库barcode交集构造事件集合
evtList, evtDict, stdDict = build_std_evt_dict()
'''=== 1. 只需运行一次,生成事件对应的标准特征库字典,如已生成,无需运行 ===='''
# gen_bcd_features(stdSamplePath, stdBarcodePath, stdFeaturePath, eventSourcePath)
rltdata = one2one_simi(evtList, evtDict, stdDict)
'''==== 2. 生成事件字典, 只需运行一次 ===================='''
one2one_pr(rltdata)
# date_ = ['2025-3-4_1', '2025-3-5_1', '2025-3-5_2']
# for dt in date_:
# evtpaths = os.path.join(eventSourcePath, dt)
# init_eventDict(evtpaths, eventDataPath, source_type)
init_eventDict(eventSourcePath, eventDataPath, source_type)
def test_one2SN():
'''1:SN性能评估'''
# 1. 只需运行一次,生成事件字典和相应的标准特征库字典
# init_std_evt_dict()
# 2. 事件barcode集和标准库barcode求交集
'''==== 2. 基于事件barcode集和标准库barcode交集构造事件集合 ========='''
evtList, evtDict, stdDict = build_std_evt_dict()
one2SN_pr(evtList, evtDict, stdDict)
one2one_pr(evtList, evtDict, stdDict)
one2SN_pr(evtList, evtDict, stdDict)
if __name__ == '__main__':
'''
共7个地址
@ -627,32 +707,30 @@ if __name__ == '__main__':
stdSamplePath = r"\\192.168.1.28\share\数据\已完成数据\比对数据\barcode\all_totalBarocde\totalBarcode"
stdBarcodePath = r"\\192.168.1.28\share\测试视频数据以及日志\全实时测试\testing\bcdpath"
stdFeaturePath = r"\\192.168.1.28\share\测试视频数据以及日志\全实时测试\testing\stdfeats"
stdFeaturePath = r"\\192.168.1.28\share\数据\已完成数据\比对数据\barcode\all_totalBarocde\features_json\v11_barcode_0304"
if not os.path.exists(stdBarcodePath):
os.makedirs(stdBarcodePath)
if not os.path.exists(stdFeaturePath):
os.makedirs(stdFeaturePath)
'''source_type:
"source": eventSourcePath 为 Yolo-Resnet-Tracker 输出的 pickle 文件
"data": 基于事件切分的原 data 文件版本
"realtime": 全实时生成的 data 文件
'''
source_type:
"source": eventSourcePath 为 Yolo-Resnet-Tracker 输出的 pickle 文件
"data": eventSourcePath 为 包含 data 文件的文件夹
'''
source_type = 'realtime' # 'source', 'data', 'realtime'
eventSourcePath = r"\\192.168.1.28\share\测试视频数据以及日志\全实时测试\V12\2025-2-21\比对\video"
source_type = 'realtime' # 'source', 'data', 'realtime'
eventSourcePath = r"\\192.168.1.28\share\测试视频数据以及日志\全实时测试\V12\基准数据集\2025-3-4_1"
resultPath = r"\\192.168.1.28\share\测试视频数据以及日志\全实时测试\testing"
eventDataPath = os.path.join(resultPath, "evtobjs_data")
similPath = os.path.join(resultPath, "simidata_data")
eventDataPath = os.path.join(resultPath, "evtobjs_0304_1")
similPath = os.path.join(resultPath, "simidata_0304_1")
if not os.path.exists(eventDataPath):
os.makedirs(eventDataPath)
if not os.path.exists(similPath):
os.makedirs(similPath)
test_one2one()
test_one2SN()
test_one2one_one2SN()