Files
detecttracking/contrast/one2n_contrast.py
2025-01-21 18:22:56 +08:00

288 lines
8.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- 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.event import ShoppingEvent
def init_eventdict(sourcePath, stype="data"):
'''stype: str,
'source': 由 videos 或 images 生成的 pickle 文件
'data': 从 data 文件中读取的现场运行数据
'''
k, errEvents = 0, []
for bname in os.listdir(sourcePath):
# bname = r"20241126-135911-bdf91cf9-3e9a-426d-94e8-ddf92238e175_6923555210479"
source_path = os.path.join(sourcePath, bname)
if stype=="data":
pickpath = os.path.join(eventDataPath, f"{bname}.pickle")
if not os.path.isdir(source_path) or os.path.isfile(pickpath):
continue
if stype=="source":
pickpath = os.path.join(eventDataPath, bname)
if not os.path.isfile(source_path) or os.path.isfile(pickpath):
continue
try:
event = ShoppingEvent(source_path, stype)
with open(pickpath, 'wb') as f:
pickle.dump(event, f)
print(bname)
except Exception as e:
errEvents.append(source_path)
print(e)
# k += 1
# if k==1:
# break
errfile = os.path.join(resultPath, 'error_events.txt')
with open(errfile, 'a', encoding='utf-8') as f:
for line in errEvents:
f.write(line + '\n')
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, typee=None):
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 typee==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: 以其它方式选择特征计算相似度
'''
tpevents, fnevents, fpevents, tnevents = [], [], [], []
tpsimi, fnsimi, tnsimi, fpsimi = [], [], [], []
one2nFile, errorFile_one2n = [], []
for evtname, event in evtDicts.items():
evt_names, evt_barcodes, evt_similars, evt_types = [], [], [], []
if len(event.barcode)==0:
continue
for ndict in event.one2n:
nname = ndict["event"]
barcode = ndict["barcode"]
similar = ndict["similar"]
typee = ndict["type"].strip()
evt_names.append(nname)
evt_barcodes.append(barcode)
evt_types.append(typee)
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:
o2nevt = o2n_evt[0]
else:
continue
if pattern==2:
simival = simi_calc(event, o2nevt, typee)
if pattern==3:
simival = simi_calc(event, o2nevt, typee=pattern)
if simival==None:
continue
evt_similars.append(simival)
## 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) and len(evt_barcodes)==len(evt_similars) \
and 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:
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/(len(one2nFile)+1e-6))
NPrecise.append(TN/(TN+FN+1e-6))
NRecall.append(TN/(len(tnsimi)+len(fpsimi)+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.grid(True)
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, stype="data")
'''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\测试视频数据以及日志\海外展厅测试数据\比对数据"
resultPath = r"\\192.168.1.28\share\测试视频数据以及日志\海外展厅测试数据\testing"
eventDataPath = os.path.join(resultPath, "evtobjs")
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()