This commit is contained in:
王庆刚
2024-11-08 08:52:56 +08:00
parent 5ecc1285d4
commit c47894ddc0
11 changed files with 562 additions and 644 deletions

Binary file not shown.

View File

@ -16,7 +16,7 @@ from tracking.utils.read_data import extract_data, read_deletedBarcode_file, rea
# from tracking.dotrack.dotracks import Track # from tracking.dotrack.dotracks import Track
from one2n_contrast import compute_recall_precision, show_recall_prec from one2n_contrast import compute_recall_precision, show_recall_prec
from one2n_contrast import performance_evaluate from one2n_contrast import performance_evaluate, one2n_return, one2n_deleted
def compute_similar(feat1, feat2): def compute_similar(feat1, feat2):

View File

@ -27,7 +27,7 @@ model.load_state_dict(torch.load(model_path, map_location=conf.device))
model.eval() model.eval()
print('load model {} '.format(conf.testbackbone)) print('load model {} '.format(conf.testbackbone))
def get_std_barcodeDict(bcdpath, savepath): def get_std_barcodeDict(bcdpath, savepath, bcdSet):
''' '''
inputs: inputs:
bcdpath: 已清洗的barcode样本图像如果barcode下有'base'文件夹,只选用该文件夹下图像 bcdpath: 已清洗的barcode样本图像如果barcode下有'base'文件夹,只选用该文件夹下图像
@ -42,10 +42,14 @@ def get_std_barcodeDict(bcdpath, savepath):
'''读取数据集中 barcode 列表''' '''读取数据集中 barcode 列表'''
stdBarcodeList = [] stdBarcodeList = []
for filename in os.listdir(bcdpath): for filename in os.listdir(bcdpath):
filepath = os.path.join(bcdpath, filename) # filepath = os.path.join(bcdpath, filename)
# if not os.path.isdir(filepath) or not filename.isdigit() or len(filename)<8: # if not os.path.isdir(filepath) or not filename.isdigit() or len(filename)<8:
# continue # continue
stdBarcodeList.append(filename) if bcdSet is None:
stdBarcodeList.append(filename)
elif filename in bcdSet:
stdBarcodeList.append(filename)
bcdPaths = [(barcode, os.path.join(bcdpath, barcode)) for barcode in stdBarcodeList] bcdPaths = [(barcode, os.path.join(bcdpath, barcode)) for barcode in stdBarcodeList]
@ -184,18 +188,15 @@ def stdfeat_infer(imgPath, featPath, bcdSet=None):
def genfeatures(imgpath, bcdpath, featpath): def genfeatures(imgpath, bcdpath, featpath, bcdSet=None):
''' 生成标准特征集 '''
'''1. 提取 imgpath 中样本地址,生成字典{barcode: [imgpath1, imgpath1, ...]}
并存储于: bcdpath, 格式为 barcode.pickle'''
get_std_barcodeDict(imgpath, bcdpath, bcdSet)
get_std_barcodeDict(imgpath, bcdpath) '''2. 特征提取,并保存至文件夹 featpath 中,也根据 bcdSet 交集执行'''
stdfeat_infer(bcdpath, featpath, bcdSet=None) stdfeat_infer(bcdpath, featpath, bcdSet)
print(f"Features have generated, saved in: {featpath}")
def main(): def main():
imgpath = r"\\192.168.1.28\share\展厅barcode数据\整理\zhantingBase" imgpath = r"\\192.168.1.28\share\展厅barcode数据\整理\zhantingBase"
bcdpath = r"D:\exhibition\dataset\bcdpath" bcdpath = r"D:\exhibition\dataset\bcdpath"

View File

@ -21,7 +21,7 @@ import sys
sys.path.append(r"D:\DetectTracking") sys.path.append(r"D:\DetectTracking")
from tracking.utils.plotting import Annotator, colors from tracking.utils.plotting import Annotator, colors
from tracking.utils.read_data import extract_data, read_deletedBarcode_file, read_tracking_output, read_returnGoods_file from tracking.utils.read_data import extract_data, read_deletedBarcode_file, read_tracking_output, read_returnGoods_file
from tracking.utils.plotting import draw_tracking_boxes from tracking.utils.plotting import draw_tracking_boxes, get_subimgs
from contrast.utils.tools import showHist, show_recall_prec, compute_recall_precision from contrast.utils.tools import showHist, show_recall_prec, compute_recall_precision
@ -148,13 +148,18 @@ def get_contrast_paths(pair, basepath):
if len(input_folds): if len(input_folds):
indice = np.argsort(np.array(times)) indice = np.argsort(np.array(times))
input_fold = input_folds[indice[-1]] input_fold = input_folds[indice[-1]]
inputpath = os.path.join(basepath, input_fold) inputpath = os.path.join(basepath, input_fold)
'''取出操作错误匹配的放入操作对应的文件夹''' '''取出操作错误匹配的放入操作对应的文件夹'''
if len(errmatch_folds): if len(errmatch_folds):
indice = np.argsort(np.array(errmatch_times)) indice = np.argsort(np.array(errmatch_times))
errmatch_fold = errmatch_folds[indice[-1]] errmatch_fold = errmatch_folds[indice[-1]]
errorpath = os.path.join(basepath, errmatch_fold) errorpath = os.path.join(basepath, errmatch_fold)
'''放入事件文件夹地址、取出事件文件夹地址''' '''放入事件文件夹地址、取出事件文件夹地址'''
getoutpath = os.path.join(basepath, getout_fold) getoutpath = os.path.join(basepath, getout_fold)
@ -163,33 +168,33 @@ def get_contrast_paths(pair, basepath):
return getoutpath, inputpath, errorpath return getoutpath, inputpath, errorpath
def save_tracking_imgpairs(pair, basepath, savepath): def save_tracking_imgpairs(pairs, savepath):
''' '''
basepath: 原始测试数据文件夹的路径 pairs: 匹配事件对
savepath: 保存的目标文件夹 savepath: 保存的目标文件夹
''' '''
def get_event_path(evtpath):
basepath, eventname = os.path.split(evtpath)
evt_path = ''
for filename in os.listdir(basepath):
if filename.find(eventname)==0:
evt_path = os.path.join(basepath, filename)
break
return evt_path
getoutpath, inputpath, errorpath = get_contrast_paths(pair, basepath) getoutpath = get_event_path(pairs[0])
inputpath = get_event_path(pairs[1])
if len(inputpath)==0:
return
if len(pairs) == 3:
errorpath = get_event_path(pairs[2])
else:
errorpath = ''
'''==== 读取放入、取出事件对应的 Yolo输入的前后摄图像0后摄1前摄 ====''' ''' 1. 读取放入、取出事件对应的 Yolo输入的前后摄图像0后摄1前摄
2. 读取放入、取出事件对应的 tracking 输出boxes, feats
3. boxes绘制并保存图像序列
'''==== 读取放入、取出事件对应的 tracking 输出boxes, feats ====''' 4. 截取并保存轨迹子图
'''
if len(inputpath):
imgs_input_0, imgs_input_1 = read_tracking_imgs(inputpath)
input_data_0 = os.path.join(inputpath, '0_tracking_output.data')
input_data_1 = os.path.join(inputpath, '1_tracking_output.data')
boxes_input_0, feats_input_0 = read_tracking_output(input_data_0)
boxes_input_1, feats_input_1 = read_tracking_output(input_data_1)
ImgsInput_0 = draw_tracking_boxes(imgs_input_0, boxes_input_0)
ImgsInput_1 = draw_tracking_boxes(imgs_input_1, boxes_input_1)
if len(getoutpath): if len(getoutpath):
imgs_getout_0, imgs_getout_1 = read_tracking_imgs(getoutpath) imgs_getout_0, imgs_getout_1 = read_tracking_imgs(getoutpath)
@ -199,9 +204,28 @@ def save_tracking_imgpairs(pair, basepath, savepath):
boxes_output_1, feats_output_1 = read_tracking_output(getout_data_1) boxes_output_1, feats_output_1 = read_tracking_output(getout_data_1)
ImgsGetout_0 = draw_tracking_boxes(imgs_getout_0, boxes_output_0) ImgsGetout_0 = draw_tracking_boxes(imgs_getout_0, boxes_output_0)
ImgsGetout_1 = draw_tracking_boxes(imgs_getout_1, boxes_output_1) ImgsGetout_1 = draw_tracking_boxes(imgs_getout_1, boxes_output_1)
if len(errorpath):
SubimgsGetout_0 = get_subimgs(imgs_getout_0, boxes_output_0)
SubimgsGetout_1 = get_subimgs(imgs_getout_1, boxes_output_1)
savedir = os.path.basename(getoutpath)
if len(inputpath):
imgs_input_0, imgs_input_1 = read_tracking_imgs(inputpath)
input_data_0 = os.path.join(inputpath, '0_tracking_output.data')
input_data_1 = os.path.join(inputpath, '1_tracking_output.data')
boxes_input_0, feats_input_0 = read_tracking_output(input_data_0)
boxes_input_1, feats_input_1 = read_tracking_output(input_data_1)
ImgsInput_0 = draw_tracking_boxes(imgs_input_0, boxes_input_0)
ImgsInput_1 = draw_tracking_boxes(imgs_input_1, boxes_input_1)
SubimgsInput_0 = get_subimgs(imgs_input_0, boxes_input_0)
SubimgsInput_1 = get_subimgs(imgs_input_1, boxes_input_1)
savedir = savedir + '+' + os.path.basename(inputpath)
if len(errorpath):
imgs_error_0, imgs_error_1 = read_tracking_imgs(errorpath) imgs_error_0, imgs_error_1 = read_tracking_imgs(errorpath)
error_data_0 = os.path.join(errorpath, '0_tracking_output.data') error_data_0 = os.path.join(errorpath, '0_tracking_output.data')
@ -211,37 +235,61 @@ def save_tracking_imgpairs(pair, basepath, savepath):
ImgsError_0 = draw_tracking_boxes(imgs_error_0, boxes_error_0) ImgsError_0 = draw_tracking_boxes(imgs_error_0, boxes_error_0)
ImgsError_1 = draw_tracking_boxes(imgs_error_1, boxes_error_1) ImgsError_1 = draw_tracking_boxes(imgs_error_1, boxes_error_1)
SubimgsError_0 = get_subimgs(imgs_error_0, boxes_error_0)
SubimgsError_1 = get_subimgs(imgs_error_0, boxes_error_0)
savedir = pair[0] + pair[1] savedir = savedir + '+' + os.path.basename(errorpath)
if len(errorpath):
savedir = savedir + '_' + errorpath.split('_')[-1]
foldname = os.path.join(savepath, 'imgpairs', savedir)
if not os.path.exists(foldname):
os.makedirs(foldname)
for i, img in enumerate(ImgsInput_0):
imgpath = os.path.join(foldname, f'input_0_{i}.png')
cv2.imwrite(imgpath, img)
for i, img in enumerate(ImgsInput_1):
imgpath = os.path.join(foldname, f'input_1_{i}.png')
cv2.imwrite(imgpath, img)
for i, img in enumerate(ImgsGetout_0):
imgpath = os.path.join(foldname, f'getout_0_{i}.png')
cv2.imwrite(imgpath, img)
for i, img in enumerate(ImgsGetout_1):
imgpath = os.path.join(foldname, f'getout_1_{i}.png')
cv2.imwrite(imgpath, img)
for i, img in enumerate(ImgsError_0): ''' savepath\pairs\savedir\eventpairs\保存画框后的图像序列 '''
imgpath = os.path.join(foldname, f'errMatch_0_{i}.png') entpairs = os.path.join(savepath, 'pairs', savedir, 'eventpairs')
if not os.path.exists(entpairs):
os.makedirs(entpairs)
for fid, img in ImgsInput_0:
imgpath = os.path.join(entpairs, f'input_0_{fid}.png')
cv2.imwrite(imgpath, img) cv2.imwrite(imgpath, img)
for i, img in enumerate(ImgsError_1): for fid, img in ImgsInput_1:
imgpath = os.path.join(foldname, f'errMatch_1_{i}.png') imgpath = os.path.join(entpairs, f'input_1_{fid}.png')
cv2.imwrite(imgpath, img) cv2.imwrite(imgpath, img)
for fid, img in ImgsGetout_0:
imgpath = os.path.join(entpairs, f'getout_0_{fid}.png')
cv2.imwrite(imgpath, img)
for fid, img in ImgsGetout_1:
imgpath = os.path.join(entpairs, f'getout_1_{fid}.png')
cv2.imwrite(imgpath, img)
if 'ImgsError_0' in vars() and 'ImgsError_1' in vars():
for fid, img in ImgsError_0:
imgpath = os.path.join(entpairs, f'errMatch_0_{fid}.png')
cv2.imwrite(imgpath, img)
for fid, img in ImgsError_1:
imgpath = os.path.join(entpairs, f'errMatch_1_{fid}.png')
cv2.imwrite(imgpath, img)
''' savepath\pairs\savedir\subimgpairs\保存轨迹子图 '''
subimgpairs = os.path.join(savepath, 'pairs', savedir, 'subimgpairs')
if not os.path.exists(subimgpairs):
os.makedirs(subimgpairs)
for fid, bid, img in SubimgsGetout_0:
imgpath = os.path.join(subimgpairs, f'getout_0_{fid}_{bid}.png')
cv2.imwrite(imgpath, img)
for fid, bid, img in SubimgsGetout_1:
imgpath = os.path.join(subimgpairs, f'getout_1_{fid}_{bid}.png')
cv2.imwrite(imgpath, img)
for fid, bid, img in SubimgsInput_0:
imgpath = os.path.join(subimgpairs, f'input_0_{fid}_{bid}.png')
cv2.imwrite(imgpath, img)
for fid, bid, img in SubimgsInput_1:
imgpath = os.path.join(subimgpairs, f'input_1_{fid}_{bid}.png')
cv2.imwrite(imgpath, img)
if 'SubimgsError_0' in vars() and 'SubimgsError_1' in vars():
for fid, bid, img in SubimgsError_0:
imgpath = os.path.join(subimgpairs, f'errMatch_0_{fid}_{bid}.png')
cv2.imwrite(imgpath, img)
for fid, bid, img in SubimgsError_1:
imgpath = os.path.join(subimgpairs, f'errMatch_1_{fid}_{bid}.png')
cv2.imwrite(imgpath, img)
def one2n_deleted(all_list):
def one2n_old(all_list):
corrpairs, errpairs, correct_similarity, err_similarity = [], [], [], [] corrpairs, errpairs, correct_similarity, err_similarity = [], [], [], []
for s_list in all_list: for s_list in all_list:
seqdir = s_list['SeqDir'].strip() seqdir = s_list['SeqDir'].strip()
@ -277,8 +325,9 @@ def one2n_old(all_list):
def one2n_new(all_list): def one2n_return(all_list, basepath):
corrpairs, correct_similarity, errpairs, err_similarity = [], [], [], [] corrpairs, corr_similarity, errpairs, err_similarity = [], [], [], []
for s_list in all_list: for s_list in all_list:
seqdir = s_list['SeqDir'].strip() seqdir = s_list['SeqDir'].strip()
delete = s_list['Deleted'].strip() delete = s_list['Deleted'].strip()
@ -305,7 +354,7 @@ def one2n_new(all_list):
matched_barcode = barcodes[index] matched_barcode = barcodes[index]
if matched_barcode == delete: if matched_barcode == delete:
corrpairs.append((seqdir, events[index])) corrpairs.append((seqdir, events[index]))
correct_similarity.append(max(similarity)) corr_similarity.append(max(similarity))
else: else:
idx = [i for i, name in enumerate(events) if name.split('_')[-1] == delete] idx = [i for i, name in enumerate(events) if name.split('_')[-1] == delete]
idxmax, simimax = -1, -1 idxmax, simimax = -1, -1
@ -314,49 +363,80 @@ def one2n_new(all_list):
if similarity[k] > simimax: if similarity[k] > simimax:
idxmax = k idxmax = k
simimax = similarity[k] simimax = similarity[k]
if idxmax>-1:
errpairs.append((seqdir, events[idxmax], events[index])) input_event = events[idxmax]
else:
input_event = ''
errpairs.append((seqdir, input_event, events[index]))
err_similarity.append(max(similarity)) err_similarity.append(max(similarity))
return corrpairs, errpairs, corr_similarity, err_similarity
return errpairs, corrpairs, err_similarity, correct_similarity
# def contrast_analysis(del_barcode_file, basepath, savepath, saveimgs=False): def test_rpath_deleted():
def get_relative_paths(del_barcode_file, basepath, savepath, saveimgs=False): '''deletedBarcode.txt 格式的 1:n 数据结果文件, returnGoods.txt格式数据文件不需要调用该函数'''
'''
del_barcode_file: del_bfile = r'\\192.168.1.28\share\测试_202406\709\deletedBarcode.txt'
deletedBarcode.txt 格式的 1:n 数据结果文件 basepath = r'\\192.168.1.28\share\测试_202406\709'
returnGoods.txt格式数据文件不需要调用该函数one2n_old() 函数返回的 errpairs savepath = r'D:\DetectTracking\contrast\result'
中元素为三元元组(取出,放入, 错误匹配) saveimgs = True
'''
relative_paths = [] relative_paths = []
'''1. 读取 deletedBarcode 文件 ''' '''1. 读取 deletedBarcode 文件 '''
all_list = read_deletedBarcode_file(del_barcode_file) all_list = read_deletedBarcode_file(del_bfile)
'''2. 算法性能评估,并输出 (取出,删除, 错误匹配) 对 ''' '''2. 算法性能评估,并输出 (取出,删除, 错误匹配) 对 '''
errpairs, corrpairs, _, _ = one2n_old(all_list) corrpairs, errpairs, _, _ = one2n_deleted(all_list)
'''3. 构造事件组合(取出,放入并删除, 错误匹配) 对应路径 ''' '''3. 构造事件组合(取出,放入并删除, 错误匹配) 对应路径 '''
for errpair in errpairs: for errpair in errpairs:
GetoutPath, InputPath, ErrorPath = get_contrast_paths(errpair, basepath) GetoutPath, InputPath, ErrorPath = get_contrast_paths(errpair, basepath)
relative_paths.append((GetoutPath, InputPath, ErrorPath))
pairs = (GetoutPath, InputPath, ErrorPath)
relative_paths.append(pairs)
print(InputPath)
'''3. 获取 (取出,放入并删除, 错误匹配) 对应路径,保存相应轨迹图像''' '''3. 获取 (取出,放入并删除, 错误匹配) 对应路径,保存相应轨迹图像'''
if saveimgs: if saveimgs:
save_tracking_imgpairs(errpair, basepath, savepath) save_tracking_imgpairs(pairs, savepath)
return relative_paths def test_rpath_return():
return_bfile = r'\\192.168.1.28\share\测试_202406\1101\images\returnGoods.txt'
basepath = r'\\192.168.1.28\share\测试_202406\1101\images'
def one2n_test(): savepath = r'D:\DetectTracking\contrast\result'
fpath = r'\\192.168.1.28\share\测试_202406\deletedBarcode\other'
fpath = r'\\192.168.1.28\share\测试_202406\1030\images'
all_list = read_returnGoods_file(return_bfile)
corrpairs, errpairs, _, _ = one2n_return(all_list, basepath)
for corrpair in corrpairs:
GetoutPath = os.path.join(basepath, corrpair[0])
InputPath = os.path.join(basepath, corrpair[1])
pairs = (GetoutPath, InputPath)
save_tracking_imgpairs(pairs, savepath)
for errpair in errpairs:
GetoutPath = os.path.join(basepath, errpair[0])
InputPath = os.path.join(basepath, errpair[1])
ErrorPath = os.path.join(basepath, errpair[2])
pairs = (GetoutPath, InputPath, ErrorPath)
save_tracking_imgpairs(pairs, savepath)
def test_one2n():
'''
1:n 性能测试
兼容 2 种 txt 文件格式returnGoods.txt, deletedBarcode.txt
fpath: 文件路径、或文件夹,其中包含多个 txt 文件
savepath: pr曲线保存路径
'''
# fpath = r'\\192.168.1.28\share\测试_202406\deletedBarcode\other' # deletedBarcode.txt
fpath = r'\\192.168.1.28\share\测试_202406\returnGoods\all' # returnGoods.txt
savepath = r'\\192.168.1.28\share\测试_202406\deletedBarcode\illustration' savepath = r'\\192.168.1.28\share\测试_202406\deletedBarcode\illustration'
if not os.path.exists(savepath):
os.mkdir(savepath)
if os.path.isdir(fpath): if os.path.isdir(fpath):
filepaths = [os.path.join(fpath, f) for f in os.listdir(fpath) filepaths = [os.path.join(fpath, f) for f in os.listdir(fpath)
@ -366,37 +446,27 @@ def one2n_test():
filepaths = [fpath] filepaths = [fpath]
else: else:
return return
FileFormat = {}
if not os.path.exists(savepath):
os.mkdir(savepath)
BarLists, blists = {}, [] BarLists, blists = {}, []
for pth in filepaths: for pth in filepaths:
file = str(Path(pth).stem) file = str(Path(pth).stem)
if file.find('deletedBarcode')>=0: if file.find('deletedBarcode')>=0:
FileFormat[file] = 'deletedBarcode'
blist = read_deletedBarcode_file(pth) blist = read_deletedBarcode_file(pth)
elif file.find('returnGoods')>=0: if file.find('returnGoods')>=0:
FileFormat[file] = 'returnGoods'
blist = read_returnGoods_file(pth) blist = read_returnGoods_file(pth)
else:
return
BarLists.update({file: blist}) BarLists.update({file: blist})
blists.extend(blist) blists.extend(blist)
BarLists.update({file: blist}) if len(blists): BarLists.update({"Total": blists})
BarLists.update({"Total": blists})
for file, blist in BarLists.items(): for file, blist in BarLists.items():
if FileFormat[file] == 'deletedBarcode': if all(b['filetype']=="deletedBarcode" for b in blist):
_, _, err_similarity, correct_similarity = one2n_old(blist) _, _, correct_similarity, err_similarity = one2n_deleted(blist)
elif FileFormat[file] == 'returnGoods': if all(b['filetype']=="returnGoods" for b in blists):
_, _, err_similarity, correct_similarity = one2n_new(blist) _, _, correct_similarity, err_similarity = one2n_return(blist)
else:
_, _, err_similarity, correct_similarity = one2n_old(blist)
recall, prec, ths = compute_recall_precision(err_similarity, correct_similarity) recall, prec, ths = compute_recall_precision(err_similarity, correct_similarity)
@ -413,51 +483,16 @@ def one2n_test():
def test_getreltpath():
'''
适用于deletedBarcode.txt不适用于returnGoods.txt
'''
del_barcode_file = r'\\192.168.1.28\share\测试_202406\709\deletedBarcode.txt'
basepath = r'\\192.168.1.28\share\测试_202406\709'
# del_barcode_file = r'\\192.168.1.28\share\测试_202406\1030\images\returnGoods.txt'
# basepath = r'\\192.168.1.28\share\测试_202406\1030\images'
savepath = r'D:\contrast\dataset\result'
saveimgs = True
try:
relative_path = get_relative_paths(del_barcode_file, basepath, savepath, saveimgs)
except Exception as e:
print(f'Error Type: {e}')
if __name__ == '__main__': if __name__ == '__main__':
# test_one2n()
one2n_test() test_rpath_return() # returnGoods.txt
test_rpath_deleted() # deleteBarcode.txt
# test_getreltpath()
# try:
# test_rpath_return()
# test_rpath_deleted()
# except Exception as e:
# print(e)

View File

@ -11,7 +11,7 @@ Created on Fri Aug 30 17:53:03 2024
标准特征提取,并保存至文件夹 stdFeaturePath 中, 标准特征提取,并保存至文件夹 stdFeaturePath 中,
也可在运行过程中根据与购物事件集合 barcodes 交集执行 也可在运行过程中根据与购物事件集合 barcodes 交集执行
2. 1:1 比对性能测试, 2. 1:1 比对性能测试,
func: contrast_performance_evaluate(resultPath) func: one2one_eval(resultPath)
(1) 求购物事件和标准特征级 Barcode 交集,构造 evtDict、stdDict (1) 求购物事件和标准特征级 Barcode 交集,构造 evtDict、stdDict
(2) 构造扫 A 放 A、扫 A 放 B 组合mergePairs = AA_list + AB_list (2) 构造扫 A 放 A、扫 A 放 B 组合mergePairs = AA_list + AB_list
(3) 循环计算 mergePairs 中元素 "(A, A) 或 (A, B)" 相似度; (3) 循环计算 mergePairs 中元素 "(A, A) 或 (A, B)" 相似度;
@ -32,86 +32,83 @@ import os
import sys import sys
import random import random
import pickle import pickle
import torch # import torch
import time import time
import json # import json
from pathlib import Path from pathlib import Path
from scipy.spatial.distance import cdist from scipy.spatial.distance import cdist
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import shutil import shutil
from datetime import datetime from datetime import datetime
from openpyxl import load_workbook, Workbook # from openpyxl import load_workbook, Workbook
# Vit版resnet, 和现场特征不一致需将resnet_vit中文件提出
# from config import config as conf # from config import config as conf
# from model import resnet18 # from model import resnet18 as resnet18
# from inference import load_contrast_model # from feat_inference import inference_image
# from inference import featurize
# embedding_size = conf.embedding_size
# img_size = conf.img_size
# device = conf.device
# model = load_contrast_model()
sys.path.append(r"D:\DetectTracking") sys.path.append(r"D:\DetectTracking")
from tracking.utils.read_data import extract_data, read_tracking_output, read_deletedBarcode_file from tracking.utils.read_data import extract_data, read_tracking_output, read_one2one_simi, read_deletedBarcode_file
from config import config as conf
from model import resnet18 as resnet18
from feat_inference import inference_image
from genfeats import genfeatures, stdfeat_infer
IMG_FORMAT = ['.bmp', '.jpg', '.jpeg', '.png'] IMG_FORMAT = ['.bmp', '.jpg', '.jpeg', '.png']
'''
共6个地址
(1) stdSamplePath: 用于生成比对标准特征集的原始图像地址
(2) stdBarcodePath: 比对标准特征集原始图像地址的pickle文件存储{barcode: [imgpath1, imgpath1, ...]}
(3) stdFeaturePath: 比对标准特征集特征存储地址
(4) eventFeatPath: 用于1:1比对的购物事件特征存储地址、对应子图存储地址
(5) subimgPath: 1:1比对购物事件轨迹、标准barcode所对应的 subimgs 存储地址
(6) resultPath: 1:1比对结果存储地址
'''
stdSamplePath = r"\\192.168.1.28\share\已标注数据备份\对比数据\barcode\barcode_500_1979_已清洗"
stdBarcodePath = r"\\192.168.1.28\share\测试_202406\contrast\std_barcodes_2192"
stdFeaturePath = r"\\192.168.1.28\share\测试_202406\contrast\std_features_ft32"
eventFeatPath = r"\\192.168.1.28\share\测试_202406\contrast\events"
subimgPath = r'\\192.168.1.28\share\测试_202406\contrast\subimgs'
resultPath = r"D:\DetectTracking\contrast\result\pickle"
if not os.path.exists(resultPath):
os.makedirs(resultPath)
##============ load resnet mdoel
model = resnet18().to(conf.device)
# model = nn.DataParallel(model).to(conf.device)
model.load_state_dict(torch.load(conf.test_model, map_location=conf.device))
model.eval()
print('load model {} '.format(conf.testbackbone))
def creat_shopping_event(eventPath, subimgPath=False): def int8_to_ft16(arr_uint8, amin, amax):
arr_ft16 = (arr_uint8 / 255 * (amax-amin) + amin).astype(np.float16)
return arr_ft16
def ft16_to_uint8(arr_ft16):
# pickpath = r"\\192.168.1.28\share\测试_202406\contrast\std_features_ft32vsft16\6902265587712_ft16.pickle"
# with open(pickpath, 'rb') as f:
# edict = pickle.load(f)
# arr_ft16 = edict['feats']
amin = np.min(arr_ft16)
amax = np.max(arr_ft16)
arr_ft255 = (arr_ft16 - amin) * 255 / (amax-amin)
arr_uint8 = arr_ft255.astype(np.uint8)
arr_ft16_ = int8_to_ft16(arr_uint8, amin, amax)
arrDistNorm = np.linalg.norm(arr_ft16_ - arr_ft16) / arr_ft16_.size
return arr_uint8, arr_ft16_
def creat_shopping_event(eventPath):
'''构造放入商品事件字典,这些事件需满足条件: '''构造放入商品事件字典,这些事件需满足条件:
1) 前后摄至少有一条轨迹输出 1) 前后摄至少有一条轨迹输出
2) 保存有帧图像,以便裁剪出 boxe 子图 2) 保存有帧图像,以便裁剪出 boxe 子图
''' '''
# filename = "20240723-155413_6904406215720"
'''filename下为一次购物事件'''
eventName = os.path.basename(eventPath)
'''================ 0. 检查 filename 及 eventPath 正确性和有效性 ================''' '''evtName 为一次购物事件'''
nmlist = eventName.split('_') evtName = os.path.basename(eventPath)
# if eventName.find('2024')<0 or len(nmlist)!=2 or len(nmlist[0])!=15 or len(nmlist[1])<11: evtList = evtName.split('_')
# return
if eventName.find('2024')<0 or len(nmlist)!=2 or len(nmlist[1])<11: '''================ 0. 检查 evtName 及 eventPath 正确性和有效性 ================'''
if evtName.find('2024')<0 and len(evtList[0])!=15:
return return
if not os.path.isdir(eventPath): if not os.path.isdir(eventPath):
return return
if len(evtList)==1 or (len(evtList)==2 and len(evtList[1])==0):
barcode = ''
else:
barcode = evtList[-1]
if len(evtList)==3 and evtList[-1]== evtList[-2]:
evtType = 'input'
else:
evtType = 'other'
'''================ 1. 构造事件描述字典,暂定 9 items ===============''' '''================ 1. 构造事件描述字典,暂定 9 items ==============='''
event = {} event = {}
event['barcode'] = eventName.split('_')[1] event['barcode'] = barcode
event['type'] = 'input' event['type'] = evtType
event['filepath'] = eventPath event['filepath'] = eventPath
event['back_imgpaths'] = [] event['back_imgpaths'] = []
event['front_imgpaths'] = [] event['front_imgpaths'] = []
@ -120,7 +117,8 @@ def creat_shopping_event(eventPath, subimgPath=False):
event['back_feats'] = np.empty((0, 256), dtype=np.float64) event['back_feats'] = np.empty((0, 256), dtype=np.float64)
event['front_feats'] = np.empty((0, 256), dtype=np.float64) event['front_feats'] = np.empty((0, 256), dtype=np.float64)
event['feats_compose'] = np.empty((0, 256), dtype=np.float64) event['feats_compose'] = np.empty((0, 256), dtype=np.float64)
# event['feats_select'] = np.empty((0, 256), dtype=np.float64) event['one2one_simi'] = None
event['feats_select'] = np.empty((0, 256), dtype=np.float64)
'''================= 2. 读取 data 文件 =============================''' '''================= 2. 读取 data 文件 ============================='''
@ -144,8 +142,12 @@ def creat_shopping_event(eventPath, subimgPath=False):
elif CamerType == '1': elif CamerType == '1':
event['front_boxes'] = tracking_output_boxes event['front_boxes'] = tracking_output_boxes
event['front_feats'] = tracking_output_feats event['front_feats'] = tracking_output_feats
if dataname.find("process.data")==0:
simiDict = read_one2one_simi(datapath)
event['one2one_simi'] = simiDict
if len(event['back_boxes'])==0 or len(event['front_boxes'])==0: if len(event['back_boxes'])==0 or len(event['front_boxes'])==0:
return None return None
@ -165,16 +167,8 @@ def creat_shopping_event(eventPath, subimgPath=False):
if len(ft_feats): if len(ft_feats):
event['feats_select'] = ft_feats event['feats_select'] = ft_feats
# pickpath = os.path.join(savePath, f"{filename}.pickle")
# with open(pickpath, 'wb') as f:
# pickle.dump(event, f)
# print(f"Event: {filename}")
# if subimgPath==False:
# eventList.append(event)
# continue
'''================ 2. 读取图像文件地址并按照帧ID排序 =============''' '''================ 3. 读取图像文件地址并按照帧ID排序 ============='''
frontImgs, frontFid = [], [] frontImgs, frontFid = [], []
backImgs, backFid = [], [] backImgs, backFid = [], []
for imgname in os.listdir(eventPath): for imgname in os.listdir(eventPath):
@ -194,11 +188,11 @@ def creat_shopping_event(eventPath, subimgPath=False):
frontIdx = np.argsort(np.array(frontFid)) frontIdx = np.argsort(np.array(frontFid))
backIdx = np.argsort(np.array(backFid)) backIdx = np.argsort(np.array(backFid))
'''2.1 生成依据帧 ID 排序的前后摄图像地址列表''' '''3.1 生成依据帧 ID 排序的前后摄图像地址列表'''
frontImgs = [frontImgs[i] for i in frontIdx] frontImgs = [frontImgs[i] for i in frontIdx]
backImgs = [backImgs[i] for i in backIdx] backImgs = [backImgs[i] for i in backIdx]
'''2.2 将前、后摄图像路径添加至事件字典''' '''3.2 将前、后摄图像路径添加至事件字典'''
bfid = event['back_boxes'][:, 7].astype(np.int64) bfid = event['back_boxes'][:, 7].astype(np.int64)
@ -209,101 +203,16 @@ def creat_shopping_event(eventPath, subimgPath=False):
event['front_imgpaths'] = [frontImgs[i-1] for i in ffid] event['front_imgpaths'] = [frontImgs[i-1] for i in ffid]
'''================ 3. 判断当前事件有效性,并添加至事件列表 ==========''' '''================ 4. 判断当前事件有效性,并添加至事件列表 =========='''
condt1 = len(event['back_imgpaths'])==0 or len(event['front_imgpaths'])==0 condt1 = len(event['back_imgpaths'])==0 or len(event['front_imgpaths'])==0
condt2 = len(event['front_feats'])==0 and len(event['back_feats'])==0 condt2 = len(event['front_feats'])==0 and len(event['back_feats'])==0
if condt1 or condt2: if condt1 or condt2:
print(f"Event: {eventName}, Error, condt1: {condt1}, condt2: {condt2}") print(f"Event: {evtName}, Error, condt1: {condt1}, condt2: {condt2}")
return None return None
'''构造放入商品事件列表,暂不处理'''
# delepath = os.path.join(basePath, 'deletedBarcode.txt')
# bcdList = read_deletedBarcode_file(delepath)
# for slist in bcdList:
# getoutFold = slist['SeqDir'].strip()
# getoutPath = os.path.join(basePath, getoutFold)
# '''取出事件文件夹不存在,跳出循环'''
# if not os.path.exists(getoutPath) and not os.path.isdir(getoutPath):
# continue
# ''' 生成取出事件字典 '''
# event = {}
# event['barcode'] = slist['Deleted'].strip()
# event['type'] = 'getout'
# event['basePath'] = getoutPath
return event return event
# def get_std_barcodeDict(bcdpath, savepath):
# '''
# inputs:
# bcdpath: 已清洗的barcode样本图像如果barcode下有'base'文件夹,只选用该文件夹下图像
# (default = r'\\192.168.1.28\share\已标注数据备份\对比数据\barcode\barcode_1771')
# 功能:
# 生成并保存只有一个key值的字典 {barcode: [imgpath1, imgpath1, ...]}
# savepath: 字典存储地址文件名格式barcode.pickle
# '''
# # savepath = r'\\192.168.1.28\share\测试_202406\contrast\std_barcodes'
# '''读取数据集中 barcode 列表'''
# stdBarcodeList = []
# for filename in os.listdir(bcdpath):
# filepath = os.path.join(bcdpath, filename)
# # if not os.path.isdir(filepath) or not filename.isdigit() or len(filename)<8:
# # continue
# stdBarcodeList.append(filename)
# bcdPaths = [(barcode, os.path.join(bcdpath, barcode)) for barcode in stdBarcodeList]
# '''遍历数据集针对每一个barcode生成并保存字典{barcode: [imgpath1, imgpath1, ...]}'''
# k = 0
# errbarcodes = []
# for barcode, bpath in bcdPaths:
# pickpath = os.path.join(savepath, f"{barcode}.pickle")
# if os.path.isfile(pickpath):
# continue
# stdBarcodeDict = {}
# stdBarcodeDict[barcode] = []
# for root, dirs, files in os.walk(bpath):
# imgpaths = []
# if "base" in dirs:
# broot = os.path.join(root, "base")
# for imgname in os.listdir(broot):
# imgpath = os.path.join(broot, imgname)
# file, ext = os.path.splitext(imgpath)
# if ext not in IMG_FORMAT:
# continue
# imgpaths.append(imgpath)
# stdBarcodeDict[barcode].extend(imgpaths)
# break
# else:
# for imgname in files:
# imgpath = os.path.join(root, imgname)
# _, ext = os.path.splitext(imgpath)
# if ext not in IMG_FORMAT: continue
# imgpaths.append(imgpath)
# stdBarcodeDict[barcode].extend(imgpaths)
# pickpath = os.path.join(savepath, f"{barcode}.pickle")
# with open(pickpath, 'wb') as f:
# pickle.dump(stdBarcodeDict, f)
# print(f"Barcode: {barcode}")
# # k += 1
# # if k == 10:
# # break
# print(f"Len of errbarcodes: {len(errbarcodes)}")
# return
def save_event_subimg(event, savepath): def save_event_subimg(event, savepath):
''' '''
@ -340,131 +249,20 @@ def save_event_subimg(event, savepath):
print(f"Image saved: {os.path.basename(event['filepath'])}") print(f"Image saved: {os.path.basename(event['filepath'])}")
def batch_inference(imgpaths, batch):
size = len(imgpaths)
groups = []
for i in range(0, size, batch):
end = min(batch + i, size)
groups.append(imgpaths[i: end])
features = [] def one2one_eval(resultPath):
for group in groups:
feature = featurize(group, conf.test_transform, model, conf.device)
features.append(feature)
features = np.concatenate(features, axis=0)
return features
# def stdfeat_infer(imgPath, featPath, bcdSet=None):
# '''
# inputs:
# imgPath: 该文件夹下的 pickle 文件格式 {barcode: [imgpath1, imgpath1, ...]}
# featPath: imgPath图像对应特征的存储地址
# 功能:
# 对 imgPath中图像进行特征提取生成只有一个key值的字典
# {barcode: features}features.shape=(nsample, 256),并保存至 featPath 中
# '''
# # imgPath = r"\\192.168.1.28\share\测试_202406\contrast\std_barcodes"
# # featPath = r"\\192.168.1.28\share\测试_202406\contrast\std_features"
# stdBarcodeDict = {}
# stdBarcodeDict_ft16 = {}
# '''4处同名: (1)barcode原始图像文件夹; (2)imgPath中的 .pickle 文件名、该pickle文件中字典的key值'''
# k = 0
# for filename in os.listdir(imgPath):
# bcd, ext = os.path.splitext(filename)
# pkpath = os.path.join(featPath, f"{bcd}.pickle")
# if os.path.isfile(pkpath): continue
# if bcdSet is not None and bcd not in bcdSet:
# continue
# filepath = os.path.join(imgPath, filename)
# stdbDict = {}
# stdbDict_ft16 = {}
# stdbDict_uint8 = {}
# t1 = time.time()
# try:
# with open(filepath, 'rb') as f:
# bpDict = pickle.load(f)
# for barcode, imgpaths in bpDict.items():
# # feature = batch_inference(imgpaths, 8) #from vit distilled model of LiChen
# feature = inference_image(imgpaths, conf.test_transform, model, conf.device)
# feature /= np.linalg.norm(feature, axis=1)[:, None]
# # float16
# feature_ft16 = feature.astype(np.float16)
# feature_ft16 /= np.linalg.norm(feature_ft16, axis=1)[:, None]
# # uint8, 两种策略1) 精度损失小, 2) 计算复杂度小
# # feature_uint8, _ = ft16_to_uint8(feature_ft16)
# feature_uint8 = (feature_ft16*128).astype(np.int8)
# except Exception as e:
# print(f"Error accured at: {filename}, with Exception is: {e}")
# '''================ 保存单个barcode特征 ================'''
# ##================== float32
# stdbDict["barcode"] = barcode
# stdbDict["imgpaths"] = imgpaths
# stdbDict["feats_ft32"] = feature
# stdbDict["feats_ft16"] = feature_ft16
# stdbDict["feats_uint8"] = feature_uint8
# with open(pkpath, 'wb') as f:
# pickle.dump(stdbDict, f)
# stdBarcodeDict[barcode] = feature
# stdBarcodeDict_ft16[barcode] = feature_ft16
# t2 = time.time()
# print(f"Barcode: {barcode}, need time: {t2-t1:.1f} secs")
# # k += 1
# # if k == 10:
# # break
# ##================== float32
# # pickpath = os.path.join(featPath, f"barcode_features_{k}.pickle")
# # with open(pickpath, 'wb') as f:
# # pickle.dump(stdBarcodeDict, f)
# ##================== float16
# # pickpath_ft16 = os.path.join(featPath, f"barcode_features_ft16_{k}.pickle")
# # with open(pickpath_ft16, 'wb') as f:
# # pickle.dump(stdBarcodeDict_ft16, f)
# return
def contrast_performance_evaluate(resultPath):
# stdBarcode = [p.stem for p in Path(stdFeaturePath).iterdir() if p.is_file() and p.suffix=='.pickle'] # stdBarcode = [p.stem for p in Path(stdFeaturePath).iterdir() if p.is_file() and p.suffix=='.pickle']
stdBarcode = [p.stem for p in Path(stdBarcodePath).iterdir() if p.is_file() and p.suffix=='.pickle'] stdBarcode = [p.stem for p in Path(stdBarcodePath).iterdir() if p.is_file() and p.suffix=='.pickle']
'''购物事件列表,该列表中的 Barcode 存在于标准的 stdBarcode 内''' '''购物事件列表,该列表中的 Barcode 存在于标准的 stdBarcode 内'''
# evtList = [(p.stem, p.stem.split('_')[1]) for p in Path(eventFeatPath).iterdir() evtList = [(p.stem, p.stem.split('_')[-1]) for p in Path(eventFeatPath).iterdir()
# if p.is_file()
# and p.suffix=='.pickle'
# and len(p.stem.split('_'))==2
# and p.stem.split('_')[1].isdigit()
# and p.stem.split('_')[1] in stdBarcode
# ]
evtList = [(p.stem, p.stem.split('_')[1]) for p in Path(eventFeatPath).iterdir()
if p.is_file() if p.is_file()
and str(p).find('240910')>0
and p.suffix=='.pickle' and p.suffix=='.pickle'
and len(p.stem.split('_'))==2 and (len(p.stem.split('_'))==2 or len(p.stem.split('_'))==3)
and p.stem.split('_')[1].isdigit() and p.stem.split('_')[-1].isdigit()
and p.stem.split('_')[1] in stdBarcode and p.stem.split('_')[-1] in stdBarcode
] ]
barcodes = set([bcd for _, bcd in evtList]) barcodes = set([bcd for _, bcd in evtList])
@ -612,7 +410,7 @@ def contrast_performance_evaluate(resultPath):
f.write(line + '\n') f.write(line + '\n')
print("func: contrast_performance_evaluate(), have finished!") print("func: one2one_eval(), have finished!")
@ -684,44 +482,16 @@ def compute_precise_recall(pickpath):
plt.savefig(f'./result/{file}_pr.png') # svg, png, pdf plt.savefig(f'./result/{file}_pr.png') # svg, png, pdf
def generate_event_and_stdfeatures(): def gen_eventdict(eventDatePath, saveimg=True):
'''=========================== 1. 生成标准特征集 ========================'''
'''1.1 提取 stdSamplePath 中样本地址,生成字典{barcode: [imgpath1, imgpath1, ...]}
并存储为 pickle 文件barcode.pickle'''
# get_std_barcodeDict(stdSamplePath, stdBarcodePath)
# print("standard imgpath have extracted and saved")
'''1.2 特征提取,并保存至文件夹 stdFeaturePath 中,也可在运行过程中根据 barcodes 交集执行'''
# stdfeat_infer(stdBarcodePath, stdFeaturePath, bcdSet=None)
# print("standard features have generated!")
'''=========================== 2. 提取并存储事件特征 ========================'''
eventDatePath = [r'\\192.168.1.28\share\测试_202406\0910\images',
# r'\\192.168.1.28\share\测试_202406\0723\0723_1',
# r'\\192.168.1.28\share\测试_202406\0723\0723_2',
# r'\\192.168.1.28\share\测试_202406\0723\0723_3',
# r'\\192.168.1.28\share\测试_202406\0722\0722_01',
# r'\\192.168.1.28\share\测试_202406\0722\0722_02'
# r'\\192.168.1.28\share\测试_202406\0719\719_3',
# r'\\192.168.1.28\share\测试_202406\0716\0716_1',
# r'\\192.168.1.28\share\测试_202406\0716\0716_2',
# r'\\192.168.1.28\share\测试_202406\0716\0716_3',
# r'\\192.168.1.28\share\测试_202406\0712\0712_1', # 无帧图像
# r'\\192.168.1.28\share\测试_202406\0712\0712_2', # 无帧图像
]
eventList = [] eventList = []
# k = 0 # k = 0
for datePath in eventDatePath: for datePath in eventDatePath:
for eventName in os.listdir(datePath): for eventName in os.listdir(datePath):
pickpath = os.path.join(eventFeatPath, f"{eventName}.pickle") pickpath = os.path.join(eventFeatPath, f"{eventName}.pickle")
if os.path.isfile(pickpath): if os.path.isfile(pickpath):
continue continue
eventPath = os.path.join(datePath, eventName) eventPath = os.path.join(datePath, eventName)
eventDict = creat_shopping_event(eventPath) eventDict = creat_shopping_event(eventPath)
@ -736,52 +506,61 @@ def generate_event_and_stdfeatures():
# break # break
## 保存轨迹中 boxes 子图 ## 保存轨迹中 boxes 子图
if not saveimg:
return
for event in eventList: for event in eventList:
basename = os.path.basename(event['filepath']) basename = os.path.basename(event['filepath'])
savepath = os.path.join(subimgPath, basename) savepath = os.path.join(subimgPath, basename)
if not os.path.exists(savepath): if not os.path.exists(savepath):
os.makedirs(savepath) os.makedirs(savepath)
save_event_subimg(event, savepath) save_event_subimg(event, savepath)
def test_one2one():
eventDatePath = [r'\\192.168.1.28\share\测试_202406\1101\images',
# r'\\192.168.1.28\share\测试_202406\0910\images',
# r'\\192.168.1.28\share\测试_202406\0723\0723_1',
# r'\\192.168.1.28\share\测试_202406\0723\0723_2',
# r'\\192.168.1.28\share\测试_202406\0723\0723_3',
# r'\\192.168.1.28\share\测试_202406\0722\0722_01',
# r'\\192.168.1.28\share\测试_202406\0722\0722_02'
# r'\\192.168.1.28\share\测试_202406\0719\719_3',
# r'\\192.168.1.28\share\测试_202406\0716\0716_1',
# r'\\192.168.1.28\share\测试_202406\0716\0716_2',
# r'\\192.168.1.28\share\测试_202406\0716\0716_3',
# r'\\192.168.1.28\share\测试_202406\0712\0712_1', # 无帧图像
# r'\\192.168.1.28\share\测试_202406\0712\0712_2', # 无帧图像
]
bcdList = []
for evtpath in eventDatePath:
for evtname in os.listdir(evtpath):
evt = evtname.split('_')
if len(evt)>=2 and evt[-1].isdigit() and len(evt[-1])>=10:
bcdList.append(evt[-1])
bcdSet = set(bcdList)
print("eventList have generated and features have saved!")
def int8_to_ft16(arr_uint8, amin, amax):
arr_ft16 = (arr_uint8 / 255 * (amax-amin) + amin).astype(np.float16)
return arr_ft16
def ft16_to_uint8(arr_ft16):
# pickpath = r"\\192.168.1.28\share\测试_202406\contrast\std_features_ft32vsft16\6902265587712_ft16.pickle"
# with open(pickpath, 'rb') as f:
# edict = pickle.load(f)
# arr_ft16 = edict['feats']
amin = np.min(arr_ft16)
amax = np.max(arr_ft16)
arr_ft255 = (arr_ft16 - amin) * 255 / (amax-amin)
arr_uint8 = arr_ft255.astype(np.uint8)
arr_ft16_ = int8_to_ft16(arr_uint8, amin, amax)
'''==== 1. 生成标准特征集, 只需运行一次 ==============='''
genfeatures(stdSamplePath, stdBarcodePath, stdFeaturePath, bcdSet)
print("stdFeats have generated and saved!")
arrDistNorm = np.linalg.norm(arr_ft16_ - arr_ft16) / arr_ft16_.size '''==== 2. 生成事件字典, 只需运行一次 ==============='''
gen_eventdict(eventDatePath)
return arr_uint8, arr_ft16_ print("eventList have generated and saved!")
'''==== 3. 1:1性能评估 ==============='''
one2one_eval(resultPath)
def main():
# generate_event_and_stdfeatures()
contrast_performance_evaluate(resultPath)
for filename in os.listdir(resultPath): for filename in os.listdir(resultPath):
if filename.find('.pickle') < 0: continue if filename.find('.pickle') < 0: continue
if filename.find('0911') < 0: continue if filename.find('0911') < 0: continue
@ -789,63 +568,29 @@ def main():
compute_precise_recall(pickpath) compute_precise_recall(pickpath)
# def main_std():
# std_sample_path = r"\\192.168.1.28\share\已标注数据备份\对比数据\barcode\barcode_500_2192_已清洗"
# std_barcode_path = r"\\192.168.1.28\share\测试_202406\contrast\std_barcodes_2192"
# std_feature_path = r"\\192.168.1.28\share\测试_202406\contrast\std_features_2192_ft32vsft16"
# get_std_barcodeDict(std_sample_path, std_barcode_path)
# stdfeat_infer(std_barcode_path, std_feature_path, bcdSet=None)
# # fileList = []
# # for filename in os.listdir(std_barcode_path):
# # filepath = os.path.join(std_barcode_path, filename)
# # with open(filepath, 'rb') as f:
# # bpDict = pickle.load(f)
# # for v in bpDict.values():
# # fileList.append(len(v))
# # print("done")
if __name__ == '__main__': if __name__ == '__main__':
main() '''
# main_std() 共6个地址
(1) stdSamplePath: 用于生成比对标准特征集的原始图像地址
(2) stdBarcodePath: 比对标准特征集原始图像地址的pickle文件存储{barcode: [imgpath1, imgpath1, ...]}
(3) stdFeaturePath: 比对标准特征集特征存储地址
(4) eventFeatPath: 用于1:1比对的购物事件特征存储地址、对应子图存储地址
(5) subimgPath: 1:1比对购物事件轨迹、标准barcode所对应的 subimgs 存储地址
(6) resultPath: 1:1比对结果存储地址
'''
stdSamplePath = r"\\192.168.1.28\share\已标注数据备份\对比数据\barcode\barcode_500_1979_已清洗"
stdBarcodePath = r"\\192.168.1.28\share\测试_202406\contrast\std_barcodes_2192"
stdFeaturePath = r"\\192.168.1.28\share\测试_202406\contrast\std_features_ft32"
eventFeatPath = r"\\192.168.1.28\share\测试_202406\contrast\events"
subimgPath = r'\\192.168.1.28\share\测试_202406\contrast\subimgs'
resultPath = r"D:\DetectTracking\contrast\result\pickle"
if not os.path.exists(resultPath):
os.makedirs(resultPath)
test_one2one()

View File

@ -17,7 +17,6 @@ import copy
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from imgs_inference import run_yolo from imgs_inference import run_yolo
from event_time_specify import devide_motion_state#, state_measure from event_time_specify import devide_motion_state#, state_measure
from tracking.utils.read_data import read_seneor from tracking.utils.read_data import read_seneor

View File

@ -285,6 +285,38 @@ def boxing_img(det, img, line_width=3):
return imgx return imgx
def array2list(bboxes):
track_fids = np.unique(bboxes[:, 7].astype(int))
track_fids.sort()
lboxes = []
for f_id in track_fids:
# print(f"The ID is: {t_id}")
idx = np.where(bboxes[:, 7] == f_id)[0]
box = bboxes[idx, :]
lboxes.append(box)
assert len(set(box[:, 4])) == len(box), "Please check!!!"
return lboxes
def get_subimgs(imgs, tracks, scale=2):
bboxes = []
if len(tracks):
bboxes = array2list(tracks)
subimgs = []
for i, boxes in enumerate(bboxes):
fid = int(boxes[0, 7])
for *xyxy, tid, conf, cls, fid, bid in boxes:
pt2 = [p/scale for p in xyxy]
x1, y1, x2, y2 = (int(pt2[0]), int(pt2[1])), (int(pt2[2]), int(pt2[3]))
subimgs.append((int(fid), int(bid), imgs[fid-1][y1:y2, x1:x2]))
return subimgs
def draw_tracking_boxes(imgs, tracks, scale=2): def draw_tracking_boxes(imgs, tracks, scale=2):
'''需要确保 imgs 覆盖tracks中的帧ID数 '''需要确保 imgs 覆盖tracks中的帧ID数
tracks: [x1, y1, x2, y2, track_id, score, cls, frame_index, box_index] tracks: [x1, y1, x2, y2, track_id, score, cls, frame_index, box_index]
@ -295,27 +327,15 @@ def draw_tracking_boxes(imgs, tracks, scale=2):
''' '''
def array2list(bboxes):
track_fids = np.unique(bboxes[:, 7].astype(int)) bboxes = []
track_fids.sort() if len(tracks):
bboxes = array2list(tracks)
lboxes = []
for f_id in track_fids:
# print(f"The ID is: {t_id}")
idx = np.where(bboxes[:, 7] == f_id)[0]
box = bboxes[idx, :]
lboxes.append(box)
assert len(set(box[:, 4])) == len(box), "Please check!!!"
return lboxes
bboxes = array2list(tracks)
# if len(bboxes)!=len(imgs): # if len(bboxes)!=len(imgs):
# return False, imgs # return False, imgs
subimgs = [] annimgs = []
for i, boxes in enumerate(bboxes): for i, boxes in enumerate(bboxes):
fid = int(boxes[0, 7]) fid = int(boxes[0, 7])
annotator = Annotator(imgs[fid-1].copy()) annotator = Annotator(imgs[fid-1].copy())
@ -331,11 +351,11 @@ def draw_tracking_boxes(imgs, tracks, scale=2):
pt2 = [p/scale for p in xyxy] pt2 = [p/scale for p in xyxy]
annotator.box_label(pt2, label, color=color) annotator.box_label(pt2, label, color=color)
img = annotator.result() img = annotator.result()
subimgs.append((fid, img)) annimgs.append((int(fid), img))
return subimgs return annimgs

View File

@ -37,6 +37,9 @@ def find_samebox_in_array(arr, target):
def extract_data(datapath): def extract_data(datapath):
'''
0/1_track.data 数据读取
'''
bboxes, ffeats = [], [] bboxes, ffeats = [], []
trackerboxes = np.empty((0, 9), dtype=np.float64) trackerboxes = np.empty((0, 9), dtype=np.float64)
@ -147,8 +150,15 @@ def extract_data(datapath):
return bboxes, ffeats, trackerboxes, tracker_feat_dict, trackingboxes, tracking_feat_dict return bboxes, ffeats, trackerboxes, tracker_feat_dict, trackingboxes, tracking_feat_dict
def read_tracking_output(filepath): def read_tracking_output(filepath):
'''
0/1_tracking_output.data 数据读取
'''
boxes = [] boxes = []
feats = [] feats = []
if not os.path.isfile(filepath):
return np.array(boxes), np.array(feats)
with open(filepath, 'r', encoding='utf-8') as file: with open(filepath, 'r', encoding='utf-8') as file:
for line in file: for line in file:
line = line.strip() # 去除行尾的换行符和可能的空白字符 line = line.strip() # 去除行尾的换行符和可能的空白字符
@ -176,7 +186,6 @@ def read_deletedBarcode_file(filePath):
split_flag, all_list = False, [] split_flag, all_list = False, []
dict, barcode_list, similarity_list = {}, [], [] dict, barcode_list, similarity_list = {}, [], []
clean_lines = [line.strip().replace("'", '').replace('"', '') for line in lines] clean_lines = [line.strip().replace("'", '').replace('"', '') for line in lines]
for i, line in enumerate(clean_lines): for i, line in enumerate(clean_lines):
@ -199,6 +208,7 @@ def read_deletedBarcode_file(filePath):
if label == 'SeqDir': if label == 'SeqDir':
dict['SeqDir'] = value dict['SeqDir'] = value
dict['filetype'] = "deletedBarcode"
if label == 'Deleted': if label == 'Deleted':
dict['Deleted'] = value dict['Deleted'] = value
if label == 'List': if label == 'List':
@ -259,15 +269,19 @@ def read_returnGoods_file(filePath):
if label == 'SeqDir': if label == 'SeqDir':
dict['SeqDir'] = value dict['SeqDir'] = value
dict['Deleted'] = value.split('_')[-1] dict['Deleted'] = value.split('_')[-1]
dict['filetype'] = "returnGoods"
if label == 'List': if label == 'List':
split_flag = True split_flag = True
continue continue
if split_flag: if split_flag:
bcd = label.split('_')[-1]
# event_list.append(label + '_' + bcd)
event_list.append(label) event_list.append(label)
barcode_list.append(label.split('_')[-1]) barcode_list.append(bcd)
similarity_list.append(value.split(',')[0]) similarity_list.append(value.split(',')[0])
type_list.append(value.split('=')[-1]) type_list.append(value.split('=')[-1])
if len(barcode_list): dict['barcode'] = barcode_list if len(barcode_list): dict['barcode'] = barcode_list
if len(similarity_list): dict['similarity'] = similarity_list if len(similarity_list): dict['similarity'] = similarity_list
if len(event_list): dict['event'] = event_list if len(event_list): dict['event'] = event_list
@ -279,33 +293,51 @@ def read_returnGoods_file(filePath):
# =============================================================================
# def read_seneor(filepath):
# WeightDict = OrderedDict()
# with open(filepath, 'r', encoding='utf-8') as f:
# lines = f.readlines()
# for i, line in enumerate(lines):
# line = line.strip()
#
# keyword = line.split(':')[0]
# value = line.split(':')[1]
#
# vdata = [float(s) for s in value.split(',') if len(s)]
#
# WeightDict[keyword] = vdata[-1]
#
# return WeightDict
# =============================================================================
def read_one2one_simi(filePath):
SimiDict = {}
with open(filePath, 'r', encoding='utf-8') as f:
def read_seneor(filepath):
WeightDict = OrderedDict()
with open(filepath, 'r', encoding='utf-8') as f:
lines = f.readlines() lines = f.readlines()
flag = False
for i, line in enumerate(lines): for i, line in enumerate(lines):
line = line.strip() line = line.strip()
if line.find('barcode:')<0 and not flag:
continue
if line.find('barcode:')==0 :
flag = True
continue
keyword = line.split(':')[0] # if line.endswith(','):
value = line.split(':')[1] # line = line[:-1]
if flag:
vdata = [float(s) for s in value.split(',') if len(s)] barcode = line.split(',')[0].strip()
value = line.split(',')[1].split(':')[1].strip()
WeightDict[keyword] = vdata[-1] SimiDict[barcode] = float(value)
return WeightDict if flag and not line:
flag = False
return SimiDict
def read_weight_timeConsuming(filePth): def read_weight_timeConsuming(filePth):
@ -362,15 +394,14 @@ def plot_sensor_curve(WeightDict, SensorDict, ProcessTimeDict):
nw = len(wdata) nw = len(wdata)
assert(nw) >= 8, "The num of weight data is less than 8!" assert(nw) >= 8, "The num of weight data is less than 8!"
i1, i2 = 0, 7 # i1, i2 = 0, 7
while i2 < nw: # while i2 < nw:
data = wdata[i1:(i2+1)] # data = wdata[i1:(i2+1)]
max(data) - min(data) # max(data) - min(data)
# if i2<7:
if i2<7: # i1 = 0
i1 = 0 # else:
else: # i1 = i2-windth
i1 = i2-windth
min_t = min(wtime + stime) min_t = min(wtime + stime)
wtime = [t-min_t for t in wtime] wtime = [t-min_t for t in wtime]
@ -405,15 +436,12 @@ def plot_sensor_curve(WeightDict, SensorDict, ProcessTimeDict):
def main(file_path): def test_process(file_path):
WeightDict, SensorDict, ProcessTimeDict = read_weight_timeConsuming(file_path) WeightDict, SensorDict, ProcessTimeDict = read_weight_timeConsuming(file_path)
plot_sensor_curve(WeightDict, SensorDict, ProcessTimeDict) plot_sensor_curve(WeightDict, SensorDict, ProcessTimeDict)
if __name__ == "__main__":
def main():
files_path = r'\\192.168.1.28\share\测试_202406\0814\0814\20240814-102227-62264578-a720-4eb9-b95e-cb8be009aa98_null' files_path = r'\\192.168.1.28\share\测试_202406\0814\0814\20240814-102227-62264578-a720-4eb9-b95e-cb8be009aa98_null'
k = 0 k = 0
for filename in os.listdir(files_path): for filename in os.listdir(files_path):
@ -424,42 +452,21 @@ if __name__ == "__main__":
extract_data(file_path) extract_data(file_path)
if os.path.isfile(file_path) and filename.find("process.data")>=0: if os.path.isfile(file_path) and filename.find("process.data")>=0:
main(file_path) test_process(file_path)
k += 1 k += 1
if k == 1: if k == 1:
break break
def main1():
fpath = r'\\192.168.1.28\share\测试_202406\1101\images\20241101-140456-44dc75b5-c406-4cb2-8317-c4660bb727a3_6922130101355_6922130101355\process.data'
# print("Done") simidct = read_one2one_simi(fpath)
print(simidct)
if __name__ == "__main__":
# main()
main1()

View File

@ -144,15 +144,124 @@
precision_compare(filepath, savepath) precision_compare(filepath, savepath)
读取 deletedBarcode.txt 和 deletedBarcodeTest.txt 中的数据,进行相似度比较 读取 deletedBarcode.txt 和 deletedBarcodeTest.txt 中的数据,进行相似度比较
genfeats.py
get_std_barcodeDict(bcdpath, savepath)
功能: 生成并保存只有一个key值的字典 {barcode: [imgpath1, imgpath1, ...]}
stdfeat_infer(imgPath, featPath, bcdSet=None)
功能: 对 imgPath 中图像进行特征提取生成只有一个key值的字典。
{barcode: features}features.shape=(nsample, 256),并保存至 featPath 中
one2n_contrast.py one2n_contrast.py
1:n 比对,读取 deletedBarcode.txt实现现场测试评估。 test_one2n()
main(): 1:n 现场测试性能评估,输出 PR 曲线
循环读取不同文件夹中的 deletedBarcode.txt,合并评估。 兼容 2 种 txt 文件格式returnGoods.txt, deletedBarcode.txt,
main1(): 分别对应不同的文件读取函数:
指定deletedBarcode.txt进行1:n性能评估 - read_deletedBarcode_file()
- read_returnGoods_file()
one2n_return(all_list)
输入从returnGoods.txt读取的数据
输出:
corrpairs(取出事件, 正确匹配的放入事件)
errpairs(取出事件, 放入事件, 错误匹配的放入事件)
corr_similarity: (正确匹配时的相似度)
err_similarity: (错误匹配时的相似度)
one2n_deleted(all_list)
输入: 从deletedBarcode.txt读取的数据
输出:
corrpairs(取出事件, 取出的barcode)
errpairs(取出事件, 取出的barcode, 错误匹配的barcode)
corr_similarity: (正确匹配时的相似度)
err_similarity: (错误匹配时的相似度)
save_tracking_imgpairs(pairs, savepath)
输入:
pairs匹配时间对len(2)=2 or 3, 对应正确匹配与错误匹配
savepath结果保存地址其中图像文件的命名为取出事件 + 放入事件 + 错误匹配时间
子函数 get_event_path(), 扫码放入的对齐名
对于 returnGoods.txt, 放入事件的事件名和对应的文件夹名不一致,需要对齐
test_rpath_deleted()
功能:
针对 eletedBarcode.txt 格式的 1:n 数据结果文件
获得 1:n 情况下正确或匹配事件对(取出事件、放入事件、错误匹配事件)
匹配事件分析, 实现函数save_tracking_imgpairs()
重要参数:
del_barcode_file:
basepath: 对应事件路径
savepath: 存储路径, 是函数 save_tracking_imgpairs() 的输入
saveimgs: Ture, False, 是否保存错误匹配的事件对
get_contrast_paths()
针对 eletedBarcode.txt 格式的 1:n 数据结果文件,返回三元时间元组getoutpath, inputpath, errorpath
test_rpath_return()
针对 returnGoods.txt 格式 1:n 数据文件不需要调用函数get_contrast_paths()
获得 1:n 情况下正确或匹配事件对(取出事件、放入事件、错误匹配事件)
匹配事件分析, 实现函数save_tracking_imgpairs()
one2one_contrast.py
共6个地址
(1) stdSamplePath: 用于生成比对标准特征集的原始图像地址
(2) stdBarcodePath: 比对标准特征集原始图像地址的pickle文件存储{barcode: [imgpath1, imgpath1, ...]}
(3) stdFeaturePath: 比对标准特征集特征存储地址
(4) eventFeatPath: 用于1:1比对的购物事件特征存储地址、对应子图存储地址
(5) subimgPath: 1:1比对购物事件轨迹、标准barcode所对应的 subimgs 存储地址
(6) resultPath: 1:1比对结果存储地址
(1), (2), (3): 保存标准特征集向量,只需运行一次
(4): 保存测试的事件字典,只需运行一次
test_one2one()
(1) 生成标准特征集, 只需运行一次
genfeatures()
(2) 生成事件字典, 只需运行一次
gen_eventdict(eventDatePath, saveimg)
参数:
eventDatePath: 事件集列表,其中每个元素均为事件的集合;
saveimg: 是否保存事件子图
(3) 1:1性能评估
(4) 计算PR曲线
creat_shopping_event(eventPath, subimgPath=False)
构造一次购物事件字典, 共12个关键字。
save_event_subimg(event, savepath)
保存一次购物事件的子图
one2one_eval()
compute_precise_recall()
int8_to_ft16()
ft16_to_uint8()
one2one_onsite.py one2one_onsite.py
现场试验输出数据的 1:1 性能评估; 现场试验输出数据的 1:1 性能评估;
适用于202410前数据保存版本的需调用 OneToOneCompare.txt 适用于202410前数据保存版本的需调用 OneToOneCompare.txt
@ -161,11 +270,13 @@
std_sample_path图像样本的存储地址 std_sample_path图像样本的存储地址
std_barcode_path对 std_sample_path 中文件列表进行遍历,形成{barcode: 图像样本地址}形式字典并进行存储 std_barcode_path对 std_sample_path 中文件列表进行遍历,形成{barcode: 图像样本地址}形式字典并进行存储
std_feature_path调用 inference_image(), 对每一个barcode生成字典并进行存储 std_feature_path调用 inference_image(), 对每一个barcode生成字典并进行存储
genfeats.py genfeats.py
genfeatures(imgpath, bcdpath, featpath) genfeatures(imgpath, bcdpath, featpath)
功能:生成标准特征向量 功能:生成标准特征向量的字典, 并保存为: barcode.pickle
keys: barcode, imgpaths, feats_ft32, feats_ft16, feats_uint8
参数: 参数:
(1) imgpath图像样本的存储地址 (1) imgpath图像样本的存储地址
(2) bcdpath对 imgpath 中文件列表进行遍历,形成{barcode: 图像样本地址}形式字典并进行存储 (2) bcdpath对 imgpath 中文件列表进行遍历,形成{barcode: 图像样本地址}形式字典并进行存储