diff --git a/contrast/event_test.py b/contrast/event_test.py new file mode 100644 index 0000000..b148825 --- /dev/null +++ b/contrast/event_test.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +""" +Created on Mon Dec 16 18:56:18 2024 + +@author: ym +""" +import os +import cv2 + +from utils.event import ShoppingEvent + +def main(): + evtpaths = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\images" + text1 = "one2n_Error.txt" + text2 = "one2SN_Error.txt" + events = [] + text = (text1, text2) + for txt in text: + txtfile = os.path.join(evtpaths, txt) + with open(txtfile, "r") as f: + lines = f.readlines() + for i, line in enumerate(lines): + line = line.strip() + if line: + fpath=os.path.join(evtpaths, line) + events.append(fpath) + + + events = list(set(events)) + + '''定义当前事件存储地址及生成相应文件件''' + resultPath = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\result" + for evtpath in events: + evtname = os.path.basename(evtpath) + event = ShoppingEvent(evtpath) + + img_cat = event.draw_tracks() + trajpath = os.path.join(resultPath, "trajectory") + if not os.path.exists(trajpath): + os.makedirs(trajpath) + traj_imgpath = os.path.join(trajpath, evtname+".png") + cv2.imwrite(traj_imgpath, img_cat) + + + ## 保存序列图像和轨迹子图 + subimgpath = os.path.join(resultPath, f"{evtname}", "subimg") + imgspath = os.path.join(resultPath, f"{evtname}", "imgs") + if not os.path.exists(subimgpath): + os.makedirs(subimgpath) + if not os.path.exists(imgspath): + os.makedirs(imgspath) + + + subimgpairs = event.save_event_subimg(subimgpath) + for subimgName, subimg in subimgpairs: + spath = os.path.join(subimgpath, subimgName) + cv2.imwrite(spath, subimg) + + imgpairs = event.plot_save_image(imgspath) + for imgname, img in imgpairs: + spath = os.path.join(imgspath, imgname) + cv2.imwrite(spath, img) + + print(f"{evtname}") + + + +if __name__ == "__main__": + main() diff --git a/contrast/one2one_contrast.py b/contrast/one2one_contrast.py index 663d16f..f6b8177 100644 --- a/contrast/one2one_contrast.py +++ b/contrast/one2one_contrast.py @@ -84,82 +84,84 @@ def ft16_to_uint8(arr_ft16): return arr_uint8, arr_ft16_ -def plot_save_image(event, savepath): - cameras = ('front', 'back') - for camera in cameras: - if camera == 'front': - boxes = event.front_trackerboxes - imgpaths = event.front_imgpaths - else: - boxes = event.back_trackerboxes - imgpaths = event.back_imgpaths - - def array2list(bboxes): - '''[x1, y1, x2, y2, track_id, score, cls, frame_index, box_index]''' - frame_ids = bboxes[:, 7].astype(int) - fID = np.unique(bboxes[:, 7].astype(int)) - fboxes = [] - for f_id in fID: - idx = np.where(frame_ids==f_id)[0] - box = bboxes[idx, :] - fboxes.append((f_id, box)) - return fboxes - - fboxes = array2list(boxes) - - for fid, fbox in fboxes: - imgpath = imgpaths[int(fid-1)] - - image = cv2.imread(imgpath) - - annotator = Annotator(image.copy(), line_width=2) - for i, *xyxy, tid, score, cls, fid, bid in enumerate(fbox): - label = f'{int(id), int(cls)}' - if tid >=0 and cls==0: - color = colors(int(cls), True) - elif tid >=0 and cls!=0: - color = colors(int(id), True) - else: - color = colors(19, True) # 19为调色板的最后一个元素 - annotator.box_label(xyxy, label, color=color) - - im0 = annotator.result() - spath = os.path.join(savepath, Path(imgpath).name) - cv2.imwrite(spath, im0) - - -def save_event_subimg(event, savepath): - ''' - 功能: 保存一次购物事件的轨迹子图 - 9 items: barcode, type, filepath, back_imgpaths, front_imgpaths, - back_boxes, front_boxes, back_feats, front_feats, - feats_compose, feats_select - 子图保存次序:先前摄、后后摄,以 k 为编号,和 "feats_compose" 中次序相同 - ''' - cameras = ('front', 'back') - for camera in cameras: - if camera == 'front': - boxes = event.front_boxes - imgpaths = event.front_imgpaths - else: - boxes = event.back_boxes - imgpaths = event.back_imgpaths - - for i, box in enumerate(boxes): - x1, y1, x2, y2, tid, score, cls, fid, bid = box - - imgpath = imgpaths[int(fid-1)] - image = cv2.imread(imgpath) - - subimg = image[int(y1/2):int(y2/2), int(x1/2):int(x2/2), :] - - camerType, timeTamp, _, frameID = os.path.basename(imgpath).split('.')[0].split('_') - subimgName = f"cam{camerType}_{i}_tid{int(tid)}_fid({int(fid)}, {frameID}).png" - spath = os.path.join(savepath, subimgName) - - cv2.imwrite(spath, subimg) - # basename = os.path.basename(event['filepath']) - print(f"Image saved: {os.path.basename(event.eventpath)}") +# ============================================================================= +# def plot_save_image(event, savepath): +# cameras = ('front', 'back') +# for camera in cameras: +# if camera == 'front': +# boxes = event.front_trackerboxes +# imgpaths = event.front_imgpaths +# else: +# boxes = event.back_trackerboxes +# imgpaths = event.back_imgpaths +# +# def array2list(bboxes): +# '''[x1, y1, x2, y2, track_id, score, cls, frame_index, box_index]''' +# frame_ids = bboxes[:, 7].astype(int) +# fID = np.unique(bboxes[:, 7].astype(int)) +# fboxes = [] +# for f_id in fID: +# idx = np.where(frame_ids==f_id)[0] +# box = bboxes[idx, :] +# fboxes.append((f_id, box)) +# return fboxes +# +# fboxes = array2list(boxes) +# +# for fid, fbox in fboxes: +# imgpath = imgpaths[int(fid-1)] +# +# image = cv2.imread(imgpath) +# +# annotator = Annotator(image.copy(), line_width=2) +# for i, *xyxy, tid, score, cls, fid, bid in enumerate(fbox): +# label = f'{int(id), int(cls)}' +# if tid >=0 and cls==0: +# color = colors(int(cls), True) +# elif tid >=0 and cls!=0: +# color = colors(int(id), True) +# else: +# color = colors(19, True) # 19为调色板的最后一个元素 +# annotator.box_label(xyxy, label, color=color) +# +# im0 = annotator.result() +# spath = os.path.join(savepath, Path(imgpath).name) +# cv2.imwrite(spath, im0) +# +# +# def save_event_subimg(event, savepath): +# ''' +# 功能: 保存一次购物事件的轨迹子图 +# 9 items: barcode, type, filepath, back_imgpaths, front_imgpaths, +# back_boxes, front_boxes, back_feats, front_feats, +# feats_compose, feats_select +# 子图保存次序:先前摄、后后摄,以 k 为编号,和 "feats_compose" 中次序相同 +# ''' +# cameras = ('front', 'back') +# for camera in cameras: +# if camera == 'front': +# boxes = event.front_boxes +# imgpaths = event.front_imgpaths +# else: +# boxes = event.back_boxes +# imgpaths = event.back_imgpaths +# +# for i, box in enumerate(boxes): +# x1, y1, x2, y2, tid, score, cls, fid, bid = box +# +# imgpath = imgpaths[int(fid-1)] +# image = cv2.imread(imgpath) +# +# subimg = image[int(y1/2):int(y2/2), int(x1/2):int(x2/2), :] +# +# camerType, timeTamp, _, frameID = os.path.basename(imgpath).split('.')[0].split('_') +# subimgName = f"cam{camerType}_{i}_tid{int(tid)}_fid({int(fid)}, {frameID}).png" +# spath = os.path.join(savepath, subimgName) +# +# cv2.imwrite(spath, subimg) +# # basename = os.path.basename(event['filepath']) +# print(f"Image saved: {os.path.basename(event.eventpath)}") +# ============================================================================= def data_precision_compare(stdfeat, evtfeat, evtMessage, save=True): @@ -296,7 +298,11 @@ def one2one_simi(): if not os.path.exists(pairpath): os.makedirs(pairpath) try: - save_event_subimg(event, pairpath) + subimgpairs = event.save_event_subimg(pairpath) + for subimgName, subimg in subimgpairs: + spath = os.path.join(pairpath, subimgName) + cv2.imwrite(spath, subimg) + except Exception as e: error_event.append(evtname) @@ -304,10 +310,16 @@ def one2one_simi(): if not os.path.exists(img_path): os.makedirs(img_path) try: - plot_save_image(event, img_path) + imgpairs = event.plot_save_image(img_path) + for imgname, img in imgpairs: + spath = os.path.join(img_path, imgname) + cv2.imwrite(spath, img) except Exception as e: error_event.append(evtname) - + + + + errfile = os.path.join(subimgPath, f'error_event.txt') with open(errfile, 'w', encoding='utf-8') as f: @@ -353,17 +365,16 @@ def one2one_simi(): matrix = 1 - cdist(stdfeat, evtfeat, 'cosine') matrix[matrix < 0] = 0 - simi_mean = np.mean(matrix) simi_max = np.max(matrix) stdfeatm = np.mean(stdfeat, axis=0, keepdims=True) evtfeatm = np.mean(evtfeat, axis=0, keepdims=True) simi_mfeat = 1- np.maximum(0.0, cdist(stdfeatm, evtfeatm, 'cosine')) rltdata.append((label, stdbcd, evtname, simi_mean, simi_max, simi_mfeat[0,0])) - + '''================ float32、16、int8 精度比较与存储 =============''' # data_precision_compare(stdfeat, evtfeat, mergePairs[i], save=True) - + print("func: one2one_eval(), have finished!") return rltdata @@ -436,8 +447,11 @@ def gen_eventdict(sourcePath, saveimg=True): errEvents = [] k = 0 for source_path in sourcePath: - bname = os.path.basename(source_path) + evtpath, bname = os.path.split(source_path) + 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 @@ -451,9 +465,9 @@ def gen_eventdict(sourcePath, saveimg=True): errEvents.append(source_path) print(e) - # k += 1 - # if k==10: - # break + k += 1 + if k==1: + break errfile = os.path.join(eventDataPath, f'error_events.txt') with open(errfile, 'w', encoding='utf-8') as f: diff --git a/contrast/one2one_onsite.py b/contrast/one2one_onsite.py index 16ecdbe..1456c9d 100644 --- a/contrast/one2one_onsite.py +++ b/contrast/one2one_onsite.py @@ -105,27 +105,56 @@ def test_compare(): plot_pr_curve(simiList) def one2one_pr(paths): + ''' + 1:1 + + ''' + paths = Path(paths) - # evtpaths = [p for p in paths.iterdir() if p.is_dir() and len(p.name.split('_'))>=2] - evtpaths = [p for p in paths.iterdir() if p.is_dir()] + evtpaths = [] + for p in paths.iterdir(): + condt1 = p.is_dir() + condt2 = len(p.name.split('_'))>=2 + condt3 = len(p.name.split('_')[-1])>8 + condt4 = p.name.split('_')[-1].isdigit() + + if condt1 and condt2 and condt3 and condt4: + evtpaths.append(p) + + + + + # evtpaths = [p for p in paths.iterdir() if p.is_dir() and len(p.name.split('_'))>=2 and len(p.name.split('_')[-1])>8] + # evtpaths = [p for p in paths.iterdir() if p.is_dir()] events, similars = [], [] - ##===================================== 扫A放A, 扫A放B场景 + ##===================================== 扫A放A, 扫A放B场景() one2oneAA, one2oneAB = [], [] + one2SNAA, one2SNAB = [], [] - ##===================================== 应用于展厅 1:N + ##===================================== 应用于 1:1 + + _tp_events, _fn_events, _fp_events, _tn_events = [], [], [], [] + _tp_simi, _fn_simi, _tn_simi, _fp_simi = [], [], [], [] + + ##===================================== 应用于 1:SN tp_events, fn_events, fp_events, tn_events = [], [], [], [] tp_simi, fn_simi, tn_simi, fp_simi = [], [], [], [] ##===================================== 应用于1:n tpevents, fnevents, fpevents, tnevents = [], [], [], [] tpsimi, fnsimi, tnsimi, fpsimi = [], [], [], [] - other_event, other_simi = [], [] ##===================================== barcodes总数、比对错误事件 - bcdList, one2onePath = [], [] + bcdList = [] + one2onePath, one2onePath1 = [], [] + one2SNPath, one2SNPath1 = [], [] + one2nPath = [] + + errorFile_one2one, errorFile_one2SN, errorFile_one2n = [], [], [] + for path in evtpaths: barcode = path.stem.split('_')[-1] datapath = path.joinpath('process.data') @@ -140,51 +169,93 @@ def one2one_pr(paths): except Exception as e: print(f"{path.stem}, Error: {e}") + + '''放入为 1:1,相似度取最大值;取出时为 1:SN, 相似度取均值''' one2one = SimiDict['one2one'] + one2SN = SimiDict['one2SN'] one2n = SimiDict['one2n'] + '''================== 0. 1:1 ===================''' barcodes, similars = [], [] for dt in one2one: + one2onePath.append((path.stem)) + if dt['similar']==0: + one2onePath1.append((path.stem)) + continue + barcodes.append(dt['barcode']) + similars.append(dt['similar']) + if len(barcodes)==len(similars) and len(barcodes)!=0: + ## 扫A放A, 扫A放B场景 + simAA = [similars[i] for i in range(len(barcodes)) if barcodes[i]==barcode] + simAB = [similars[i] for i in range(len(barcodes)) if barcodes[i]!=barcode] + + one2oneAA.extend(simAA) + one2oneAB.extend(simAB) + + ## 相似度排序,barcode相等且排名第一为TP,适用于多的barcode相似度比较 + max_idx = similars.index(max(similars)) + max_sim = similars[max_idx] + # max_bcd = barcodes[max_idx] + for i in range(len(one2one)): + bcd, simi = barcodes[i], similars[i] + if bcd==barcode and simi==max_sim: + _tp_simi.append(simi) + _tp_events.append(path.stem) + elif bcd==barcode and simi!=max_sim: + _fn_simi.append(simi) + _fn_events.append(path.stem) + elif bcd!=barcode and simi!=max_sim: + _tn_simi.append(simi) + _tn_events.append(path.stem) + elif bcd!=barcode and simi==max_sim and barcode in barcodes: + _fp_simi.append(simi) + _fp_events.append(path.stem) + else: + errorFile_one2one.append(path.stem) + + + '''================== 2. 取出场景下的 1 : Small N ===================''' + barcodes, similars = [], [] + for dt in one2SN: barcodes.append(dt['barcode']) similars.append(dt['similar']) - if len(barcodes)!=len(similars) or len(barcodes)==0: - continue + if len(barcodes)==len(similars) and len(barcodes)!=0: + ## 扫A放A, 扫A放B场景 + simAA = [similars[i] for i in range(len(barcodes)) if barcodes[i]==barcode] + simAB = [similars[i] for i in range(len(barcodes)) if barcodes[i]!=barcode] - ##===================================== 扫A放A, 扫A放B场景 - simAA = [similars[i] for i in range(len(barcodes)) if barcodes[i]==barcode] - simAB = [similars[i] for i in range(len(barcodes)) if barcodes[i]!=barcode] - - one2oneAA.extend(simAA) - one2oneAB.extend(simAB) - one2onePath.append(path.stem) - - ##===================================== 以下应用适用于展厅 1:N - max_idx = similars.index(max(similars)) - max_sim = similars[max_idx] - # max_bcd = barcodes[max_idx] - - if path.stem.find('100321')>0: - print("hhh") - - - for i in range(len(one2one)): - bcd, simi = barcodes[i], similars[i] - if bcd==barcode and simi==max_sim: - tp_simi.append(simi) - tp_events.append(path.stem) - elif bcd==barcode and simi!=max_sim: - fn_simi.append(simi) - fn_events.append(path.stem) - elif bcd!=barcode and simi!=max_sim: - tn_simi.append(simi) - tn_events.append(path.stem) - else: - fp_simi.append(simi) - fp_events.append(path.stem) + one2SNAA.extend(simAA) + one2SNAB.extend(simAB) + one2SNPath.append(path.stem) + if len(simAA)==0: + one2SNPath1.append(path.stem) + + + ## 相似度排序,barcode相等且排名第一为TP,适用于多的barcode相似度比较 + max_idx = similars.index(max(similars)) + max_sim = similars[max_idx] + # max_bcd = barcodes[max_idx] + for i in range(len(one2SN)): + bcd, simi = barcodes[i], similars[i] + if bcd==barcode and simi==max_sim: + tp_simi.append(simi) + tp_events.append(path.stem) + elif bcd==barcode and simi!=max_sim: + fn_simi.append(simi) + fn_events.append(path.stem) + elif bcd!=barcode and simi!=max_sim: + tn_simi.append(simi) + tn_events.append(path.stem) + elif bcd!=barcode and simi==max_sim and barcode in barcodes: + fp_simi.append(simi) + fp_events.append(path.stem) + else: + errorFile_one2SN.append(path.stem) + - ##===================================== 以下应用适用1:n + '''===================== 3. 取出场景下的 1:n ========================''' events, evt_barcodes, evt_similars, evt_types = [], [], [], [] for dt in one2n: events.append(dt["event"]) @@ -192,92 +263,132 @@ def one2one_pr(paths): evt_similars.append(dt["similar"]) evt_types.append(dt["type"]) - if len(events)!=len(evt_barcodes) or len(evt_barcodes)!=len(evt_similars) \ - or len(evt_barcodes)!=len(evt_similars) or len(events)==0: continue - - maxsim = evt_similars[evt_similars.index(max(evt_similars))] - for i in range(len(one2n)): - bcd, simi = evt_barcodes[i], evt_similars[i] + if len(events)==len(evt_barcodes) and len(evt_barcodes)==len(evt_similars) \ + and len(evt_similars)==len(evt_types) and len(events)>0: - if bcd==barcode and simi==maxsim: - tpsimi.append(simi) - tpevents.append(path.stem) - elif bcd==barcode and simi!=maxsim: - fnsimi.append(simi) - fnevents.append(path.stem) - elif bcd!=barcode and simi!=maxsim: - tnsimi.append(simi) - tnevents.append(path.stem) - elif bcd!=barcode and simi==maxsim: - fpsimi.append(simi) - fpevents.append(path.stem) - else: - other_simi.append(simi) - other_event.append(path.stem) + one2nPath.append(path.stem) + maxsim = evt_similars[evt_similars.index(max(evt_similars))] + for i in range(len(one2n)): + bcd, simi = evt_barcodes[i], evt_similars[i] + + if bcd==barcode and simi==maxsim: + tpsimi.append(simi) + tpevents.append(path.stem) + elif bcd==barcode and simi!=maxsim: + fnsimi.append(simi) + fnevents.append(path.stem) + elif bcd!=barcode and simi!=maxsim: + tnsimi.append(simi) + tnevents.append(path.stem) + elif bcd!=barcode and simi==maxsim and barcode in evt_barcodes: + fpsimi.append(simi) + fpevents.append(path.stem) + else: + errorFile_one2n.append(path.stem) '''命名规则: - 1:1 1:n 1:N - TP_ TP TPX - PPrecise_ PPrecise PPreciseX - tpsimi tp_simi + 1:1 (max) 1:1 (max) 1:n 1:N + _TP TP_ TP TPX + _PPrecise PPrecise_ PPrecise PPreciseX + tpsimi tp_simi ''' - ''' 1:1 数据存储''' + ''' 1:1 数据存储, 相似度计算方式:最大值、均值''' + _PPrecise, _PRecall = [], [] + _NPrecise, _NRecall = [], [] PPrecise_, PRecall_ = [], [] NPrecise_, NRecall_ = [], [] - ''' 1:n 数据存储''' - PPrecise, PRecall = [], [] - NPrecise, NRecall = [], [] - - ''' 展厅 1:N 数据存储''' + ''' 1:SN 数据存储,需根据相似度排序''' PPreciseX, PRecallX = [], [] NPreciseX, NRecallX = [], [] + ''' 1:n 数据存储,需根据相似度排序''' + PPrecise, PRecall = [], [] + NPrecise, NRecall = [], [] + + + Thresh = np.linspace(-0.2, 1, 100) for th in Thresh: - '''============================= 1:1''' - TP_ = sum(np.array(one2oneAA) >= th) - FP_ = sum(np.array(one2oneAB) >= th) - FN_ = sum(np.array(one2oneAA) < th) - TN_ = sum(np.array(one2oneAB) < th) + '''(Precise, Recall) 计算方式, 若 1:1 与 1:SN 相似度选择方式相同,则可以合并''' + '''===================================== 1:1 最大值''' + _TP = sum(np.array(one2oneAA) >= th) + _FP = sum(np.array(one2oneAB) >= th) + _FN = sum(np.array(one2oneAA) < th) + _TN = sum(np.array(one2oneAB) < th) + + _PPrecise.append(_TP/(_TP+_FP+1e-6)) + _PRecall.append(_TP/(len(one2oneAA)+1e-6)) + _NPrecise.append(_TN/(_TN+_FN+1e-6)) + _NRecall.append(_TN/(len(one2oneAB)+1e-6)) + + '''===================================== 1:SN 均值''' + TP_ = sum(np.array(one2SNAA) >= th) + FP_ = sum(np.array(one2SNAB) >= th) + FN_ = sum(np.array(one2SNAA) < th) + TN_ = sum(np.array(one2SNAB) < th) + PPrecise_.append(TP_/(TP_+FP_+1e-6)) - # PRecall_.append(TP_/(TP_+FN_+1e-6)) - PRecall_.append(TP_/(len(one2oneAA)+1e-6)) - + PRecall_.append(TP_/(len(one2SNAA)+1e-6)) NPrecise_.append(TN_/(TN_+FN_+1e-6)) - # NRecall_.append(TN_/(TN_+FP_+1e-6)) - NRecall_.append(TN_/(len(one2oneAB)+1e-6)) - - '''============================= 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)) - PRecall.append(TP/(len(tpsimi)+len(fnsimi)+1e-6)) - - NPrecise.append(TN/(TN+FN+1e-6)) - # NRecall.append(TN/(TN+FP+1e-6)) - NRecall.append(TN/(len(tnsimi)+len(fpsimi)+1e-6)) - - - '''============================= 1:N 展厅''' + NRecall_.append(TN_/(len(one2SNAB)+1e-6)) + + '''适用于 (Precise, Recall) 计算方式:多个相似度计算并排序,barcode相等且排名第一为 TP ''' + '''===================================== 1:SN ''' TPX = sum(np.array(tp_simi) >= th) FPX = sum(np.array(fp_simi) >= th) FNX = sum(np.array(fn_simi) < th) TNX = sum(np.array(tn_simi) < th) PPreciseX.append(TPX/(TPX+FPX+1e-6)) - # PRecallX.append(TPX/(TPX+FNX+1e-6)) PRecallX.append(TPX/(len(tp_simi)+len(fn_simi)+1e-6)) NPreciseX.append(TNX/(TNX+FNX+1e-6)) - # NRecallX.append(TNX/(TNX+FPX+1e-6)) NRecallX.append(TNX/(len(tn_simi)+len(fp_simi)+1e-6)) + + + '''===================================== 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(tpsimi)+len(fnsimi)+1e-6)) + NPrecise.append(TN/(TN+FN+1e-6)) + NRecall.append(TN/(len(tnsimi)+len(fpsimi)+1e-6)) + + - '''============================= 1:1 曲线''' + + '''1. ============================= 1:1 最大值方案 曲线''' + 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:1 Precise & Recall') + ax.set_xlabel(f"Event Num: {len(one2oneAA)+len(one2oneAB)}") + ax.legend() + plt.show() + ## ============================= 1:1 最大值方案 直方图''' + fig, axes = plt.subplots(2, 1) + axes[0].hist(np.array(one2oneAA), bins=60, edgecolor='black') + axes[0].set_xlim([-0.2, 1]) + axes[0].set_title('AA') + axes[1].hist(np.array(one2oneAB), bins=60, edgecolor='black') + axes[1].set_xlim([-0.2, 1]) + axes[1].set_title('BB') + plt.show() + + + + + '''2. ============================= 1:1 均值方案 曲线''' fig, ax = plt.subplots() ax.plot(Thresh, PPrecise_, 'r', label='Precise_Pos: TP/TPFP') ax.plot(Thresh, PRecall_, 'b', label='Recall_Pos: TP/TPFN') @@ -287,21 +398,50 @@ def one2one_pr(paths): ax.set_ylim([0, 1]) ax.grid(True) ax.set_title('1:1 Precise & Recall') - ax.set_xlabel(f"Event Num: {len(one2oneAA)}") + ax.set_xlabel(f"Event Num: {len(one2SNAA)}") ax.legend() plt.show() - - '''============================= 1:1 直方图''' + ## ============================= 1:1 均值方案 直方图''' fig, axes = plt.subplots(2, 1) - axes[0].hist(np.array(one2oneAA), bins=60, edgecolor='black') + axes[0].hist(np.array(one2SNAA), bins=60, edgecolor='black') axes[0].set_xlim([-0.2, 1]) axes[0].set_title('AA') - axes[1].hist(np.array(one2oneAB), bins=60, edgecolor='black') + axes[1].hist(np.array(one2SNAB), bins=60, edgecolor='black') axes[1].set_xlim([-0.2, 1]) axes[1].set_title('BB') plt.show() + + ''''3. ============================= 1:SN 曲线''' + fig, ax = plt.subplots() + ax.plot(Thresh, PPreciseX, 'r', label='Precise_Pos: TP/TPFP') + ax.plot(Thresh, PRecallX, 'b', label='Recall_Pos: TP/TPFN') + ax.plot(Thresh, NPreciseX, 'g', label='Precise_Neg: TN/TNFP') + 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_title('1:SN Precise & Recall') + ax.set_xlabel(f"Event Num: {len(one2SNAA)}") + ax.legend() + plt.show() + ## ============================= 1:N 展厅 直方图''' + fig, axes = plt.subplots(2, 2) + axes[0, 0].hist(tp_simi, bins=60, edgecolor='black') + axes[0, 0].set_xlim([-0.2, 1]) + axes[0, 0].set_title('TP') + axes[0, 1].hist(fp_simi, bins=60, edgecolor='black') + axes[0, 1].set_xlim([-0.2, 1]) + axes[0, 1].set_title('FP') + axes[1, 0].hist(tn_simi, bins=60, edgecolor='black') + axes[1, 0].set_xlim([-0.2, 1]) + axes[1, 0].set_title('TN') + axes[1, 1].hist(fn_simi, bins=60, edgecolor='black') + axes[1, 1].set_xlim([-0.2, 1]) + axes[1, 1].set_title('FN') + plt.show() + - '''============================= 1:n 曲线''' + '''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') @@ -311,11 +451,10 @@ def one2one_pr(paths): ax.set_ylim([0, 1]) ax.grid(True) ax.set_title('1:n Precise & Recall') - ax.set_xlabel(f"Event Num: {len(one2oneAA)}") + ax.set_xlabel(f"Event Num: {len(tpsimi)+len(fnsimi)}") ax.legend() plt.show() - - '''============================= 1:n 直方图''' + ## ============================= 1:n 直方图''' fig, axes = plt.subplots(2, 2) axes[0, 0].hist(tpsimi, bins=60, edgecolor='black') axes[0, 0].set_xlim([-0.2, 1]) @@ -332,35 +471,18 @@ def one2one_pr(paths): plt.show() - '''============================= 1:N 展厅 曲线''' - fig, ax = plt.subplots() - ax.plot(Thresh, PPreciseX, 'r', label='Precise_Pos: TP/TPFP') - ax.plot(Thresh, PRecallX, 'b', label='Recall_Pos: TP/TPFN') - ax.plot(Thresh, NPreciseX, 'g', label='Precise_Neg: TN/TNFP') - 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_title('1:N Precise & Recall') - ax.set_xlabel(f"Event Num: {len(one2oneAA)}") - ax.legend() - plt.show() + fpsnErrFile = str(paths.joinpath("one2SN_Error.txt")) + with open(fpsnErrFile, "w") as file: + for item in fp_events: + file.write(item + "\n") + + fpErrFile = str(paths.joinpath("one2n_Error.txt")) + with open(fpErrFile, "w") as file: + for item in fpevents: + file.write(item + "\n") + + - '''============================= 1:N 展厅 直方图''' - fig, axes = plt.subplots(2, 2) - axes[0, 0].hist(tp_simi, bins=60, edgecolor='black') - axes[0, 0].set_xlim([-0.2, 1]) - axes[0, 0].set_title('TP') - axes[0, 1].hist(fp_simi, bins=60, edgecolor='black') - axes[0, 1].set_xlim([-0.2, 1]) - axes[0, 1].set_title('FP') - axes[1, 0].hist(tn_simi, bins=60, edgecolor='black') - axes[1, 0].set_xlim([-0.2, 1]) - axes[1, 0].set_title('TN') - axes[1, 1].hist(fn_simi, bins=60, edgecolor='black') - axes[1, 1].set_xlim([-0.2, 1]) - axes[1, 1].set_title('FN') - plt.show() # bcdSet = set(bcdList) # one2nErrFile = str(paths.joinpath("one_2_Small_n_Error.txt")) @@ -378,7 +500,7 @@ def one2one_pr(paths): if __name__ == "__main__": - evtpaths = r"\\192.168.1.28\share\测试视频数据以及日志\各模块测试记录\展厅测试\1129_展厅模型v801测试组测试" + evtpaths = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\images" one2one_pr(evtpaths) diff --git a/contrast/utils/__pycache__/event.cpython-39.pyc b/contrast/utils/__pycache__/event.cpython-39.pyc index 113c3dd..0cbfef1 100644 Binary files a/contrast/utils/__pycache__/event.cpython-39.pyc and b/contrast/utils/__pycache__/event.cpython-39.pyc differ diff --git a/contrast/utils/event.py b/contrast/utils/event.py index fa0757f..090cd0c 100644 --- a/contrast/utils/event.py +++ b/contrast/utils/event.py @@ -5,17 +5,43 @@ Created on Tue Nov 26 17:35:05 2024 @author: ym """ import os +import cv2 import pickle import numpy as np from pathlib import Path import sys sys.path.append(r"D:\DetectTracking") +from tracking.utils.plotting import Annotator, colors +from tracking.utils.drawtracks import drawTrack from tracking.utils.read_data import extract_data, read_tracking_output, read_similar IMG_FORMAT = ['.bmp', '.jpg', '.jpeg', '.png'] VID_FORMAT = ['.mp4', '.avi'] + +def array2list(bboxes): + ''' + 将 bboxes 变换为 track 列表 + bboxes: [x1, y1, x2, y2, track_id, score, cls, frame_index, box_index] + Return: + lboxes:列表,列表中元素具有同一 track_id,x1y1x2y2 格式 + [x1, y1, x2, y2, track_id, score, cls, frame_index, box_index] + ''' + lboxes = [] + if len(bboxes)==0: + return [] + + trackID = np.unique(bboxes[:, 4].astype(int)) + track_ids = bboxes[:, 4].astype(int) + for t_id in trackID: + idx = np.where(track_ids == t_id)[0] + box = bboxes[idx, :] + lboxes.append(box) + + return lboxes + + class ShoppingEvent: def __init__(self, eventpath, stype="data"): '''stype: str, 'pickle', 'data', ''' @@ -252,15 +278,219 @@ class ShoppingEvent: self.feats_select = self.front_feats elif len(self.back_feats): self.feats_select = self.back_feats + + def plot_save_image(self, savepath): + + def array2list(bboxes): + '''[x1, y1, x2, y2, track_id, score, cls, frame_index, box_index]''' + frame_ids = bboxes[:, 7].astype(int) + fID = np.unique(bboxes[:, 7].astype(int)) + fboxes = [] + for f_id in fID: + idx = np.where(frame_ids==f_id)[0] + box = bboxes[idx, :] + fboxes.append((f_id, box)) + return fboxes + + imgpairs = [] + cameras = ('front', 'back') + for camera in cameras: + if camera == 'front': + boxes = self.front_trackerboxes + imgpaths = self.front_imgpaths + else: + boxes = self.back_trackerboxes + imgpaths = self.back_imgpaths + + fboxes = array2list(boxes) + for fid, fbox in fboxes: + imgpath = imgpaths[int(fid-1)] + + image = cv2.imread(imgpath) + + annotator = Annotator(image.copy(), line_width=2) + for i, box in enumerate(fbox): + x1, y1, x2, y2, tid, score, cls, fid, bid = box + label = f'{int(tid), int(cls)}' + if tid >=0 and cls==0: + color = colors(int(cls), True) + elif tid >=0 and cls!=0: + color = colors(int(tid), True) + else: + color = colors(19, True) # 19为调色板的最后一个元素 + xyxy = (x1/2, y1/2, x2/2, y2/2) + annotator.box_label(xyxy, label, color=color) + + im0 = annotator.result() + + imgpairs.append((Path(imgpath).name, im0)) + + # spath = os.path.join(savepath, Path(imgpath).name) + + + # cv2.imwrite(spath, im0) + return imgpairs + + + def save_event_subimg(self, savepath): + ''' + 功能: 保存一次购物事件的轨迹子图 + 9 items: barcode, type, filepath, back_imgpaths, front_imgpaths, + back_boxes, front_boxes, back_feats, front_feats, + feats_compose, feats_select + 子图保存次序:先前摄、后后摄,以 k 为编号,和 "feats_compose" 中次序相同 + ''' + imgpairs = [] + cameras = ('front', 'back') + for camera in cameras: + boxes = np.empty((0, 9), dtype=np.float64) ##和类doTracks兼容 + if camera == 'front': + for b in self.front_boxes: + boxes = np.concatenate((boxes, b), axis=0) + imgpaths = self.front_imgpaths + else: + for b in self.back_boxes: + boxes = np.concatenate((boxes, b), axis=0) + imgpaths = self.back_imgpaths + + for i, box in enumerate(boxes): + x1, y1, x2, y2, tid, score, cls, fid, bid = box + + imgpath = imgpaths[int(fid-1)] + image = cv2.imread(imgpath) + + subimg = image[int(y1/2):int(y2/2), int(x1/2):int(x2/2), :] + + camerType, timeTamp, _, frameID = os.path.basename(imgpath).split('.')[0].split('_') + subimgName = f"cam{camerType}_{i}_tid{int(tid)}_fid({int(fid)}, {frameID}).png" + + imgpairs.append((subimgName, subimg)) + + # spath = os.path.join(savepath, subimgName) + + # cv2.imwrite(spath, subimg) + return imgpairs + # basename = os.path.basename(event['filepath']) + print(f"Image saved: {os.path.basename(self.eventpath)}") + + def draw_tracks(self): + front_edge = cv2.imread(r"D:\DetectTracking\tracking\shopcart\cart_tempt\board_ftmp_line.png") + back_edge = cv2.imread(r"D:\DetectTracking\tracking\shopcart\cart_tempt\edgeline.png") + + front_trackerboxes = array2list(self.front_trackerboxes) + back_trackerboxes = array2list(self.back_trackerboxes) + + # img1, img2 = edgeline.copy(), edgeline.copy() + img1 = drawTrack(front_trackerboxes, front_edge.copy()) + img2 = drawTrack(self.front_trackingboxes, front_edge.copy()) + + img3 = drawTrack(back_trackerboxes, back_edge.copy()) + img4 = drawTrack(self.back_trackingboxes, back_edge.copy()) + + + + imgcat1 = np.concatenate((img1, img2), axis = 1) + H, W = imgcat1.shape[:2] + cv2.line(imgcat1, (int(W/2), 0), (int(W/2), H), (128, 255, 128), 2) + + imgcat2 = np.concatenate((img3, img4), axis = 1) + H, W = imgcat2.shape[:2] + cv2.line(imgcat2, (int(W/2), 0), (int(W/2), H), (128, 255, 128), 2) + + + illus = [imgcat1, imgcat2] + if len(illus): + img_cat = np.concatenate(illus, axis = 1) + if len(illus)==2: + H, W = img_cat.shape[:2] + cv2.line(img_cat, (int(W/2), 0), (int(W/2), int(H)), (128, 128, 255), 3) + + return img_cat + + + + def main(): - pklpath = r"D:\DetectTracking\evtresult\images2\ShoppingDict.pkl" - evt = ShoppingEvent(pklpath, stype='pickle') + # pklpath = r"D:\DetectTracking\evtresult\images2\ShoppingDict.pkl" + # evt = ShoppingEvent(pklpath, stype='pickle') + + + + evtpath = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\images\20241209-160248-08edd5f6-1806-45ad-babf-7a4dd11cea60_6973226721445" + evt = ShoppingEvent(evtpath, stype='data') + + img_cat = evt.draw_tracks() + + cv2.imwrite("a.png", img_cat) + + + +# ============================================================================= +# def main1(): +# evtpaths = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\images" +# text1 = "one2n_Error.txt" +# text2 = "one2SN_Error.txt" +# events = [] +# text = (text1, text2) +# for txt in text: +# txtfile = os.path.join(evtpaths, txt) +# with open(txtfile, "r") as f: +# lines = f.readlines() +# for i, line in enumerate(lines): +# line = line.strip() +# if line: +# fpath=os.path.join(evtpaths, line) +# events.append(fpath) +# +# +# events = list(set(events)) +# +# '''定义当前事件存储地址及生成相应文件件''' +# resultPath = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\result" +# # eventDataPath = os.path.join(resultPath, "evtobjs") +# # subimgPath = os.path.join(resultPath, "subimgs") +# # imagePath = os.path.join(resultPath, "image") +# +# # if not os.path.exists(eventDataPath): +# # os.makedirs(eventDataPath) +# # if not os.path.exists(subimgPath): +# # os.makedirs(subimgPath) +# # if not os.path.exists(imagePath): +# # os.makedirs(imagePath) +# +# +# for evtpath in events: +# event = ShoppingEvent(evtpath) +# +# +# evtname = os.path.basename(evtpath) +# subimgpath = os.path.join(resultPath, f"{evtname}", "subimg") +# imgspath = os.path.join(resultPath, f"{evtname}", "imgs") +# if not os.path.exists(subimgpath): +# os.makedirs(subimgpath) +# if not os.path.exists(imgspath): +# os.makedirs(imgspath) +# +# subimgpairs = event.save_event_subimg(subimgpath) +# +# for subimgName, subimg in subimgpairs: +# spath = os.path.join(subimgpath, subimgName) +# cv2.imwrite(spath, subimg) +# +# imgpairs = event.plot_save_image(imgspath) +# for imgname, img in imgpairs: +# spath = os.path.join(imgspath, imgname) +# cv2.imwrite(spath, img) +# +# ============================================================================= + if __name__ == "__main__": main() + # main1() diff --git a/pipeline.py b/pipeline.py index 71fa31b..f3ef177 100644 --- a/pipeline.py +++ b/pipeline.py @@ -77,8 +77,13 @@ def pipeline( '''事件结果存储文件夹''' if not savepath: savepath = Path(__file__).resolve().parents[0] / "evtresult" + save_dir_event = Path(savepath) / evtname + pickpath = Path(savepath)/"pickfile" + if not pickpath.exists(): + pickpath.mkdir(parents=True, exist_ok=True) + ShoppingDict = {"eventPath": eventpath, "eventName": evtname, @@ -117,6 +122,8 @@ def pipeline( save_dir_video.mkdir(parents=True, exist_ok=True) + + '''Yolo + Resnet + Tracker''' optdict["source"] = vpath optdict["save_dir"] = save_dir_video @@ -162,14 +169,16 @@ def pipeline( # pklpath = save_dir_event / "ShoppingDict.pkl" # with open(str(pklpath), 'wb') as f: # pickle.dump(ShoppingDict, f) - pklpath = Path(savepath) / evtname+".pkl" - with open(str(pklpath), 'wb') as f: + pf_path = Path(pickpath) / Path(str(evtname)+".pkl") + with open(str(pf_path), 'wb') as f: pickle.dump(ShoppingDict, f) '''轨迹显示模块''' illus = [None, None] for CamerType, vts in event_tracks: + if len(vts.tracks)==0: continue + if CamerType == 'front': edgeline = cv2.imread("./tracking/shopcart/cart_tempt/board_ftmp_line.png") @@ -255,7 +264,7 @@ def main(): ''' 函数:pipeline(),遍历事件文件夹,选择类型 image 或 video, ''' - evtdir = r"\\192.168.1.28\share\测试视频数据以及日志\各模块测试记录\比对测试\1209永辉超市测试" + evtdir = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\images" evtdir = Path(evtdir) parmDict = {} @@ -263,25 +272,22 @@ def main(): parmDict["SourceType"] = "image" # video, image parmDict["stdfeat_path"] = None - k = 1 + k = 0 errEvents = [] for item in evtdir.iterdir(): if item.is_dir(): - item = r"D:\exhibition\images\images2\images2" - - + # item = r"D:\exhibition\images\images2\images2" parmDict["eventpath"] = item + pipeline(**parmDict) - - try: - pipeline(**parmDict) - except Exception as e: - errEvents.append(item) - - - # k+=1 - # if k==1: - # break + # try: + # pipeline(**parmDict) + # except Exception as e: + # errEvents.append(str(item)) + + k+=1 + if k==1: + break errfile = os.path.join(parmDict["savepath"], f'error_events.txt') with open(errfile, 'w', encoding='utf-8') as f: diff --git a/shopper.py b/shopper.py new file mode 100644 index 0000000..7e8bdd4 --- /dev/null +++ b/shopper.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue Dec 17 10:45:10 2024 + +@author: ym +""" +import os +import numpy as np +import pandas as pd +from pathlib import Path + + + + + +xpath = r"\\192.168.1.28\share\模型\部署相关\永辉金源广场店商品信息.xlsx" +xroot, xfilename = os.path.split(xpath) +xfile, ext = os.path.splitext(xfilename) +spath = os.path.join(xroot, xfile+'_diff.xlsx') + + +df = pd.read_excel(xpath) +barcodes = df["商品条码"].tolist() +names_caojq = df["商品名称"].tolist() + +stdpath = r"\\192.168.1.28\share\数据\已完成数据\比对数据\barcode\all_totalBarocde\totalBarcode" + +stdpath = Path(stdpath) +stdBarcodes = [int(f.stem) for f in stdpath.iterdir() if f.is_dir() and f.stem.isdigit() and len(f.stem)>=8] + + +barcodes_s = set(barcodes) +stdBarcodes_s = set(stdBarcodes) + +A = barcodes_s - stdBarcodes_s + +record_bcd, record_name = [], [] +for bcd in A: + if np.isnan(bcd): continue + try: + index = barcodes.index(bcd) + name = names_caojq[index] + + record_bcd.append(bcd) + record_name.append(name) + except ValueError: + print(f"元素 {bcd} 不在列表中") + +df_save = pd.DataFrame({ + '商品条码': record_bcd, + '商品名称': record_name +}) + +df.to_excel(spath, index=False) + +print("Done") + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tracking/utils/__pycache__/drawtracks.cpython-39.pyc b/tracking/utils/__pycache__/drawtracks.cpython-39.pyc index d1e5e1e..bccf31b 100644 Binary files a/tracking/utils/__pycache__/drawtracks.cpython-39.pyc and b/tracking/utils/__pycache__/drawtracks.cpython-39.pyc differ diff --git a/tracking/utils/__pycache__/read_data.cpython-39.pyc b/tracking/utils/__pycache__/read_data.cpython-39.pyc index 3bc17c6..00f91e8 100644 Binary files a/tracking/utils/__pycache__/read_data.cpython-39.pyc and b/tracking/utils/__pycache__/read_data.cpython-39.pyc differ diff --git a/tracking/utils/drawtracks.py b/tracking/utils/drawtracks.py index 024c22b..d9ba04e 100644 --- a/tracking/utils/drawtracks.py +++ b/tracking/utils/drawtracks.py @@ -364,7 +364,10 @@ def drawTrack(tracks, img): annotator = TrackAnnotator(img, line_width=2) for track in tracks: - annotator.plotting_track(track.boxes) + if isinstance(track, np.ndarray): + annotator.plotting_track(track) + else: + annotator.plotting_track(track.boxes) img = annotator.result() # pth = save_dir.joinpath(f"{filename}") diff --git a/tracking/utils/read_data.py b/tracking/utils/read_data.py index 36b05a6..8996f72 100644 --- a/tracking/utils/read_data.py +++ b/tracking/utils/read_data.py @@ -202,9 +202,9 @@ def read_tracking_output(filepath): if len(feats) != len(boxes): - return np.array([]), np.array([]) + return [np.array([])], [np.array([])] - return np.array(boxes), np.array(feats) + return [np.array(boxes)], [np.array(feats)] def read_deletedBarcode_file(filePath): @@ -408,7 +408,8 @@ def read_similar(filePath): if len(one2one_list): SimiDict['one2one'] = one2one_list if len(one2n_list): SimiDict['one2n'] = one2n_list - + if len(one2SN_list): SimiDict['one2SN'] = one2SN_list + return SimiDict @@ -532,13 +533,12 @@ def main(): break def main1(): - fpath = r'\\192.168.1.28\share\测试_202406\1101\images\20241101-140456-44dc75b5-c406-4cb2-8317-c4660bb727a3_6922130101355_6922130101355\process.data' - simidct = read_one2one_simi(fpath) + fpath = r'\\192.168.1.28\share\测试视频数据以及日志\各模块测试记录\比对测试\1209永辉超市测试\20241209-155924-117e1941-70f8-4287-8de1-4866868548a6_6926475209967\process.data' + simidct = read_similar(fpath) print(simidct) if __name__ == "__main__": - # main() main1() @@ -552,3 +552,4 @@ if __name__ == "__main__": +