# -*- coding: utf-8 -*- """ Created on Wed Dec 18 11:49:01 2024 @author: ym """ import os import pickle import numpy as np from pathlib import Path import matplotlib.pyplot as plt from scipy.spatial.distance import cdist from utils.tools import init_eventDict def read_eventdict(eventDataPath): evtDict = {} for filename in os.listdir(eventDataPath): evtname, ext = os.path.splitext(filename) if ext != ".pickle": continue evtpath = os.path.join(eventDataPath, filename) with open(evtpath, 'rb') as f: evtdata = pickle.load(f) evtDict[evtname] = evtdata return evtDict def simi_calc(event, o2nevt, pattern, typee=None): if pattern==1 or pattern==2: if typee == "11": boxes1 = event.front_boxes boxes2 = o2nevt.front_boxes feat1 = event.front_feats feat2 = o2nevt.front_feats if typee == "10": boxes1 = event.front_boxes boxes2 = o2nevt.back_boxes feat1 = event.front_feats feat2 = o2nevt.back_feats if typee == "00": boxes1 = event.back_boxes boxes2 = o2nevt.back_boxes feat1 = event.back_feats feat2 = o2nevt.back_feats if typee == "01": boxes1 = event.back_boxes boxes2 = o2nevt.front_boxes feat1 = event.back_feats feat2 = o2nevt.front_feats '''自定义事件特征选择''' if pattern==3 and len(event.feats_compose) and len(o2nevt.feats_compose): feat1 = [event.feats_compose] feat2 = [o2nevt.feats_compose] if len(feat1) and len(feat2): matrix = 1 - cdist(feat1[0], feat2[0], 'cosine') simi = np.mean(matrix) else: simi = None return simi def one2n_pr(evtDicts, pattern=1): ''' pattern: 1: process.data 中记录的相似度 2: 根据 process.data 中标记的 type 选择特征组合方式计算相似度 3: 利用 process.data 中的轨迹特征,以其它方式计算相似度 ''' tpevents, fnevents, fpevents, tnevents = [], [], [], [] tpsimi, fnsimi, tnsimi, fpsimi = [], [], [], [] one2nFile, errorFile_one2n = [], [] errorFile_one2n_ = [] evts_output = [] for evtname, event in evtDicts.items(): evt_names, evt_barcodes, evt_similars, evt_types = [], [], [], [] if len(event.one2n)==0 or len(event.barcode)==0: continue evts_output.append(evtname) for ndict in event.one2n: nname = ndict["event"] barcode = ndict["barcode"] similar = ndict["similar"] typee = ndict["type"].strip() if len(barcode)==0: continue if typee.find(",") >=0: typee = typee.split(",")[-1] if pattern==1: evt_similars.append(similar) if pattern==2 or pattern==3: o2n_evt = [evt for name, evt in evtDicts.items() if name.find(nname[:15])==0] if len(o2n_evt)!=1: continue simival = simi_calc(event, o2n_evt[0], pattern, typee) if simival==None: continue evt_similars.append(simival) evt_names.append(nname) evt_barcodes.append(barcode) evt_types.append(typee) # if evtname == "20250226-170321-327_6903244678377": # print("evtname") ## process.data的oneTon的各项中,均不包括当前事件的barcode if event.barcode not in evt_barcodes: errorFile_one2n.append(evtname) continue else: one2nFile.append(evtname) if len(evt_names)==len(evt_barcodes)==len(evt_similars)==len(evt_types) and len(evt_names)>0: # maxsim = evt_similars[evt_similars.index(max(evt_similars))] maxsim = max(evt_similars) for i in range(len(evt_names)): bcd, simi = evt_barcodes[i], evt_similars[i] if bcd==event.barcode and simi==maxsim: tpsimi.append(simi) tpevents.append(evtname) elif bcd==event.barcode and simi!=maxsim: fnsimi.append(simi) fnevents.append(evtname) elif bcd!=event.barcode and simi!=maxsim: tnsimi.append(simi) tnevents.append(evtname) elif bcd!=event.barcode and simi==maxsim and event.barcode in evt_barcodes: fpsimi.append(simi) fpevents.append(evtname) else: errorFile_one2n_.append(evtname) ''' 1:n 数据存储,需根据相似度排序''' PPrecise, PRecall = [], [] NPrecise, NRecall = [], [] Thresh = np.linspace(-0.2, 1, 100) for th in Thresh: '''============================= 1:n 计算''' TP = sum(np.array(tpsimi) >= th) FP = sum(np.array(fpsimi) >= th) FN = sum(np.array(fnsimi) < th) TN = sum(np.array(tnsimi) < th) PPrecise.append(TP/(TP+FP+1e-6)) PRecall.append(TP/(TP+FN+1e-6)) NPrecise.append(TN/(TN+FN+1e-6)) NRecall.append(TN/(TN+FP+1e-6)) '''4. ============================= 1:n 曲线,''' fig, ax = plt.subplots() ax.plot(Thresh, PPrecise, 'r', label='Precise_Pos: TP/TPFP') ax.plot(Thresh, PRecall, 'b', label='Recall_Pos: TP/TPFN') ax.plot(Thresh, NPrecise, 'g', label='Precise_Neg: TN/TNFP') ax.plot(Thresh, NRecall, 'c', label='Recall_Neg: TN/TNFN') ax.set_xlim([0, 1]) ax.set_ylim([0, 1]) 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:n Precise & Recall') ax.set_xlabel(f"Event Num: {len(one2nFile)}") ax.legend() plt.show() ## ============================= 1:n 直方图''' fig, axes = plt.subplots(2, 2) axes[0, 0].hist(tpsimi, bins=60, range=(-0.2, 1), edgecolor='black') axes[0, 0].set_xlim([-0.2, 1]) axes[0, 0].set_title(f'TP: {len(tpsimi)}') axes[0, 1].hist(fpsimi, bins=60, range=(-0.2, 1), edgecolor='black') axes[0, 1].set_xlim([-0.2, 1]) axes[0, 1].set_title(f'FP: {len(fpsimi)}') axes[1, 0].hist(tnsimi, bins=60, range=(-0.2, 1), edgecolor='black') axes[1, 0].set_xlim([-0.2, 1]) axes[1, 0].set_title(f'TN: {len(tnsimi)}') axes[1, 1].hist(fnsimi, bins=60, range=(-0.2, 1), edgecolor='black') axes[1, 1].set_xlim([-0.2, 1]) axes[1, 1].set_title(f'FN: {len(fnsimi)}') plt.show() return fpevents def main(): '''1. 生成事件字典并保存至 eventDataPath, 只需运行一次 ''' init_eventDict(eventSourcePath, eventDataPath, stype="realtime") # 'source', 'data', 'realtime' # for pfile in os.listdir(eventDataPath): # evt = os.path.splitext(pfile)[0].split('_') # cont = len(evt)>=2 and evt[-1].isdigit() and len(evt[-1])>=10 # if not cont: # continue '''2. 读取事件字典 ''' evtDicts = read_eventdict(eventDataPath) '''3. 1:n 比对事件评估 ''' fpevents = one2n_pr(evtDicts, pattern=1) fpErrFile = str(Path(resultPath).joinpath("one2n_fp_Error.txt")) with open(fpErrFile, "w") as file: for item in fpevents: file.write(item + "\n") if __name__ == '__main__': eventSourcePath = r"\\192.168.1.28\share\测试视频数据以及日志\全实时测试\V12\2025-3-4_2" resultPath = r"\\192.168.1.28\share\测试视频数据以及日志\全实时测试\testing" eventDataPath = os.path.join(resultPath, "evtobjs_wang") if not os.path.exists(eventDataPath): os.makedirs(eventDataPath) # similPath = os.path.join(resultPath, "simidata") # if not os.path.exists(similPath): # os.makedirs(similPath) main()