diff --git a/__pycache__/event_time_specify.cpython-39.pyc b/__pycache__/event_time_specify.cpython-39.pyc new file mode 100644 index 0000000..f810d64 Binary files /dev/null and b/__pycache__/event_time_specify.cpython-39.pyc differ diff --git a/__pycache__/imgs_inference.cpython-39.pyc b/__pycache__/imgs_inference.cpython-39.pyc new file mode 100644 index 0000000..b9f30b5 Binary files /dev/null and b/__pycache__/imgs_inference.cpython-39.pyc differ diff --git a/__pycache__/move_detect.cpython-39.pyc b/__pycache__/move_detect.cpython-39.pyc new file mode 100644 index 0000000..2565888 Binary files /dev/null and b/__pycache__/move_detect.cpython-39.pyc differ diff --git a/__pycache__/track_reid.cpython-39.pyc b/__pycache__/track_reid.cpython-39.pyc index 2532102..c565e61 100644 Binary files a/__pycache__/track_reid.cpython-39.pyc and b/__pycache__/track_reid.cpython-39.pyc differ diff --git a/contrast/__pycache__/__init__.cpython-39.pyc b/contrast/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..5c77270 Binary files /dev/null and b/contrast/__pycache__/__init__.cpython-39.pyc differ diff --git a/contrast/__pycache__/one2n_contrast.cpython-39.pyc b/contrast/__pycache__/one2n_contrast.cpython-39.pyc index 6b44536..7e47383 100644 Binary files a/contrast/__pycache__/one2n_contrast.cpython-39.pyc and b/contrast/__pycache__/one2n_contrast.cpython-39.pyc differ diff --git a/contrast/genfeats.py b/contrast/genfeats.py new file mode 100644 index 0000000..651c9da --- /dev/null +++ b/contrast/genfeats.py @@ -0,0 +1,209 @@ +# -*- coding: utf-8 -*- +""" +Created on Sun Nov 3 12:05:19 2024 + +@author: ym +""" +import os +import time +import torch +import pickle +import numpy as np +from config import config as conf +from model import resnet18 as resnet18 +from feat_inference import inference_image + + +IMG_FORMAT = ['.bmp', '.jpg', '.jpeg', '.png'] + +'''======= 0. 配置特征提取模型地址 =======''' +model_path = conf.test_model +model_path = r"D:\exhibition\ckpt\zhanting.pth" + +##============ load resnet mdoel +model = resnet18().to(conf.device) +# model = nn.DataParallel(model).to(conf.device) +model.load_state_dict(torch.load(model_path, map_location=conf.device)) +model.eval() +print('load model {} '.format(conf.testbackbone)) + +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 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 genfeatures(imgpath, bcdpath, featpath): + + get_std_barcodeDict(imgpath, bcdpath) + stdfeat_infer(bcdpath, featpath, bcdSet=None) + + print(f"Features have generated, saved in: {featpath}") + + + + + + +def main(): + imgpath = r"\\192.168.1.28\share\展厅barcode数据\整理\zhantingBase" + bcdpath = r"D:\exhibition\dataset\bcdpath" + featpath = r"D:\exhibition\dataset\feats" + + genfeatures(imgpath, bcdpath, featpath) + + + +if __name__ == '__main__': + main() diff --git a/contrast/one2n_contrast.py b/contrast/one2n_contrast.py index 8b7a6db..0c3ae93 100644 --- a/contrast/one2n_contrast.py +++ b/contrast/one2n_contrast.py @@ -16,60 +16,13 @@ import shutil import numpy as np import matplotlib.pyplot as plt import cv2 - +from pathlib import Path import sys sys.path.append(r"D:\DetectTracking") from tracking.utils.plotting import Annotator, colors -from tracking.utils.read_data import extract_data, read_deletedBarcode_file, read_tracking_output +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 - - - -def showHist(err, correct): - err = np.array(err) - correct = np.array(correct) - - fig, axs = plt.subplots(2, 1) - axs[0].hist(err, bins=50, edgecolor='black') - axs[0].set_xlim([0, 1]) - axs[0].set_title('err') - - axs[1].hist(correct, bins=50, edgecolor='black') - axs[1].set_xlim([0, 1]) - axs[1].set_title('correct') - # plt.show() - - return plt - -def show_recall_prec(recall, prec, ths): - # x = np.linspace(start=-0, stop=1, num=11, endpoint=True).tolist() - fig = plt.figure(figsize=(10, 6)) - plt.plot(ths, recall, color='red', label='recall') - plt.plot(ths, prec, color='blue', label='PrecisePos') - plt.legend() - plt.xlabel(f'threshold') - # plt.ylabel('Similarity') - plt.grid(True, linestyle='--', alpha=0.5) - # plt.savefig('accuracy_recall_grid.png') - # plt.show() - # plt.close() - - return plt - - -def compute_recall_precision(err_similarity, correct_similarity): - ths = np.linspace(0, 1, 51) - recall, prec = [], [] - for th in ths: - TP = len([num for num in correct_similarity if num >= th]) - FP = len([num for num in err_similarity if num >= th]) - if (TP+FP) == 0: - prec.append(1) - recall.append(0) - else: - prec.append(TP / (TP + FP)) - recall.append(TP / (len(err_similarity) + len(correct_similarity))) - return recall, prec, ths +from contrast.utils.tools import showHist, show_recall_prec, compute_recall_precision # ============================================================================= @@ -129,7 +82,7 @@ def read_tracking_imgs(imgspath): return imgs_0, imgs_1 - + # ============================================================================= # def draw_tracking_boxes(imgs, tracks): # '''tracks: [x1, y1, x2, y2, track_id, score, cls, frame_index, box_index] @@ -287,27 +240,9 @@ def save_tracking_imgpairs(pair, basepath, savepath): cv2.imwrite(imgpath, img) -# def performance_evaluate(all_list, isshow=False): - -# corrpairs, correct_barcode_list, correct_similarity, errpairs, err_barcode_list, err_similarity = [], [], [], [], [], [] -# for s_list in all_list: -# seqdir = s_list['SeqDir'].strip() -# delete = s_list['Deleted'].strip() -# barcodes = [s.strip() for s in s_list['barcode']] -# similarity = [float(s.strip()) for s in s_list['similarity']] - -# if delete in barcodes[:1]: -# corrpairs.append((seqdir, delete)) -# correct_barcode_list.append(delete) -# correct_similarity.append(similarity[0]) -# else: -# errpairs.append((seqdir, delete, barcodes[0])) -# err_barcode_list.append(delete) -# err_similarity.append(similarity[0]) -def performance_evaluate(all_list, isshow=False): - - corrpairs, correct_barcode_list, correct_similarity, errpairs, err_barcode_list, err_similarity = [], [], [], [], [], [] +def one2n_old(all_list): + corrpairs, errpairs, correct_similarity, err_similarity = [], [], [], [] for s_list in all_list: seqdir = s_list['SeqDir'].strip() delete = s_list['Deleted'].strip() @@ -332,70 +267,136 @@ def performance_evaluate(all_list, isshow=False): matched_barcode = barcodes[index] if matched_barcode == delete: corrpairs.append((seqdir, delete)) - correct_barcode_list.append(delete) correct_similarity.append(max(similarity)) else: errpairs.append((seqdir, delete, matched_barcode)) - err_barcode_list.append(delete) err_similarity.append(max(similarity)) - '''3. 计算比对性能 ''' - if isshow: - recall, prec, ths = compute_recall_precision(err_similarity, correct_similarity) - show_recall_prec(recall, prec, ths) - showHist(err_similarity, correct_similarity) - return errpairs, corrpairs, err_similarity, correct_similarity - + return corrpairs, errpairs, correct_similarity, err_similarity -def contrast_analysis(del_barcode_file, basepath, savepath, saveimgs=False): - ''' - del_barcode_file: 测试数据文件,利用该文件进行算法性能分析 + +def one2n_new(all_list): + corrpairs, correct_similarity, errpairs, err_similarity = [], [], [], [] + for s_list in all_list: + seqdir = s_list['SeqDir'].strip() + delete = s_list['Deleted'].strip() + barcodes = [s.strip() for s in s_list['barcode']] + events = [s.strip() for s in s_list['event']] + types = [s.strip() for s in s_list['type']] + + ## =================== 读入相似度值 + similarity_comp, similarity_front = [], [] + for simil in s_list['similarity']: + ss = [float(s.strip()) for s in simil.split(',')] + + similarity_comp.append(ss[0]) + if len(ss)==3: + similarity_front.append(ss[2]) + + if len(similarity_front): + similarity = [s for s in similarity_front] + else: + similarity = [s for s in similarity_comp] + + + index = similarity.index(max(similarity)) + matched_barcode = barcodes[index] + if matched_barcode == delete: + corrpairs.append((seqdir, events[index])) + correct_similarity.append(max(similarity)) + else: + idx = [i for i, name in enumerate(events) if name.split('_')[-1] == delete] + idxmax, simimax = -1, -1 + # idxmax, simimax = k, similarity[k] for k in idx if similarity[k] > simimax + for k in idx: + if similarity[k] > simimax: + idxmax = k + simimax = similarity[k] + + errpairs.append((seqdir, events[idxmax], events[index])) + err_similarity.append(max(similarity)) + + return errpairs, corrpairs, err_similarity, correct_similarity + + +# def contrast_analysis(del_barcode_file, basepath, savepath, saveimgs=False): +def get_relative_paths(del_barcode_file, basepath, savepath, saveimgs=False): ''' + del_barcode_file: + deletedBarcode.txt 格式的 1:n 数据结果文件 + returnGoods.txt格式数据文件不需要调用该函数,one2n_old() 函数返回的 errpairs + 中元素为三元元组(取出,放入, 错误匹配) + ''' + relative_paths = [] '''1. 读取 deletedBarcode 文件 ''' all_list = read_deletedBarcode_file(del_barcode_file) - + '''2. 算法性能评估,并输出 (取出,删除, 错误匹配) 对 ''' - errpairs, corrpairs, _, _ = performance_evaluate(all_list) - - '''3. 获取 (取出,删除, 错误匹配) 对应路径,保存相应轨迹图像''' - relative_paths = [] + errpairs, corrpairs, _, _ = one2n_old(all_list) + + '''3. 构造事件组合(取出,放入并删除, 错误匹配) 对应路径 ''' for errpair in errpairs: GetoutPath, InputPath, ErrorPath = get_contrast_paths(errpair, basepath) relative_paths.append((GetoutPath, InputPath, ErrorPath)) - + + '''3. 获取 (取出,放入并删除, 错误匹配) 对应路径,保存相应轨迹图像''' if saveimgs: save_tracking_imgpairs(errpair, basepath, savepath) return relative_paths -def contrast_loop(fpath): +def one2n_test(): + fpath = r'\\192.168.1.28\share\测试_202406\deletedBarcode\other' + fpath = r'\\192.168.1.28\share\测试_202406\1030\images' + savepath = r'\\192.168.1.28\share\测试_202406\deletedBarcode\illustration' - # savepath = r'D:\contrast\dataset\1_to_n\illustration' if not os.path.exists(savepath): os.mkdir(savepath) - - if os.path.isfile(fpath): - fpath, filename = os.path.split(fpath) + if os.path.isdir(fpath): + filepaths = [os.path.join(fpath, f) for f in os.listdir(fpath) + if f.find('.txt')>0 + and (f.find('deletedBarcode')>=0 or f.find('returnGoods')>=0)] + elif os.path.isfile(fpath): + filepaths = [fpath] + else: + return + + + FileFormat = {} + BarLists, blists = {}, [] - for filename in os.listdir(fpath): - file = os.path.splitext(filename)[0][15:] - - filepath = os.path.join(fpath, filename) - blist = read_deletedBarcode_file(filepath) + for pth in filepaths: + file = str(Path(pth).stem) + if file.find('deletedBarcode')>=0: + FileFormat[file] = 'deletedBarcode' + blist = read_deletedBarcode_file(pth) + elif file.find('returnGoods')>=0: + FileFormat[file] = 'returnGoods' + blist = read_returnGoods_file(pth) + else: + return + BarLists.update({file: blist}) blists.extend(blist) BarLists.update({file: blist}) BarLists.update({"Total": blists}) - for file, blist in BarLists.items(): - errpairs, corrpairs, err_similarity, correct_similarity = performance_evaluate(blist) + + for file, blist in BarLists.items(): + if FileFormat[file] == 'deletedBarcode': + _, _, err_similarity, correct_similarity = one2n_old(blist) + elif FileFormat[file] == 'returnGoods': + _, _, err_similarity, correct_similarity = one2n_new(blist) + else: + _, _, err_similarity, correct_similarity = one2n_old(blist) + recall, prec, ths = compute_recall_precision(err_similarity, correct_similarity) @@ -411,25 +412,33 @@ def contrast_loop(fpath): # plt.close() -def main(): - fpath = r'\\192.168.1.28\share\测试_202406\deletedBarcode\other' - contrast_loop(fpath) -def main1(): + +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' - savepath = r'D:\contrast\dataset\result' + # 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 = contrast_analysis(del_barcode_file, basepath, savepath) + relative_path = get_relative_paths(del_barcode_file, basepath, savepath, saveimgs) except Exception as e: print(f'Error Type: {e}') - + if __name__ == '__main__': - main() - # main1() + one2n_test() + + # test_getreltpath() + diff --git a/contrast/one2one_contrast.py b/contrast/one2one_contrast.py index 8730da9..27f4b20 100644 --- a/contrast/one2one_contrast.py +++ b/contrast/one2one_contrast.py @@ -239,71 +239,71 @@ def creat_shopping_event(eventPath, subimgPath=False): 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 - ''' +# 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' +# # 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) +# '''读取数据集中 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] +# 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 +# '''遍历数据集,针对每一个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) +# 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) +# if ext not in IMG_FORMAT: +# continue +# imgpaths.append(imgpath) - stdBarcodeDict[barcode].extend(imgpaths) - break +# 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) +# 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}") +# 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 +# # k += 1 +# # if k == 10: +# # break +# print(f"Len of errbarcodes: {len(errbarcodes)}") +# return def save_event_subimg(event, savepath): ''' @@ -355,92 +355,92 @@ def batch_inference(imgpaths, batch): 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 中 +# 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 = {} +# # 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值''' +# '''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") +# 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 +# if os.path.isfile(pkpath): continue +# if bcdSet is not None and bcd not in bcdSet: +# continue - filepath = os.path.join(imgPath, filename) +# filepath = os.path.join(imgPath, filename) - stdbDict = {} - stdbDict_ft16 = {} - stdbDict_uint8 = {} +# stdbDict = {} +# stdbDict_ft16 = {} +# stdbDict_uint8 = {} - t1 = time.time() +# 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] +# 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] +# # 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) +# # 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}") +# 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 +# '''================ 保存单个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) +# with open(pkpath, 'wb') as f: +# pickle.dump(stdbDict, f) - stdBarcodeDict[barcode] = feature - stdBarcodeDict_ft16[barcode] = feature_ft16 +# 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 +# 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) +# ##================== 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) +# ##================== 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 +# return def contrast_performance_evaluate(resultPath): @@ -789,30 +789,28 @@ def main(): 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" +# 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) +# 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) +# # 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") +# # for v in bpDict.values(): +# # fileList.append(len(v)) +# # print("done") if __name__ == '__main__': - # main() - - - main_std() + main() + # main_std() diff --git a/contrast/one2one_onsite.py b/contrast/one2one_onsite.py index af5f6f5..a11769e 100644 --- a/contrast/one2one_onsite.py +++ b/contrast/one2one_onsite.py @@ -1,9 +1,8 @@ # -*- coding: utf-8 -*- """ Created on Wed Sep 11 11:57:30 2024 - -永辉现场 1:1 比对测试 - + 永辉现场试验输出数据的 1:1 性能评估 + 适用于202410前数据保存版本的,需调用 OneToOneCompare.txt @author: ym """ import os @@ -65,14 +64,14 @@ def plot_pr_curve(matrix): axs[1].set_title(f'Cross Barcode, Num: {TPFN_mean}') # plt.savefig(f'./result/{file}_hist.png') # svg, png, pdf - Recall_Pos = [] + Recall_Neg = [] Thresh = np.linspace(-0.2, 1, 100) for th in Thresh: TN = np.sum(simimax < th) - Recall_Pos.append(TN/TPFN_max) + Recall_Neg.append(TN/TPFN_max) fig, ax = plt.subplots() - ax.plot(Thresh, Recall_Pos, 'b', label='Recall_Pos: TP/TPFN') + ax.plot(Thresh, Recall_Neg, 'b', label='Recall_Pos: TP/TPFN') ax.set_xlim([0, 1]) ax.set_ylim([0, 1]) ax.grid(True) @@ -96,9 +95,7 @@ def main(): simiList = [] for fp in filepaths: slist = read_one2one_data(fp) - simiList.extend(slist) - plot_pr_curve(simiList) diff --git a/contrast/utils/__pycache__/__init__.cpython-39.pyc b/contrast/utils/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..c7e60b0 Binary files /dev/null and b/contrast/utils/__pycache__/__init__.cpython-39.pyc differ diff --git a/contrast/utils/__pycache__/tools.cpython-39.pyc b/contrast/utils/__pycache__/tools.cpython-39.pyc new file mode 100644 index 0000000..fcf268f Binary files /dev/null and b/contrast/utils/__pycache__/tools.cpython-39.pyc differ diff --git a/contrast/utils/tools.py b/contrast/utils/tools.py new file mode 100644 index 0000000..7abdb5e --- /dev/null +++ b/contrast/utils/tools.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +""" +Created on Thu Oct 31 15:17:01 2024 + +@author: ym +""" +import numpy as np +import matplotlib.pyplot as plt + + + +def showHist(err, correct): + err = np.array(err) + correct = np.array(correct) + + fig, axs = plt.subplots(2, 1) + axs[0].hist(err, bins=50, edgecolor='black') + axs[0].set_xlim([0, 1]) + axs[0].set_title('err') + + axs[1].hist(correct, bins=50, edgecolor='black') + axs[1].set_xlim([0, 1]) + axs[1].set_title('correct') + # plt.show() + + return plt + +def show_recall_prec(recall, prec, ths): + # x = np.linspace(start=-0, stop=1, num=11, endpoint=True).tolist() + fig = plt.figure(figsize=(10, 6)) + plt.plot(ths, recall, color='red', label='recall') + plt.plot(ths, prec, color='blue', label='PrecisePos') + plt.legend() + plt.xlabel(f'threshold') + # plt.ylabel('Similarity') + plt.grid(True, linestyle='--', alpha=0.5) + # plt.savefig('accuracy_recall_grid.png') + # plt.show() + # plt.close() + + return plt + + +def compute_recall_precision(err_similarity, correct_similarity): + ths = np.linspace(0, 1, 51) + recall, prec = [], [] + for th in ths: + TP = len([num for num in correct_similarity if num >= th]) + FP = len([num for num in err_similarity if num >= th]) + if (TP+FP) == 0: + prec.append(1) + recall.append(0) + else: + prec.append(TP / (TP + FP)) + recall.append(TP / (len(err_similarity) + len(correct_similarity))) + return recall, prec, ths \ No newline at end of file diff --git a/event_time_specify.py b/event_time_specify.py new file mode 100644 index 0000000..8a421da --- /dev/null +++ b/event_time_specify.py @@ -0,0 +1,301 @@ +# -*- coding: utf-8 -*- +""" +Created on Thu Oct 10 11:01:39 2024 + +@author: ym +""" +import os +import numpy as np +# from matplotlib.pylab import mpl +# mpl.use('Qt5Agg') +import matplotlib.pyplot as plt +from move_detect import MoveDetect + + +import sys +sys.path.append(r"D:\DetectTracking") + +# from tracking.utils.read_data import extract_data, read_deletedBarcode_file, read_tracking_output, read_weight_timeConsuming + + +from tracking.utils.read_data import read_weight_timeConsuming + +def str_to_float_arr(s): + # 移除字符串末尾的逗号(如果存在) + if s.endswith(','): + s = s[:-1] + + # 使用split()方法分割字符串,然后将每个元素转化为float + float_array = [float(x) for x in s.split(",")] + return float_array + +def find_samebox_in_array(arr, target): + + for i, st in enumerate(arr): + if st[:4] == target[:4]: + return i + return -1 + +def array2frame(bboxes): + frameID = np.sort(np.unique(bboxes[:, 7].astype(int))) + # frame_ids = bboxes[:, frameID].astype(int) + fboxes, ttamps = [], [] + for fid in frameID: + idx = np.where(bboxes[:, 7] == fid)[0] + box = bboxes[idx, :] + + fboxes.append(box) + ttamps.append(int(box[0, 9])) + + frameTstamp = np.concatenate((frameID[:,None], np.array(ttamps)[:,None]), axis=1) + + return fboxes, frameTstamp + + +def extract_data_1(datapath): + ''' + 要求每一帧(包括最后一帧)输出数据后有一空行作为分割行,该分割行为标志行 + ''' + + trackerboxes = np.empty((0, 10), dtype=np.float64) + trackerfeats = np.empty((0, 256), dtype=np.float64) + + boxes, feats, tboxes, tfeats = [], [], [], [] + timestamp = -1 + + newframe = False + with open(datapath, 'r', encoding='utf-8') as lines: + for line in lines: + if line.find("CameraId")>=0: + newframe = True + timestamp, frameId = [int(ln.split(":")[1]) for ln in line.split(",")[1:]] + # boxes, feats, tboxes, tfeats = [], [], [], [] + + + if line.find("box:") >= 0 and line.find("output_box:") < 0: + line = line.strip() + box = line[line.find("box:") + 4:].strip() + # if len(box)==6: + boxes.append(str_to_float_arr(box)) + + if line.find("feat:") >= 0: + line = line.strip() + feat = line[line.find("feat:") + 5:].strip() + # if len(feat)==256: + feats.append(str_to_float_arr(feat)) + + if line.find("output_box:") >= 0: + line = line.strip() + # 确保 boxes 和 feats 一一对应,并可以保证 tboxes 和 tfeats 一一对应 + if len(boxes)==0 or len(boxes)!=len(feats): + continue + + box = str_to_float_arr(line[line.find("output_box:") + 11:].strip()) + + box.append(timestamp) + index = find_samebox_in_array(boxes, box) + if index >= 0: + tboxes.append(box) # 去掉'output_box:'并去除可能的空白字符 + + # feat_f = str_to_float_arr(input_feats[index]) + feat_f = feats[index] + norm_f = np.linalg.norm(feat_f) + feat_f = feat_f / norm_f + tfeats.append(feat_f) + + '''标志行(空行)判断''' + condt = line.find("timestamp")<0 and line.find("box:")<0 and line.find("feat:")<0 + if condt and newframe: + if len(tboxes) and len(tfeats): + trackerboxes = np.concatenate((trackerboxes, np.array(tboxes))) + trackerfeats = np.concatenate((trackerfeats, np.array(tfeats))) + + timestamp = -1 + boxes, feats, tboxes, tfeats = [], [], [], [] + newframe = False + + return trackerboxes, trackerfeats + + +def devide_motion_state(tboxes, width): + '''frameTstamp: 用于标记当前相机视野内用购物车运动状态变化''' + + periods = [] + if len(tboxes) < width: + return periods + + fboxes, frameTstamp = array2frame(tboxes) + + fnum = len(frameTstamp) + if fnum < width: return periods + + state = np.zeros((fnum, 2), dtype=np.int64) + frameState = np.concatenate((frameTstamp, state), axis = 1).astype(np.int64) + + mtrackFid = {} + '''frameState 标记由图像判断的购物车状态:0: 静止,1: 运动''' + for idx in range(width, fnum+1): + lboxes = np.concatenate(fboxes[idx-width:idx], axis = 0) + + md = MoveDetect(lboxes) + md.classify() + + # if idx==60: + # print('a') + + ## track.during 二元素组, 表征在该时间片段内,轨迹 track 的起止时间,数值用 boxes[:, 7] + for track in md.track_motion: + if track.cls == 0: continue + + + + f1, f2 = track.during + + + + idx1 = set(np.where(frameState[:,0] >= f1)[0]) + idx2 = set(np.where(frameState[:,0] <= f2)[0]) + idx3 = list(idx1.intersection(idx2)) + + if track.tid not in mtrackFid: + mtrackFid[track.tid] = set(idx3) + else: + mtrackFid[track.tid] = mtrackFid[track.tid].union(set(idx3)) + + frameState[idx-1, 3] = 1 + frameState[idx3, 2] = 1 + + '''状态变化输出''' + + for tid, fid in mtrackFid.items(): + fstate = np.zeros((fnum, 1), dtype=np.int64) + fstate[list(fid), 0] = tid + + frameState = np.concatenate((frameState, fstate), axis = 1).astype(np.int64) + + + + + + + return frameState + + +def state_measure(periods, weights, spath=None): + '''两种状态:static、motion, + (t0, t1) + t0: static ----> motion + t1: motion ----> static + ''' + + PrevState = 'static' + CuurState = 'static' + + camtype_0, frstate_0 = periods[0] + camtype_1, frstate_1 = periods[1] + + '''计算总时间区间: tmin, tmax, during''' + tmin_w, tmax_w = np.min(weights[:, 0]), np.max(weights[:, 0]) + tmin_0, tmax_0 = np.min(frstate_0[:, 1]), np.max(frstate_0[:, 1]) + tmin_1, tmax_1 = np.min(frstate_1[:, 1]), np.max(frstate_1[:, 1]) + + tmin = min([tmin_w, tmin_0, tmin_1]) + tmax = max([tmax_w, tmax_0, tmax_1]) + + # for ctype, tboxes, _ in tracker_boxes: + # t_min, t_max = np.min(tboxes[:, 9]), np.max(tboxes[:, 9]) + # if t_mintmax: + # tmax = t_max + # during = tmax - tmin + + + + fig, (ax1, ax2, ax3) = plt.subplots(3, 1) + + ax1.plot(weights[:, 0] - tmin, weights[:, 1], 'bo-', linewidth=1, markersize=4) + # ax1.set_xlim([0, during]) + ax1.set_title('Weight (g)') + + ax2.plot(frstate_0[:, 1] - tmin, frstate_0[:, 2], 'rx-', linewidth=1, markersize=8) + ax2.plot(frstate_0[:, 1] - tmin, frstate_0[:, 3], 'bo-', linewidth=1, markersize=4) + # ax2.set_xlim([0, during]) + ax2.set_title(f'Camera: {int(camtype_0)}') + + ax3.plot(frstate_1[:, 1] - tmin, frstate_1[:, 2], 'rx-', linewidth=1, markersize=8) + ax3.plot(frstate_1[:, 1] - tmin, frstate_1[:, 3], 'bo-', linewidth=1, markersize=4) + ax3.set_title(f'Camera: {int(camtype_1)}') + + if spath: + plt.savefig(spath) + plt.show() + +def read_yolo_weight_data(eventdir): + filepaths = [] + for filename in os.listdir(eventdir): + file, ext = os.path.splitext(filename) + if ext =='.data': + filepath = os.path.join(eventdir, filename) + filepaths.append(filepath) + + if len(filepaths) != 5: + return + + tracker_boxes = [] + WeightDict, SensorDict, ProcessTimeDict = {}, {}, {} + for filepath in filepaths: + filename = os.path.basename(filepath) + + if filename.find('_track.data')>0: + CamerType = filename.split('_')[0] + trackerboxes, trackerfeats = extract_data_1(filepath) + tracker_boxes.append((CamerType, trackerboxes, trackerfeats)) + + if filename.find('process.data')==0: + WeightDict, SensorDict, ProcessTimeDict = read_weight_timeConsuming(filepath) + + '''====================重力信号处理====================''' + weights = [(float(t), w) for t, w in WeightDict.items()] + weights = np.array(weights) + + return tracker_boxes, weights + + +def main(): + eventdir = r"\\192.168.1.28\share\测试_202406\0819\images\20240817-192549-6940120c-634c-481b-97a6-65042729f86b_null" + + tracker_boxes, weights = read_yolo_weight_data(eventdir) + + '''====================图像运动分析====================''' + win_width = 12 + periods = [] + for ctype, tboxes, _ in tracker_boxes: + period = devide_motion_state(tboxes, win_width) + + periods.append((ctype, period)) + print('done!') + + '''===============重力、图像信息融合===================''' + state_measure(periods, weights) + + +if __name__ == "__main__": + main() + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/imgs_inference.py b/imgs_inference.py new file mode 100644 index 0000000..ed314f3 --- /dev/null +++ b/imgs_inference.py @@ -0,0 +1,435 @@ +# -*- coding: utf-8 -*- +""" +Created on Fri Oct 18 13:09:42 2024 + +@author: ym +""" +import argparse +import os +import sys +import torch +from pathlib import Path +import numpy as np + +# from matplotlib.pylab import mpl +# mpl.use('Qt5Agg') +import matplotlib.pyplot as plt + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import DetectMultiBackend + +from utils.augmentations import letterbox + + +from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2, + increment_path, non_max_suppression, print_args, scale_boxes, strip_optimizer, xyxy2xywh) +from utils.torch_utils import select_device, smart_inference_mode + +'''集成跟踪模块,输出跟踪结果文件 .npy''' +# from ultralytics.engine.results import Boxes # Results +# from ultralytics.utils import IterableSimpleNamespace, yaml_load +from tracking.utils.plotting import Annotator, colors +from tracking.utils import Boxes, IterableSimpleNamespace, yaml_load, boxes_add_fid +from tracking.trackers import BOTSORT, BYTETracker +from tracking.utils.showtrack import drawtracks +from hands.hand_inference import hand_pose + +from tracking.trackers.reid.reid_interface import ReIDInterface +from tracking.trackers.reid.config import config as ReIDConfig + +ReIDEncoder = ReIDInterface(ReIDConfig) +IMG_FORMATS = 'bmp', 'dng', 'jpeg', 'jpg', 'mpo', 'png', 'tif', 'tiff', 'webp', 'pfm' # include image suffixes +VID_FORMATS = 'asf', 'avi', 'gif', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'ts', 'wmv' # include video suffixes + +class LoadImages: + # YOLOv5 image/video dataloader, i.e. `python detect.py --source image.jpg/vid.mp4` + def __init__(self, files, img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): + images = [x for x in files if x.split('.')[-1].lower() in IMG_FORMATS] + videos = [x for x in files if x.split('.')[-1].lower() in VID_FORMATS] + ni, nv = len(images), len(videos) + + + + self.img_size = img_size + self.stride = stride + self.files = images + videos + self.nf = ni + nv # number of files + self.video_flag = [False] * ni + [True] * nv + self.mode = 'image' + self.auto = auto + self.transforms = transforms # optional + self.vid_stride = vid_stride # video frame-rate stride + if any(videos): + self._new_video(videos[0]) # new video + else: + self.cap = None + + + def __iter__(self): + self.count = 0 + return self + + def __next__(self): + if self.count == self.nf: + raise StopIteration + path = self.files[self.count] + + if self.video_flag[self.count]: + # Read video + self.mode = 'video' + for _ in range(self.vid_stride): + self.cap.grab() + ret_val, im0 = self.cap.retrieve() + while not ret_val: + self.count += 1 + self.cap.release() + if self.count == self.nf: # last video + raise StopIteration + path = self.files[self.count] + self._new_video(path) + ret_val, im0 = self.cap.read() + + self.frame += 1 + # im0 = self._cv2_rotate(im0) # for use if cv2 autorotation is False + s = f'video {self.count + 1}/{self.nf} ({self.frame}/{self.frames}) {path}: ' + + else: + # Read image + self.count += 1 + im0 = cv2.imread(path) # BGR + + # image rorate + (h, w) = im0.shape[:2] + center = (w // 2, h // 2) + angle = 90 + scale = 1.0 + M = cv2.getRotationMatrix2D(center, angle, scale) + im0 = cv2.warpAffine(im0, M, (h, w)) + + assert im0 is not None, f'Image Not Found {path}' + s = f'image {self.count}/{self.nf} {path}: ' + + if self.transforms: + im = self.transforms(im0) # transforms + else: + im = letterbox(im0, self.img_size, stride=self.stride, auto=self.auto)[0] # padded resize + im = im.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB + im = np.ascontiguousarray(im) # contiguous + + return path, im, im0, self.cap, s + + def _new_video(self, path): + # Create a new video capture object + self.frame = 0 + self.cap = cv2.VideoCapture(path) + self.frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT) / self.vid_stride) + self.orientation = int(self.cap.get(cv2.CAP_PROP_ORIENTATION_META)) # rotation degrees + # self.cap.set(cv2.CAP_PROP_ORIENTATION_AUTO, 0) # disable https://github.com/ultralytics/yolov5/issues/8493 + + def _cv2_rotate(self, im): + # Rotate a cv2 video manually + if self.orientation == 0: + return cv2.rotate(im, cv2.ROTATE_90_CLOCKWISE) + elif self.orientation == 180: + return cv2.rotate(im, cv2.ROTATE_90_COUNTERCLOCKWISE) + elif self.orientation == 90: + return cv2.rotate(im, cv2.ROTATE_180) + return im + + def __len__(self): + return self.nf # number of files + +def inference_image(image, detections): + H, W, _ = np.shape(image) + imgs = [] + batch_patches = [] + patches = [] + for d in range(np.size(detections, 0)): + tlbr = detections[d, :4].astype(np.int_) + tlbr[0] = max(0, tlbr[0]) + tlbr[1] = max(0, tlbr[1]) + tlbr[2] = min(W - 1, tlbr[2]) + tlbr[3] = min(H - 1, tlbr[3]) + img1 = image[tlbr[1]:tlbr[3], tlbr[0]:tlbr[2], :] + + img = img1[:, :, ::-1].copy() # the model expects RGB inputs + patch = ReIDEncoder.transform(img) + + imgs.append(img1) + # patch = patch.to(device=self.device).half() + if str(ReIDEncoder.device) != "cpu": + patch = patch.to(device=ReIDEncoder.device).half() + else: + patch = patch.to(device=ReIDEncoder.device) + + patches.append(patch) + if (d + 1) % ReIDEncoder.batch_size == 0: + patches = torch.stack(patches, dim=0) + batch_patches.append(patches) + patches = [] + + if len(patches): + patches = torch.stack(patches, dim=0) + batch_patches.append(patches) + + features = np.zeros((0, ReIDEncoder.embedding_size)) + for patches in batch_patches: + pred = ReIDEncoder.model(patches) + pred[torch.isinf(pred)] = 1.0 + feat = pred.cpu().data.numpy() + features = np.vstack((features, feat)) + + return imgs, features + + +def init_trackers(tracker_yaml = None, bs=1): + """ + Initialize trackers for object tracking during prediction. + """ + # tracker_yaml = r"./tracking/trackers/cfg/botsort.yaml" + + TRACKER_MAP = {'bytetrack': BYTETracker, 'botsort': BOTSORT} + + cfg = IterableSimpleNamespace(**yaml_load(tracker_yaml)) + trackers = [] + for _ in range(bs): + tracker = TRACKER_MAP[cfg.tracker_type](args=cfg, frame_rate=30) + trackers.append(tracker) + + return trackers + + +def run( + weights=ROOT / 'yolov5s.pt', # model path or triton URL + source=ROOT / 'data/images', # file/dir/URL/glob/screen/0(webcam) + + project=ROOT / 'runs/detect', # save results to project/name + name='exp', # save results to project/name + + tracker_yaml = "./tracking/trackers/cfg/botsort.yaml", + imgsz=(640, 640), # inference size (height, width) + conf_thres=0.25, # confidence threshold + iou_thres=0.45, # NMS IOU threshold + max_det=1000, # maximum detections per image + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + view_img=False, # show results + save_txt=False, # save results to *.txt + save_csv=False, # save results in CSV format + save_conf=False, # save confidences in --save-txt labels + save_crop=False, # save cropped prediction boxes + save_img = True, + nosave=False, # do not save images/videos + classes=None, # filter by class: --class 0, or --class 0 2 3 + agnostic_nms=False, # class-agnostic NMS + augment=False, # augmented inference + visualize=False, # visualize features + update=False, # update all models + exist_ok=False, # existing project/name ok, do not increment + line_thickness=3, # bounding box thickness (pixels) + hide_labels=False, # hide labels + hide_conf=False, # hide confidencesL + half=False, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + vid_stride=1, # video frame-rate stride + data=ROOT / 'data/coco128.yaml', # dataset.yaml path + ): + assert isinstance(source,list), "source must be a list" + + fulldir, imgname = os.path.split(source[0]) + imgbase, ext = os.path.splitext(imgname) + + + # 事件名、相机类型 + EventName = fulldir.split('\\')[-2] + "_" + str(Path(fulldir).stem) + CamerType = imgbase.split('_')[1] + + save_dir = Path(project) / Path(EventName) + if save_dir.exists(): + print(Path(fulldir).stem) + + # save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + # save_dir.mkdir(parents=True, exist_ok=True) # make dir + else: + save_dir.mkdir(parents=True, exist_ok=True) + + save_path_video = os.path.join(str(save_dir), f"{EventName}_{CamerType}") + # Load model + device = select_device(device) + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, names, pt = model.stride, model.names, model.pt + imgsz = check_img_size(imgsz, s=stride) # check image size + + bs = 1 # batch_size + + dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride) + vid_path, vid_writer = [None] * bs, [None] * bs + + # Run inference + model.warmup(imgsz=(1 if pt or model.triton else bs, 3, *imgsz)) # warmup + seen, dt = 0, (Profile(), Profile(), Profile()) + + tracker = init_trackers(tracker_yaml, bs)[0] + track_boxes = np.empty((0, 10), dtype = np.float32) + k = 0 + for path, im, im0s, vid_cap, s in dataset: + # k +=1 + # if k==60: + # break + + timeStamp = Path(path).stem.split('_')[2] + + with dt[0]: + im = torch.from_numpy(im).to(model.device) + im = im.half() if model.fp16 else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + if len(im.shape) == 3: + im = im[None] # expand for batch dim + + # Inference + with dt[1]: + visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False + pred = model(im, augment=augment, visualize=visualize) + + # NMS + with dt[2]: + pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det) + + # Process predictions + for i, det in enumerate(pred): # per image + seen += 1 + im0 = im0s.copy() + + s += '%gx%g ' % im.shape[2:] # print string + annotator = Annotator(im0s, line_width=line_thickness, example=str(names)) + + nd = len(det) + if nd: + # Rescale boxes from img_size to im0 size + det[:, :4] = scale_boxes(im.shape[2:], det[:, :4], im0.shape).round() + + '''tracks: [x1, y1, x2, y2, track_id, score, cls, frame_index, box_index, timestamp] + 0 1 2 3 4 5 6 7 8 + 这里,frame_index 也可以用视频的 帧ID 代替, box_index 保持不变 + ''' + + det_tracking = Boxes(det, im0.shape).cpu().numpy() + tracks = tracker.update(det_tracking, im0) + if len(tracks) == 0: + continue + tracks[:, 7] = dataset.count + + + stamp = np.ones((len(tracks), 1)) * int(timeStamp) + tracks = np.concatenate((tracks, stamp), axis=1) + + '''================== 1. 存储 dets/subimgs/features Dict =============''' + # imgs, features = inference_image(im0, tracks) + track_boxes = np.concatenate([track_boxes, tracks], axis=0) + + for *xyxy, id, conf, cls, fid, bid, t in reversed(tracks): + name = ('' if id==-1 else f'id:{int(id)} ') + names[int(cls)] + label = None if hide_labels else (name if hide_conf else f'{name} {conf:.2f}') + + if id >=0 and cls==0: + color = colors(int(cls), True) + elif id >=0 and cls!=0: + color = colors(int(id), True) + else: + color = colors(19, True) # 19为调色板的最后一个元素 + + annotator.box_label(xyxy, label, color=color) + + # Save results (image and video with tracking) + im0 = annotator.result() + p = Path(path) # to Path + if save_img: + imgpath = str(save_dir/p.stem) + f"_{dataset.count}.png" + cv2.imwrite(Path(imgpath), im0) + if vid_path[i] != save_path_video: # new video + vid_path[i] = save_path_video + if isinstance(vid_writer[i], cv2.VideoWriter): + vid_writer[i].release() # release previous video writer + fps, w, h = 30, im0.shape[1], im0.shape[0] + vpath = str(Path(save_path_video).with_suffix('.mp4')) + vid_writer[i] = cv2.VideoWriter(vpath, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) + + vid_writer[i].write(im0) + + LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1E3:.1f}ms") + + for v in vid_writer: + v.release() + + if track_boxes.size == 0: + return CamerType, [] + + save_path_np = os.path.join(str(fulldir), f"{EventName}_{CamerType}") + np.save(save_path_np, track_boxes) + + # Print results + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t) + if save_txt or save_img: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + if update: + strip_optimizer(weights[0]) # update model (to fix SourceChangeWarning) + + + return CamerType, track_boxes + + +def parse_opt(): + modelpath = ROOT / 'ckpts/best_cls10_0906.pt' # 'ckpts/best_15000_0908.pt', 'ckpts/yolov5s.pt', 'ckpts/best_20000_cls30.pt, best_yolov5m_250000' + + parser = argparse.ArgumentParser() + parser.add_argument('--weights', nargs='+', type=str, default=modelpath, help='model path or triton URL') # 'yolov5s.pt', best_15000_0908.pt + parser.add_argument('--source', type=str, default='', help='file/dir/URL/glob/screen/0(webcam)') # images, videos + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='(optional) dataset.yaml path') + parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') + parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold') + parser.add_argument('--max-det', type=int, default=1000, help='maximum detections per image') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--view-img', action='store_true', help='show results') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-csv', action='store_true', help='save results in CSV format') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes') + parser.add_argument('--nosave', action='store_true', help='do not save images/videos') + parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --classes 0, or --classes 0 2 3') + parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--visualize', action='store_true', help='visualize features') + parser.add_argument('--update', action='store_true', help='update all models') + parser.add_argument('--project', default=ROOT / 'runs/detect', help='save results to project/name') + parser.add_argument('--name', default='exp', help='save results to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)') + parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels') + parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + parser.add_argument('--vid-stride', type=int, default=1, help='video frame-rate stride') + opt = parser.parse_args() + opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand + print_args(vars(opt)) + return opt + +def run_yolo(eventdir, savedir): + + opt = parse_opt() + optdict = vars(opt) + optdict["project"] = savedir + optdict["source"] = eventdir + run(**vars(opt)) + + + + + diff --git a/move_detect.py b/move_detect.py new file mode 100644 index 0000000..4701fdb --- /dev/null +++ b/move_detect.py @@ -0,0 +1,243 @@ +# -*- coding: utf-8 -*- +""" +Created on Mon Oct 14 10:01:24 2024 + +@author: ym +""" +import numpy as np +import cv2 +from scipy.spatial.distance import cdist + + +class TrackFrag: + + def __init__(self, boxes, imgshape=(1280, 1024)): + self.boxes = boxes + self.cls = int(boxes[0, 6]) + self.tid = int(boxes[0, 4]) + self.imgshape = imgshape + + + '''轨迹的持续时间,以帧ID表征, (或考虑用时间戳)''' + self.during = (np.min(boxes[:, 7]), np.max(boxes[:, 7])) + + self.groups = [set(np.unique(boxes[:, 7].astype(int)))] + + # '''5个关键点(中心点、左上点、右上点、左下点、右下点 )坐标''' + self.isCornpoint = self.is_cornpoint(10) + self.compute_cornpoints() + + + def is_cornpoint(self, edge=10): + + isleft = min(self.boxes[:, 0]) < edge + istop = min(self.boxes[:, 1]) < edge + isright = max(self.boxes[:, 2]) > self.imgshape[0] - edge + isbottom = max(self.boxes[:, 3]) > self.imgshape[0] - edge + + isCornpoint = isbottom or istop or isleft or isright + return isCornpoint + + + + def compute_cornpoints(self): + ''' + cornpoints 共10项,分别是个点的坐标值(x, y) + (center, top_left, top_right, bottom_left, bottom_right) + ''' + boxes = self.boxes + cornpoints = np.zeros((len(boxes), 10)) + + cornpoints[:,0] = (boxes[:, 0] + boxes[:, 2]) / 2 + cornpoints[:,1] = (boxes[:, 1] + boxes[:, 3]) / 2 + cornpoints[:,2], cornpoints[:,3] = boxes[:, 0], boxes[:, 1] + cornpoints[:,4], cornpoints[:,5] = boxes[:, 2], boxes[:, 1] + cornpoints[:,6], cornpoints[:,7] = boxes[:, 0], boxes[:, 3] + cornpoints[:,8], cornpoints[:,9] = boxes[:, 2], boxes[:, 3] + + trajdist = [] + for k in range(5): + X = cornpoints[:, 2*k:2*(k+1)] + trajdist.append(np.max(cdist(X, X))) + + idx = trajdist.index(min(trajdist)) + + self.trajdist_min = trajdist[idx] + self.cornpoints = cornpoints + + + + + + def update_groups(self, THRESH=18): + ''' + 对 self.groups 重新赋值 + ''' + + boxes = self.boxes + nbox = len(boxes) + + X = np.zeros((len(boxes), 2)) + X[:,0] = (boxes[:, 0] + boxes[:, 2]) / 2 + X[:,1] = (boxes[:, 1] + boxes[:, 3]) / 2 + + dist2 = cdist(X, X) + # label = np.zeros(nbox, dtype=np.int) + + marked, groups = set(), [] + for k in range(nbox): + if k in marked: + continue + group = set() + + dt = dist2[k, :] + idx = np.where(dt < THRESH)[0] + + if len(idx) == 1: + groups.append({k}) + marked.add(k) + continue + '''初始近邻样本点集合, 并移除当前点''' + seeds = set(idx) + seeds.remove(k) + + group.add(k) + marked.add(k) + while len(seeds) !=0: + pt = seeds.pop() + dt = dist2[pt, :] + + seed = set(np.where(dt < THRESH)[0]) + seed.remove(pt) + + seed.difference_update(marked) + seeds.update(seed) + + group.add(pt) + marked.add(pt) + + groups.append(group) + + self.groups = groups + + + def jump_boxes(self): + gpboxes = [] + for group in self.groups: + box = self.boxes[list(group), :] + gpboxes.append(box) + + return gpboxes + + + + def is_moving(self): + if len(self.groups)>=3: + return True + + return False + + + def is_static(self): + box1 = self.boxes[0, :4] + box2 = self.boxes[-1, :4] + + ''' 第1帧、最后一帧 boxes 四个角点间的距离 ''' + ptd = box2 - box1 + ptd1 = np.linalg.norm((ptd[0], ptd[1])) + ptd2 = np.linalg.norm((ptd[2], ptd[1])) + ptd3 = np.linalg.norm((ptd[0], ptd[3])) + ptd4 = np.linalg.norm((ptd[2], ptd[3])) + condt1 = ptd1<50 and ptd2<50 and ptd3<50 and ptd4<50 + + if not self.isCornpoint: + self.trajdist_min < 120 + + + # condt2 = self.TrajFeat[3] < 50 + # condt = condt1 or condt2 + return condt1 + + +class MoveDetect: + def __init__(self, bboxes, imgshape=(1280, 1024)): + self.bboxes = bboxes + self.shape = imgshape + + self.temp = np.zeros(imgshape, np.uint8) + + + self.trackIDs = np.unique(bboxes[:, 4].astype(int)) + # self.frameID = np.unique(bboxes[:, 7].astype(int)) + # self.fnum = len(self.frameID) + + self.lboxes = self.array2list() + + self.tracks = [TrackFrag(b) for b in self.lboxes] + + def classify(self): + + tracks = self.tracks + + '''减去静止轨迹''' + tracks_static = [t for t in tracks if t.is_static()] + tracks = self.sub_tracks(tracks, tracks_static) + + '''更新轨迹点聚类''' + for track in tracks: + track.update_groups(18) + + + self.track_motion = [t for t in tracks if len(t.groups)>=3] + + + def draw(self): + pass + + + + def array2list(self): + ''' + 将 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] + ''' + track_ids = self.bboxes[:, 4].astype(int) + lboxes = [] + for t_id in self.trackIDs: + # print(f"The ID is: {t_id}") + idx = np.where(track_ids == t_id)[0] + box = self.bboxes[idx, :] + + lboxes.append(box) + + return lboxes + + @staticmethod + def sub_tracks(tlista, tlistb): + track_ids_b = {t.tid for t in tlistb} + return [t for t in tlista if t.tid not in track_ids_b] + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pipeline.py b/pipeline.py index 1d1c0df..e013fd6 100644 --- a/pipeline.py +++ b/pipeline.py @@ -7,24 +7,20 @@ Created on Sun Sep 29 08:59:21 2024 import os import cv2 import pickle +import numpy as np from pathlib import Path from track_reid import parse_opt, yolo_resnet_tracker from tracking.dotrack.dotracks_back import doBackTracks from tracking.dotrack.dotracks_front import doFrontTracks +from tracking.utils.drawtracks import plot_frameID_y2, draw_all_trajectories +from utils.getsource import get_image_pairs, get_video_pairs -IMGFORMATS = '.bmp', '.jpeg', '.jpg', 'png', 'tif', 'tiff', 'webp', 'pfm' -VIDFORMATS = '.avi', '.gif', '.m4v', '.mkv', '.mov', '.mp4', '.ts', '.wmv' - -std_feature_path = r"\\192.168.1.28\share\测试_202406\contrast\std_features_2192_ft32vsft16" - - -opt = parse_opt() -optdict = vars(opt) +std_feature_path = r"\\192.168.1.28\share\测试_202406\contrast\std_features_2192_ft32vsft16" def get_interbcd_inputenents(): bcdpath = r"\\192.168.1.28\share\测试_202406\contrast\std_barcodes_2192" @@ -44,108 +40,118 @@ def get_interbcd_inputenents(): return input_enents + +def pipeline(eventpath, stdfeat_path=None, SourceType = "image"): + ''' + inputs: + eventpath: 事件文件夹 + stdfeat_path: 标准特征文件地址 + outputs: - - -def get_video_pairs(vpath): - vdieopath = [] - for filename in os.listdir(vpath): - file, ext = os.path.splitext(filename) - if ext in VIDFORMATS: - vdieopath.append(os.path.join(vpath, filename)) - return vdieopath - -def pipeline(eventpath, stdfeat_path): + ''' + SourceType = "image" # image + # eventpath = r"\\192.168.1.28\share\测试_202406\0918\images1\20240918-110822-1bc3902e-5a8e-4e23-8eca-fb3f02738551_6938314601726" savepath = r"D:\contrast\detect" + opt = parse_opt() + optdict = vars(opt) optdict["project"] = savepath eventname = os.path.basename(eventpath) - barcode = eventname.split('_')[-1] + # barcode = eventname.split('_')[-1] + + if SourceType == "video": + vpaths = get_video_pairs(eventpath) + elif SourceType == "image": + vpaths = get_image_pairs(eventpath) + + - vpaths = get_video_pairs(eventpath) event_tracks = [] for vpath in vpaths: '''事件结果文件夹''' save_dir_event = Path(savepath) / Path(eventname) - save_dir_img = save_dir_event / Path(str(Path(vpath).stem)) - if not save_dir_img.exists(): - save_dir_img.mkdir(parents=True, exist_ok=True) + if isinstance(vpath, list): + save_dir_video = save_dir_event / Path("images") + else: + save_dir_video = save_dir_event / Path(str(Path(vpath).stem)) + + + if not save_dir_video.exists(): + save_dir_video.mkdir(parents=True, exist_ok=True) '''Yolo + Resnet + Tracker''' optdict["source"] = vpath - optdict["save_dir"] = save_dir_img - optdict["nosave"] = False + optdict["save_dir"] = save_dir_video + optdict["is_save_img"] = True + optdict["is_save_video"] = True tracksdict = yolo_resnet_tracker(**optdict) bboxes = tracksdict['TrackBoxes'] - bname = os.path.basename(vpath) + bname = os.path.basename(vpath[0]) if isinstance(vpath, list) else os.path.basename(vpath) if bname.split('_')[0] == "0" or bname.find('back')>=0: - vts = doFrontTracks(bboxes, tracksdict) + vts = doBackTracks(bboxes, tracksdict) vts.classify() event_tracks.append(("back", vts)) if bname.split('_')[0] == "1" or bname.find('front')>=0: - vts = doBackTracks(bboxes, tracksdict) + vts = doFrontTracks(bboxes, tracksdict) vts.classify() event_tracks.append(("front", vts)) + '''轨迹显示模块''' + illus = [None, None] for CamerType, vts in event_tracks: - if CamerType == 'back': - pass if CamerType == 'front': - pass + edgeline = cv2.imread("./tracking/shopcart/cart_tempt/board_ftmp_line.png") + img_tracking = draw_all_trajectories(vts, edgeline, save_dir_event, CamerType, draw5p=True) + illus[0] = img_tracking + + + plt = plot_frameID_y2(vts) + plt.savefig(os.path.join(save_dir_event, "front_y2.png")) + + if CamerType == 'back': + edgeline = cv2.imread("./tracking/shopcart/cart_tempt/edgeline.png") + img_tracking = draw_all_trajectories(vts, edgeline, save_dir_event, CamerType, draw5p=True) + illus[1] = img_tracking + + illus = [im for im in illus if im is not None] + 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) + + trajpath = os.path.join(save_dir_event, "traj.png") + cv2.imwrite(trajpath, img_cat) + + '''前后摄轨迹选择''' - - if stdfeat_path is not None: with open(stdfeat_path, 'rb') as f: featDict = pickle.load(f) - - - - - - - - - - - - - - -def main(): +def main_loop(): bcdpath = r"\\192.168.1.28\share\测试_202406\contrast\std_barcodes_2192" eventpath = r"\\192.168.1.28\share\测试_202406\0918\images1" - - + SourceType = "image" # video, image + barcodes = [] input_enents = [] output_events = [] - - - # input_enents = get_interbcd_inputenents() - # k = 0 - # for event in input_enents: - # pipeline(event) - - # k += 1 - # if k ==1: - # break - - + + '''1. 获得barcode标准特征集列表''' for featname in os.listdir(bcdpath): barcode, ext = os.path.splitext(featname) @@ -153,31 +159,30 @@ def main(): continue barcodes.append(barcode) - - - - - - - + '''2. 构造(放入事件,标准特征)对''' for filename in os.listdir(eventpath): + '''barcode为时间文件夹的最后一个字段''' bcd = filename.split('_')[-1] event_path = os.path.join(eventpath, filename) stdfeat_path = None if bcd in barcodes: - stdfeat_path = os.path.join(bcdpath, f"{bcd}.pickle") - + stdfeat_path = os.path.join(bcdpath, f"{bcd}.pickle") input_enents.append((event_path, stdfeat_path)) - - - + for eventpath, stdfeat_path in input_enents: - pipeline(eventpath, stdfeat_path) + pipeline(eventpath, stdfeat_path, SourceType) - +def main(): + eventpath = r"D:\datasets\ym\exhibition\175836" + SourceType = 'image' + stdfeat_path = None + + pipeline(eventpath, stdfeat_path, SourceType) + + @@ -187,4 +192,10 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() + + + + + + \ No newline at end of file diff --git a/pipeline_extract_subimg.py b/pipeline_extract_subimg.py index 1e3a960..8a3cb9c 100644 --- a/pipeline_extract_subimg.py +++ b/pipeline_extract_subimg.py @@ -2,6 +2,8 @@ """ Created on Sun Sep 29 08:59:21 2024 + 针对现场采集的视频,利用算法pipeline提取运动轨迹内的subimg,代替人工图像筛选、标注 + @author: ym """ import os diff --git a/time_devide.py b/time_devide.py new file mode 100644 index 0000000..e843a7e --- /dev/null +++ b/time_devide.py @@ -0,0 +1,451 @@ +# -*- coding: utf-8 -*- +""" +Created on Wed Oct 16 17:37:07 2024 + +@author: ym +""" + +# import csv +import os +# import platform +# import sys +from pathlib import Path +import glob +import numpy as np +import copy + + +import matplotlib.pyplot as plt +from imgs_inference import run_yolo + +from event_time_specify import devide_motion_state#, state_measure +from tracking.utils.read_data import read_seneor + + + +# IMG_FORMATS = 'bmp', 'dng', 'jpeg', 'jpg', 'mpo', 'png', 'tif', 'tiff', 'webp', 'pfm' # include image suffixes +# VID_FORMATS = 'asf', 'avi', 'gif', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'ts', 'wmv' # include video suffixes + + +def filesort(p): + ''' + 需将图像文件名标准化 + ''' + + + files = [] + files.extend(sorted(glob.glob(os.path.join(p, '*.jpg')))) + # images = [x for x in files if x.split('.')[-1].lower() in IMG_FORMATS] + + tamps_0, tamps_1 = [], [] + files_0, files_1 = [], [] + for file in files: + basename = os.path.basename(file) + # if basename.find('frameId')<0: continue + + + f, ext = os.path.splitext(basename) + _, camer, tamp = f.split('_') + + if camer == '0': + tamps_0.append(int(tamp)) + files_0.append(file) + + if camer == '1': + tamps_1.append(int(tamp)) + files_1.append(file) + + idx0 = sorted(range(len(tamps_0)), key=lambda k: tamps_0[k]) + files0 = [files_0[i] for i in idx0] + + idx1 = sorted(range(len(tamps_1)), key=lambda k: tamps_1[k]) + files1 = [files_1[i] for i in idx1] + + + return (files0, files1) + + + + + +def rename(filePath, tmin): + """ + 重命名函数fun1 + 输入:文件夹路径 + 功能:对文件夹中的全部文件进行随机命名 + """ + suffix = '.png' # 设置后缀,筛选特定文件以更改名称 + for file in os.listdir(filePath): + if file.endswith(suffix): + name = file.split('.')[0] + + tamp = int(name.split('_')[2])-tmin + + suffix = file.split('.')[1] + + newname = name +f'_{int(tamp)}.'+suffix + + os.rename(os.path.join(filePath, file), os.path.join(filePath, newname)) + + +def rerename(filePath=None): + """ + 重命名函数fun1 + 输入:文件夹路径 + 功能:对文件夹中的全部文件进行随机命名 + """ + + suffix = '.png' # 设置后缀,筛选特定文件以更改名称 + for file in os.listdir(filePath): + if file.endswith(suffix): + name = file.split('.')[0] + names = name.split('_') + if len(names)>=6: + newname = "_".join(names[0:5])+'.png' + os.rename(os.path.join(filePath, file), os.path.join(filePath, newname)) + + +def state_measure(periods, weights, spath=None): + ''' + 数据类型 + 后摄: 0, 前摄: 1, CV综合: 2, 重力: 9 + frstate_0/1: + 帧ID 时间戳 单摄状态1 单摄状态2 活动轨迹标记 + 0 1 2 3 4:end + + + + time_stream = np.concatenate((tstream, weights)) + time_stream: + 序列索引号 数据类型 时间戳 单摄状态1/重力值 单摄状态2/重力(t0, t1) CV状态/重力(t0', t1') 综合数据类型 综合状态 + 0 1 2 3 4 5 6 7 + + 单摄状态1:基于运动轨迹的起止点确定的运动区间 + 单摄状态2: 基于滑动窗口的起止点确定的运动区间 + 重力(t0, t1): 重力波动的精确时间区间,基于重力波动的起止点,而不是仅依赖重力稳定时间 + 重力(t0', t1'): 根据加退购对重力波动窗口进行扩展,扩展应该涵盖购物事件的发生过程 + 方案: + 前后摄状态进行或运算 + CV与重力状态进行与运算 + ''' + + # BackType = 0 # 后摄数据类型 + # FrontType = 1 # 前摄数据类型 + CameraType = 2 # CV数据综合类型 + WeightType = 9 # 重力数据类型 + WeightStableThresh = 7.5 # 单位:g,重力稳定状态下的最大波动范围 + WeightWinWidth = 10 # 单位:重力数据点数,该值和采样间隔关联,重力稳定时间设定为500ms = WeightWinWidth * 采样间隔 + CameraTimeInterval = 100 # 单位:ms,前后摄状态进行或运算时的时间间隔阈值 + InputFrontNum = 10 # 重力增加(放入)向前延拓的重力数据点数 + InputBackNum = 0 # 重力增加(放入)向后延拓的重力数据点数 + OutputFrontNum = 2 # 重力减少(取出)向前延拓的重力数据点数 + OutputBackNum = 10 # 重力减少(取出)向前延拓的重力数据点数 + CompTimeInterval = 150 # 单位:ms,CV状态和重力状态进行与运算时的时间间隔阈值 + + + '''==================== 1.1 Weight 数据综合并排序 =======================''' + nw = len(weights) + widx = np.array([k for k in range(0, nw)])[:, None] + wtype = WeightType * np.ones((nw, 1)) + wstate = np.zeros((nw, 4)) + weights = np.concatenate((widx, wtype, weights, wstate), axis=1).astype(np.int64) + weights[:, 6] = WeightType + + weights = weights[np.argsort(weights[:, 2]), :] + + '''=================== 1.2 基确Weight的状态切割 =========================''' + w_max = np.max(weights[:, 3]) + # i0=0 + for i2 in range(0, nw): + i1 = max(i2 - WeightWinWidth, 0) + wvalue = weights[i1:i2+1, 3] + wi2 = weights[i2, 3] + wmin = np.min(wvalue) + wmax = np.max(wvalue) + + + '''对重力波动区间进行标记,并标记最新一次重力稳定值的索引和相应重力值''' + if wmax - wmin > WeightStableThresh: + weights[i2, 4] = w_max + elif i2==0: + i0=0 + wi0 = weights[i0, 3] + elif i2>0 and weights[i2-1, 4]==0: + i0 = copy.deepcopy(i2) + wi0 = weights[i0, 3] + + + if i2>0 and weights[i2-1, 4]!=0 and weights[i2, 4]==0: + # 当前稳定状态下的重力值和前一次重力稳定值的差值,确定放入还是取出 + if wi2-wi0 > WeightStableThresh: + i00 = max(i0 - InputFrontNum, 0) + i22 = min(i2 + InputBackNum, nw) + elif wi2-wi0 < -1*WeightStableThresh: + i00 = max(i0 - OutputFrontNum, 0) + i22 = min(i2 + OutputBackNum, nw) + else: + i00 = max(i0 - max(InputFrontNum, OutputFrontNum), 0) + i22 = min(i2 + max(InputBackNum, OutputBackNum), nw) + + weights[i00:i22, 5] = w_max + 100 + + + '''===================== 2.1 CV 数据综合并排序 ==========================''' + BackType, frstate_0 = periods[0] + FrontType, frstate_1 = periods[1] + + + n0, n1 = len(frstate_0), len(frstate_1) + idx0 = np.array([i for i in range(0, n0)], dtype=np.int64)[:, None] + idx1 = np.array([i for i in range(0, n1)], dtype=np.int64)[:, None] + ctype0 = BackType * np.ones((n0, 1), dtype=np.int64) + ctype1 = FrontType * np.ones((n1, 1), dtype=np.int64) + tstamp0 = frstate_0[:,1][:, None] + tstamp1 = frstate_1[:,1][:, None] + state0 = frstate_0[:,2][:, None] + state00 = frstate_0[:,3][:, None] + + state1 = frstate_1[:,2][:, None] + state11 = frstate_1[:,3][:, None] + + + + + '''序列索引号, 相机类型,时间戳, 单摄状态1、单摄状态2、CV综合状态、综合数据类型、综合状态 + 0 1 2 3 4 5 6 7 + ''' + tstream0 = np.concatenate((idx0, ctype0, tstamp0, state0, state00), axis=1) + tstream1 = np.concatenate((idx1, ctype1, tstamp1, state1, state11), axis=1) + tstream = np.concatenate((tstream0, tstream1), axis=0) + tstream = np.concatenate((tstream, np.zeros((len(tstream), 3), dtype=np.int64)), axis=1) + tstream[:, 6] = CameraType + tstream = tstream[np.argsort(tstream[:, 2]), :] + + '''=============== 2.2 基于前后摄运动轨迹起止点确定CV综合状态 ============''' + for i in range(0, len(tstream)): + idx, ctype, stamp, state = tstream[i, :4] + if i==0: + tstream[i, 5] = state + if i>0: + j = i-1 + idx0, ctype0, stamp0, state0 = tstream[j, :4] + while stamp-stamp0 < CameraTimeInterval and ctype == ctype0 and j>0: + j -= 1 + idx0, ctype0, stamp0, state0 = tstream[j, :4] + + '''两摄像头状态的或运算. 由于前后摄图像不同时,如何构造或运算,关键在于选择不同摄像头的对齐点 + i时刻摄像头(ctype)状态state,另一摄像头(ctype0 != ctype)距 i 最近最近时刻 j 的状态state0 + ''' + if ctype != ctype0 and state0==1: + tstream[i, 5] = state0 + else: + tstream[i, 5] = state + + + '''================ 3.1 CV、Wweight 数据综合并排序 ======================''' + time_stream = np.concatenate((tstream, weights), axis=0, dtype=np.int64) + time_stream = time_stream[np.argsort(time_stream[:, 2]), :] + tmin = np.min(time_stream[:, 2]) + time_stream[:, 2] = time_stream[:, 2] - tmin + + '''============== 3.2 基于 CV 和 Weight 确定 Cart 的综合状态 ============''' + for i in range(0, len(time_stream)): + idx, _, stamp, value, _, state, ctype = time_stream[i, :7] + state = min(state, 1) + + if i==0: + time_stream[i, 7] = state + + if i>0: + j = i-1 + idx0, _, stamp0, value0, _, state0, ctype0 = time_stream[j, :7] + while stamp-stamp0 < CompTimeInterval and ctype == ctype0 and j>0: + j -= 1 + idx0, _, stamp0, value0, _, state0, ctype0 = time_stream[j, :7] + + '''CV与Weight的与运算. 由于CV与Weight不同时,如何构造与运算,关键在于选择不同数据源的对齐点 + i时数据类型(ctype)状态state,另一数据类型(ctype0 != ctype)距 i 最近最近时刻 j 的状态state0 + ''' + if ctype != ctype0 and state !=0 and state0 !=0: + time_stream[i, 7] = 1 + + MotionSlice = [] + + motion_slice = [] + + t0 = time_stream[0, 7] + for i in range(1, len(time_stream)): + f0 = time_stream[i-1, 7] + f1 = time_stream[i, 7] + if f0==0 and f1==1: + t0 = time_stream[i, 2] + elif f0==1 and f1==0: + t1 = time_stream[i, 2] + if t1-t0>100: #ms + MotionSlice.append((t0+tmin, t1+tmin)) + motion_slice.append((t0, t1)) + else: + print(f"T0: {t0}, T1: {t1}") + + + '''========================== 4 结果显示 ================================''' + frstate_0[:, 1] = frstate_0[:, 1]-tmin + frstate_1[:, 1] = frstate_1[:, 1]-tmin + tstream[:, 2] = tstream[:, 2]-tmin + + fig, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(5, 1) + during = np.max(time_stream[:, 2]) + + ax1.plot(weights[:, 2]-tmin, weights[:, 3], 'bo-', linewidth=1, markersize=4) + ax1.plot(weights[:, 2]-tmin, weights[:, 4], 'mx-', linewidth=1, markersize=4) + ax1.plot(weights[:, 2]-tmin, weights[:, 5], 'gx-', linewidth=1, markersize=4) + ax1.set_xlim([0, during]) + ax1.set_title('Weight (gram)') + + ax2.plot(frstate_0[:, 1], frstate_0[:, 3], 'rx-', linewidth=1, markersize=8) + ax2.plot(frstate_0[:, 1], frstate_0[:, 2], 'bo-', linewidth=1, markersize=4) + ax2.set_xlim([0, during]) + ax2.set_title('Back Camera') + + ax3.plot(frstate_1[:, 1], frstate_1[:, 3], 'rx-', linewidth=1, markersize=8) + ax3.plot(frstate_1[:, 1], frstate_1[:, 2], 'bo-', linewidth=1, markersize=4) + ax3.set_xlim([0, during]) + ax3.set_title('Front Camera') + + ax4.plot(tstream[:, 2], tstream[:, 5], 'bx-', linewidth=1, markersize=4) + ax4.set_xlim([0, during]) + ax4.set_title('CV State') + + ax5.plot(time_stream[:, 2], time_stream[:, 7], 'gx-', linewidth=1, markersize=4) + ax5.set_xlim([0, during]) + ax5.set_title('Cart State') + + plt.show() + if spath: + plt.savefig(spath) + + return tmin, MotionSlice + +def splitevent(imgpath, MotionSlice): + suffix = '.png' + + imgfiles = [f for f in os.listdir(imgpath) if f.endswith(suffix)] + timestamp = np.array([int(f.split('_')[2]) for f in imgfiles]) + + indexes = [] + k = 0 + for t0, t1 in MotionSlice: + idx0 = set(np.where(timestamp >= t0)[0]) + idx1 = set(np.where(timestamp <= t1)[0]) + idx2 = list(idx0.intersection(idx1)) + files = [imgfiles[i] for i in idx2] + + for filename in files: + file, ext = os.path.splitext(filename) + newname = file + f'_{k}.png' + os.rename(os.path.join(imgpath, filename), os.path.join(imgpath, newname)) + k += 1 + + print("Done!") + + + +def runyolo(): + eventdirs = r"\\192.168.1.28\share\realtime\eventdata" + savedir = r"\\192.168.1.28\share\realtime\result" + + for edir in os.listdir(eventdirs): + source = os.path.join(eventdirs, edir) + files = filesort(source) + for flist in files: + run_yolo(flist, savedir) + +def run_tracking(trackboxes, MotionSlice): + pass + + + + + +def show_seri(): + datapath = r"\\192.168.1.28\share\realtime\eventdata\1728978106733" + savedir = r"\\192.168.1.28\share\realtime\result" + + + imgdir = datapath.split('\\')[-2] + "_" + datapath.split('\\')[-1] + imgpath = os.path.join(savedir, imgdir) + + eventname = Path(datapath).stem + + datafiles = sorted(glob.glob(os.path.join(datapath, '*.npy'))) + + periods, trackboxes = [], [] + win_width = 12 + for npypath in datafiles: + CameraType = Path(npypath).stem.split('_')[-1] + tkboxes = np.load(npypath) + + trackboxes.append((CameraType, tkboxes)) + + period = devide_motion_state(tkboxes, win_width) + periods.append((int(CameraType), period)) + + + + '''===============读取重力信号数据===================''' + seneorfile = os.path.join(datapath, 'sensor.txt') + WeightDict = read_seneor(seneorfile) + + weights = [(float(t), w) for t, w in WeightDict.items()] + weights = np.array(weights) + + + '''===============重力、图像信息融合===================''' + spath = os.path.join(savedir, f"{eventname}.png" ) + tmin, MotionSlice = state_measure(periods, weights, spath) + + + + + # 第一次运行时用于更改图像文件名 + # rerename(imgpath) + # rename(imgpath, tmin) + + + # splitevent(imgpath, MotionSlice) + + + + +def main(): + # runyolo() + + show_seri() + + +if __name__ == '__main__': + main() + + # imgpaths = r"\\192.168.1.28\share\realtime\result\eventdata_1728978106733" + # rerename(imgpaths) + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/track_reid.py b/track_reid.py index e927a77..3e687be 100644 --- a/track_reid.py +++ b/track_reid.py @@ -150,6 +150,8 @@ def yolo_resnet_tracker( save_crop=False, # save cropped prediction boxes nosave=False, # do not save images/videos + is_save_img = False, + is_save_video = True, classes=None, # filter by class: --class 0, or --class 0 2 3 @@ -166,9 +168,7 @@ def yolo_resnet_tracker( vid_stride=1, # video frame-rate stride data=ROOT / 'data/coco128.yaml', # dataset.yaml path ): - source = str(source) - save_img = not nosave and not source.endswith('.txt') # save inference images - + # source = str(source) # Load model device = select_device(device) model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) @@ -209,7 +209,6 @@ def yolo_resnet_tracker( for i, det in enumerate(pred): # per image im0 = im0s.copy() - save_path = str(save_dir / Path(path).name) # im.jpg s += '%gx%g ' % im.shape[2:] # print string annotator = Annotator(im0.copy(), line_width=line_thickness, example=str(names)) @@ -228,7 +227,14 @@ def yolo_resnet_tracker( tracks = tracker.update(det_tracking, im0) if len(tracks) == 0: continue - tracks[:, 7] = dataset.frame + + if dataset.mode == "video": + frameId = dataset.frame + else: + frameId = dataset.count + + tracks[:, 7] = frameId + '''================== 1. 存储 dets/subimgs/features Dict =============''' imgs, features = inference_image(im0, tracks) @@ -242,7 +248,7 @@ def yolo_resnet_tracker( imgdict.update({int(bid): imgs[ii]}) # [f"img_{int(bid)}"] = imgs[i] boxdict.update({int(bid): tracks[ii, :]}) # [f"box_{int(bid)}"] = tracks[i, :] featdict.update({int(bid): features[ii, :]}) # [f"feat_{int(bid)}"] = features[i, :] - TracksDict[f"frame_{int(dataset.frame)}"] = {"imgs":imgdict, "boxes":boxdict, "feats":featdict} + TracksDict[f"frame_{int(frameId)}"] = {"imgs":imgdict, "boxes":boxdict, "feats":featdict} track_boxes = np.concatenate([track_boxes, tracks], axis=0) @@ -256,20 +262,21 @@ def yolo_resnet_tracker( elif id >=0 and cls!=0: color = colors(int(id), True) else: - color = colors(19, True) # 19为调色板的最后一个元素 - + color = colors(19, True) # 19为调色板的最后一个元素 annotator.box_label(xyxy, label, color=color) - # Save results (image and video with tracking) + '''====== Save results (image and video) ======''' + save_path = str(save_dir / Path(path).name) # 带有后缀名 im0 = annotator.result() - save_path_img, ext = os.path.splitext(save_path) - if save_img: - # if dataset.mode == 'image': - # imgpath = save_path_img + f"_{dataset}.png" - # else: - # imgpath = save_path_img + f"_{dataset.frame}.png" - # cv2.imwrite(Path(imgpath), im0) - + if is_save_img: + save_path_img, ext = os.path.splitext(save_path) + if dataset.mode == 'image': + imgpath = save_path_img + ".png" + else: + imgpath = save_path_img + f"_{frameId}.png" + cv2.imwrite(Path(imgpath), im0) + + if dataset.mode == 'video' and is_save_video: if vid_path[i] != save_path: # new video vid_path[i] = save_path if isinstance(vid_writer[i], cv2.VideoWriter): @@ -396,8 +403,8 @@ def run( imgshow = im0s.copy() ## ============================= tracking 功能只处理视频,writed by WQG - if dataset.mode == 'image': - continue + # if dataset.mode == 'image': + # continue with dt[0]: im = torch.from_numpy(im).to(model.device) @@ -482,7 +489,14 @@ def run( tracks = tracker.update(det_tracking, im0) if len(tracks) == 0: continue - tracks[:, 7] = dataset.frame + + if dataset.mode == "video": + frameId = dataset.frame + else: + frameId = dataset.count + tracks[:, 7] = frameId + + tracks[:, 7] = frameId '''================== 1. 存储 dets/subimgs/features Dict =============''' imgs, features = inference_image(im0, tracks) @@ -496,7 +510,7 @@ def run( imgdict.update({int(bid): imgs[ii]}) # [f"img_{int(bid)}"] = imgs[i] boxdict.update({int(bid): tracks[ii, :]}) # [f"box_{int(bid)}"] = tracks[i, :] featdict.update({int(bid): features[ii, :]}) # [f"feat_{int(bid)}"] = features[i, :] - TracksDict[f"frame_{int(dataset.frame)}"] = {"imgs":imgdict, "boxes":boxdict, "feats":featdict} + TracksDict[f"frame_{int(frameId)}"] = {"imgs":imgdict, "boxes":boxdict, "feats":featdict} track_boxes = np.concatenate([track_boxes, tracks], axis=0) @@ -535,7 +549,7 @@ def run( if dataset.mode == 'image': imgpath = save_path_img + f"_{dataset}.png" else: - imgpath = save_path_img + f"_{dataset.frame}.png" + imgpath = save_path_img + f"_{frameId}.png" cv2.imwrite(Path(imgpath), im0) @@ -664,23 +678,37 @@ print('=======') def main(opt): check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) - - p = r"D:\datasets\ym\永辉测试数据_202404\20240402" - optdict = vars(opt) + + p = r"D:\datasets\ym" + p = r"D:\datasets\ym\exhibition\153112511_0_seek_105.mp4" + files = [] k = 0 if os.path.isdir(p): files.extend(sorted(glob.glob(os.path.join(p, '*.*')))) for file in files: + optdict["source"] = file run(**optdict) k += 1 - if k == 2: + if k == 1: break elif os.path.isfile(p): + optdict["source"] = p run(**vars(opt)) + +def main_imgdir(opt): + check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) + optdict = vars(opt) + + + optdict["project"] = r"\\192.168.1.28\share\realtime" + + optdict["source"] = r"\\192.168.1.28\share\realtime\addReturn\add\1728978052624" + run(**optdict) + def main_loop(opt): check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) @@ -725,8 +753,9 @@ def main_loop(opt): if __name__ == '__main__': opt = parse_opt() - # main(opt) - main_loop(opt) + main(opt) + # main_imgdir(opt) + # main_loop(opt) diff --git a/tracking/dotrack/__pycache__/dotracks.cpython-39.pyc b/tracking/dotrack/__pycache__/dotracks.cpython-39.pyc index 3cc2336..c349263 100644 Binary files a/tracking/dotrack/__pycache__/dotracks.cpython-39.pyc and b/tracking/dotrack/__pycache__/dotracks.cpython-39.pyc differ diff --git a/tracking/dotrack/__pycache__/dotracks_back.cpython-39.pyc b/tracking/dotrack/__pycache__/dotracks_back.cpython-39.pyc index c27214b..c72f837 100644 Binary files a/tracking/dotrack/__pycache__/dotracks_back.cpython-39.pyc and b/tracking/dotrack/__pycache__/dotracks_back.cpython-39.pyc differ diff --git a/tracking/dotrack/__pycache__/dotracks_front.cpython-39.pyc b/tracking/dotrack/__pycache__/dotracks_front.cpython-39.pyc index 73205fd..e7a572c 100644 Binary files a/tracking/dotrack/__pycache__/dotracks_front.cpython-39.pyc and b/tracking/dotrack/__pycache__/dotracks_front.cpython-39.pyc differ diff --git a/tracking/dotrack/__pycache__/track_back.cpython-39.pyc b/tracking/dotrack/__pycache__/track_back.cpython-39.pyc index 661bab5..4969ac8 100644 Binary files a/tracking/dotrack/__pycache__/track_back.cpython-39.pyc and b/tracking/dotrack/__pycache__/track_back.cpython-39.pyc differ diff --git a/tracking/dotrack/__pycache__/track_front.cpython-39.pyc b/tracking/dotrack/__pycache__/track_front.cpython-39.pyc index 08dd9f8..8baa7a1 100644 Binary files a/tracking/dotrack/__pycache__/track_front.cpython-39.pyc and b/tracking/dotrack/__pycache__/track_front.cpython-39.pyc differ diff --git a/tracking/dotrack/dotracks.py b/tracking/dotrack/dotracks.py index e1341e7..a3ec32b 100644 --- a/tracking/dotrack/dotracks.py +++ b/tracking/dotrack/dotracks.py @@ -59,21 +59,21 @@ class ShoppingCart: @property def incart(self): - img = cv2.imread(str(curpath/'cart_tempt/back_incart.png'), cv2.IMREAD_GRAYSCALE) + img = cv2.imread(str(parpath/'shopcart/cart_tempt/incart.png'), cv2.IMREAD_GRAYSCALE) ret, binary = cv2.threshold(img, 250, 255, cv2.THRESH_BINARY) return binary @property def outcart(self): - img = cv2.imread(str(curpath/'cart_tempt/back_outcart.png'), cv2.IMREAD_GRAYSCALE) + img = cv2.imread(str(parpath/'shopcart/cart_tempt/outcart.png'), cv2.IMREAD_GRAYSCALE) ret, binary = cv2.threshold(img, 250, 255, cv2.THRESH_BINARY) return binary @property def cartedge(self): - img = cv2.imread(str(curpath/'cart_tempt/back_cartedge.png'), cv2.IMREAD_GRAYSCALE) + img = cv2.imread(str(parpath/'shopcart/cart_tempt/cartedge.png'), cv2.IMREAD_GRAYSCALE) ret, binary = cv2.threshold(img, 250, 255, cv2.THRESH_BINARY) return binary @@ -520,8 +520,7 @@ class doTracks: mergedTracks.append(cur_list) return mergedTracks - - + @staticmethod def join_tracks(tlista, tlistb): """Combine two lists of stracks into a single one.""" @@ -541,6 +540,93 @@ class doTracks: def sub_tracks(tlista, tlistb): track_ids_b = {t.tid for t in tlistb} return [t for t in tlista if t.tid not in track_ids_b] + + + + def array2frame(self, bboxes): + frameID = np.sort(np.unique(bboxes[:, 7].astype(int))) + fboxes = [] + for fid in frameID: + idx = np.where(bboxes[:, 7] == fid)[0] + box = bboxes[idx, :] + fboxes.append(box) + return fboxes + + + def isintrude(self): + ''' + boxes: [x1, y1, x2, y2, track_id, score, cls, frame_index, box_index] + 0 1 2 3 4 5 6 7 8 + ''' + OverlapNum = 3 + bboxes = self.bboxes.astype(np.int64) + fboxes = self.array2frame(bboxes) + + incart = cv2.bitwise_not(self.incart) + sum_incart = np.zeros(incart.shape, dtype=np.int64) + for fid, boxes in enumerate(fboxes): + for i in range(len(boxes)): + x1, y1, x2, y2 = boxes[i, 0:4] + sum_incart[y1:y2, x1:x2] += 1 + + sumincart = np.zeros(sum_incart.shape, dtype=np.uint8) + idx255 = np.where(sum_incart >= OverlapNum) + sumincart[idx255] = 255 + + idxnzr = np.where(sum_incart!=0) + base = np.zeros(sum_incart.shape, dtype=np.uint8) + base[idxnzr] = 255 + + contours_sum, _ = cv2.findContours(sumincart, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + contours_base, _ = cv2.findContours(base, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + + have_existed, invasion = [], [] + for k, ct_temp in enumerate(contours_base): + tmp1 = np.zeros(sum_incart.shape, dtype=np.uint8) + cv2.drawContours(tmp1, [ct_temp], -1, 255, cv2.FILLED) + + # 确定轮廓的包含关系 + for ct_sum in contours_sum: + tmp2 = np.zeros(sum_incart.shape, dtype=np.uint8) + cv2.drawContours(tmp2, [ct_sum], -1, 255, cv2.FILLED) + tmp = cv2.bitwise_and(tmp1, tmp2) + if np.count_nonzero(tmp) == np.count_nonzero(tmp2): + have_existed.append(k) + + inIdx = [i for i in range(len(contours_base)) if i not in have_existed] + invasion = np.zeros(sum_incart.shape, dtype=np.uint8) + + for i in inIdx: + cv2.drawContours(invasion, [contours_base[i]], -1, 255, cv2.FILLED) + cv2.imwrite("./result/intrude/invasion.png", invasion) + + + Intrude = True if len(inIdx)>=1 else False + print(f"is intruded: {Intrude}") + + return Intrude + + + + + + + + + + + + + + + + + + + + + + diff --git a/tracking/dotrack/dotracks_back.py b/tracking/dotrack/dotracks_back.py index 19956d9..dd5d67b 100644 --- a/tracking/dotrack/dotracks_back.py +++ b/tracking/dotrack/dotracks_back.py @@ -5,8 +5,15 @@ Created on Mon Mar 4 18:36:31 2024 @author: ym """ import numpy as np +import cv2 from tracking.utils.mergetrack import track_equal_track from scipy.spatial.distance import cdist +from pathlib import Path +curpath = Path(__file__).resolve().parents[0] +curpath = Path(curpath) +parpath = curpath.parent + + from .dotracks import doTracks, ShoppingCart from .track_back import backTrack @@ -18,10 +25,26 @@ class doBackTracks(doTracks): self.tracks = [backTrack(b, f) for b, f in zip(self.lboxes, self.lfeats)] - # self.similar_dict = self.similarity() + # self.similar_dict = self.similarity() + # self.shopcart = ShoppingCart(bboxes) + + self.incart = self.getincart() + + + def getincart(self): + img1 = cv2.imread(str(parpath/'shopcart/cart_tempt/incart.png'), cv2.IMREAD_GRAYSCALE) + img2 = cv2.imread(str(parpath/'shopcart/cart_tempt/cartedge.png'), cv2.IMREAD_GRAYSCALE) + + + ret, binary1 = cv2.threshold(img1, 250, 255, cv2.THRESH_BINARY) + ret, binary2 = cv2.threshold(img2, 250, 255, cv2.THRESH_BINARY) + + binary = cv2.bitwise_or(binary1, binary2) + + + return binary - self.shopcart = ShoppingCart(bboxes) def classify(self): '''功能:对 tracks 中元素分类 ''' diff --git a/tracking/dotrack/dotracks_front.py b/tracking/dotrack/dotracks_front.py index 60101f5..a61e39a 100644 --- a/tracking/dotrack/dotracks_front.py +++ b/tracking/dotrack/dotracks_front.py @@ -4,7 +4,13 @@ Created on Mon Mar 4 18:38:20 2024 @author: ym """ +import cv2 import numpy as np +from pathlib import Path + +curpath = Path(__file__).resolve().parents[0] +curpath = Path(curpath) +parpath = curpath.parent # from tracking.utils.mergetrack import track_equal_track from .dotracks import doTracks from .track_front import frontTrack @@ -16,6 +22,14 @@ class doFrontTracks(doTracks): # self.tracks = [frontTrack(b) for b in self.lboxes] self.tracks = [frontTrack(b, f) for b, f in zip(self.lboxes, self.lfeats)] + self.incart = self.getincart() + + def getincart(self): + img = cv2.imread(str(parpath/'shopcart/cart_tempt/incart_ftmp.png'), cv2.IMREAD_GRAYSCALE) + ret, binary = cv2.threshold(img, 250, 255, cv2.THRESH_BINARY) + + return binary + def classify(self): '''功能:对 tracks 中元素分类 ''' diff --git a/tracking/dotrack/track_back.py b/tracking/dotrack/track_back.py index 20512bc..463c642 100644 --- a/tracking/dotrack/track_back.py +++ b/tracking/dotrack/track_back.py @@ -49,7 +49,7 @@ class backTrack(Track): self.incartrates = incartrates''' self.compute_ious_feat() - # self.PCA() + def isimgborder(self, BoundPixel=10, BoundThresh=0.3): diff --git a/tracking/dotrack/track_front.py b/tracking/dotrack/track_front.py index 0d957dd..1b28685 100644 --- a/tracking/dotrack/track_front.py +++ b/tracking/dotrack/track_front.py @@ -5,9 +5,15 @@ Created on Mon Mar 4 18:33:01 2024 @author: ym """ import numpy as np -from sklearn.cluster import KMeans +import cv2 +# from sklearn.cluster import KMeans from .dotracks import MoveState, Track +from pathlib import Path +curpath = Path(__file__).resolve().parents[0] +curpath = Path(curpath) +parpath = curpath.parent + class frontTrack(Track): # boxes: [x1, y1, x2, y2, track_id, score, cls, frame_index, box_index] @@ -36,9 +42,6 @@ class frontTrack(Track): self.HAND_STATIC_THRESH = 100 self.CART_POSIT_0 = 430 self.CART_POSIT_1 = 620 - - - def is_left_or_right_cornpoint(self): ''' 基于 all(boxes), diff --git a/tracking/module_analysis.py b/tracking/module_analysis.py index 16050dd..03a5579 100644 --- a/tracking/module_analysis.py +++ b/tracking/module_analysis.py @@ -22,9 +22,9 @@ from tracking.dotrack.dotracks_back import doBackTracks from tracking.dotrack.dotracks_front import doFrontTracks from tracking.utils.drawtracks import plot_frameID_y2, draw_all_trajectories -from tracking.utils.read_data import extract_data, read_deletedBarcode_file, read_tracking_output +from tracking.utils.read_data import extract_data, read_deletedBarcode_file, read_tracking_output, read_returnGoods_file -from contrast_analysis import contrast_analysis +from contrast.one2n_contrast import get_relative_paths, one2n_new, read_returnGoods_file from tracking.utils.annotator import TrackAnnotator W, H = 1024, 1280 @@ -32,6 +32,7 @@ Mode = 'front' #'back' ImgFormat = ['.jpg', '.jpeg', '.png', '.bmp'] + '''调用tracking()函数,利用本地跟踪算法获取各目标轨迹,可以比较本地跟踪算法与现场跟踪算法的区别。''' def init_tracker(tracker_yaml = None, bs=1): """ @@ -143,7 +144,7 @@ def do_tracking(fpath, savedir, event_name='images'): # trackerboxes, tracker_feat_dict = tracking(bboxes, ffeats) '''1.3 分别构造 2 个文件夹,(1) 存储画框后的图像; (2) 运动轨迹对应的 boxes子图''' - save_dir = os.path.join(savedir, event_name) + save_dir = os.path.join(savedir, event_name + '_images') subimg_dir = os.path.join(savedir, event_name + '_subimgs') if not os.path.exists(save_dir): os.makedirs(save_dir) @@ -237,14 +238,15 @@ def do_tracking(fpath, savedir, event_name='images'): subimg_path = os.path.join(subimg_dir, f'{CamerType}_tid{int(tid)}_{int(fid)}_{int(bid)}.png' ) cv2.imwrite(subimg_path, subimg) - # for track in tracking_output_boxes: - # for *xyxy, tid, conf, cls, fid, bid in track: - # img = imgs[int(fid-1)] - # x1, y1, x2, y2 = int(xyxy[0]/2), int(xyxy[1]/2), int(xyxy[2]/2), int(xyxy[3]/2) - # subimg = img[y1:y2, x1:x2] + + for track in tracking_output_boxes: + for *xyxy, tid, conf, cls, fid, bid in track: + img = imgs[int(fid-1)] + x1, y1, x2, y2 = int(xyxy[0]/2), int(xyxy[1]/2), int(xyxy[2]/2), int(xyxy[3]/2) + subimg = img[y1:y2, x1:x2] - # subimg_path = os.path.join(subimg_dir, f'{CamerType}_tid{int(tid)}_{int(fid-1)}_{int(bid)}_x.png' ) - # cv2.imwrite(subimg_path, subimg) + subimg_path = os.path.join(subimg_dir, f'x_{CamerType}_tid{int(tid)}_{int(fid)}_{int(bid)}.png' ) + cv2.imwrite(subimg_path, subimg) return img_tracking, abimg @@ -267,9 +269,13 @@ def tracking_simulate(eventpath, savepath): # else: # return # ============================================================================= - bname = os.path.basename(eventpath) - idx = bname.find('2024') - enent_name = bname[idx:(idx+15)] + enent_name = os.path.basename(eventpath) + + ## only for simplify the filename + idx = enent_name.find('2024') + if idx>=0: + enent_name = enent_name[idx:(idx+15)] + '''2. 依次读取 0/1_track.data 中数据,进行仿真''' illu_tracking, illu_select = [], [] @@ -308,27 +314,34 @@ def tracking_simulate(eventpath, savepath): else: Img_t = None - - '''3.1 单独另存保存完好的 8 轨迹图''' - basepath, _ = os.path.split(savepath) - trajpath = os.path.join(basepath, 'trajs') - if not os.path.exists(trajpath): - os.makedirs(trajpath) - traj_path = os.path.join(trajpath, enent_name+'.png') - imgpath_tracking = os.path.join(savepath, enent_name + '_ing.png') - imgpath_select = os.path.join(savepath, enent_name + '_slt.png') - imgpath_ts = os.path.join(savepath, enent_name + '_ts.png') + '''3.1 保存输出轨迹图,若tracking、select的shape相同,则合并输出,否则单独输出''' + imgpath_tracking = os.path.join(savepath, enent_name + '_tracking.png') + imgpath_select = os.path.join(savepath, enent_name + '_select.png') + imgpath_ts = os.path.join(savepath, enent_name + '_tracking_select.png') if Img_t is not None and Img_s is not None and np.all(Img_s.shape==Img_t.shape): Img_ts = np.concatenate((Img_t, Img_s), axis = 1) H, W = Img_ts.shape[:2] cv2.line(Img_ts, (int(W/2), 0), (int(W/2), int(H)), (0, 0, 255), 4) cv2.imwrite(imgpath_ts, Img_ts) - cv2.imwrite(traj_path, Img_ts) + else: if Img_s: cv2.imwrite(imgpath_select, Img_s) # 不会执行到该处 if Img_t: cv2.imwrite(imgpath_tracking, Img_t) # 不会执行到该处 + Img_ts = None + + '''3.2 单独另存保存完好的 8 轨迹图''' + if Img_ts is not None: + basepath, _ = os.path.split(savepath) + trajpath = os.path.join(basepath, 'trajs') + if not os.path.exists(trajpath): + os.makedirs(trajpath) + traj_path = os.path.join(trajpath, enent_name+'.png') + cv2.imwrite(traj_path, Img_ts) + + + return Img_ts @@ -336,14 +349,30 @@ def tracking_simulate(eventpath, savepath): # warnings.simplefilter("error", category=np.VisibleDeprecationWarning) def main_loop(): + + del_barcode_file = r'\\192.168.1.28\share\测试_202406\0723\0723_3\deletedBarcode.txt' basepath = r'\\192.168.1.28\share\测试_202406\0723\0723_3' # 测试数据文件夹地址 - SavePath = r'D:\contrast\dataset\resultx' # 结果保存地址 - # prefix = ["getout_", "input_", "error_"] - + + # del_barcode_file = r'\\192.168.1.28\share\测试_202406\1030\images\returnGoods.txt' + # basepath = r'\\192.168.1.28\share\测试_202406\1030\images' # 测试数据文件夹地址 + '''获取性能测试数据相关路径''' - relative_paths = contrast_analysis(del_barcode_file, basepath, SavePath) + SavePath = r'D:\contrast\dataset\resultx' # 结果保存地址 + saveimgs = True + if os.path.basename(del_barcode_file).find('deletedBarcode'): + relative_paths = get_relative_paths(del_barcode_file, basepath, SavePath, saveimgs) + elif os.path.basename(del_barcode_file).find('returnGoods'): + blist = read_returnGoods_file(del_barcode_file) + errpairs, corrpairs, err_similarity, correct_similarity = one2n_new(blist) + relative_paths = [] + for getoutevent, inputevent, errevent in errpairs: + relative_paths.append(os.path.join(basepath, getoutevent)) + relative_paths.append(os.path.join(basepath, inputevent)) + relative_paths.append(os.path.join(basepath, errevent)) + + # prefix = ["getout_", "input_", "error_"] '''开始循环执行每次测试过任务''' k = 0 for tuple_paths in relative_paths: @@ -383,12 +412,12 @@ def main(): SavePath: 包含二级目录,一级目录为轨迹图像;二级目录为与data文件对应的序列图像存储地址。 ''' # eventPaths = r'\\192.168.1.28\share\测试_202406\0723\0723_3' - eventPaths = r"D:\DetectTracking\tracking\images" - + eventPaths = r'D:\datasets\ym\exhibition\识别错' savePath = r'D:\contrast\dataset\result' + k=0 for pathname in os.listdir(eventPaths): - pathname = "20240925-142635-3e3cb61a-8bbe-45f2-aed7-a40de7f2d624_6924743924161" + pathname = "放入薯片识别为辣条" eventpath = os.path.join(eventPaths, pathname) savepath = os.path.join(savePath, pathname) @@ -396,6 +425,7 @@ def main(): os.makedirs(savepath) tracking_simulate(eventpath, savepath) + # try: # tracking_simulate(eventpath, savepath) # except Exception as e: diff --git a/tracking/tracking_test.py b/tracking/tracking_test.py index 6ea8015..0122d6a 100644 --- a/tracking/tracking_test.py +++ b/tracking/tracking_test.py @@ -85,10 +85,8 @@ def have_tracked(): k = 0 gt = Profile() for filename in os.listdir(trackdict): - # filename = 'test_20240402-173935_6920152400975_back_174037372.pkl' - # filename = '6907149227609_20240508-174733_back_returnGood_70f754088050_425_17327712807.pkl' - # filename = '6907149227609_20240508-174733_front_returnGood_70f754088050_425_17327712807.pkl' - + filename = '153112511_0_seek_105.pkl' + file, ext = os.path.splitext(filename) filepath = os.path.join(trackdict, filename) TracksDict = np.load(filepath, allow_pickle=True) @@ -97,6 +95,9 @@ def have_tracked(): with gt: if filename.find("front") >= 0: vts = doFrontTracks(bboxes, TracksDict) + + Intrude = vts.isintrude() + vts.classify() save_subimgs(vts, file, TracksDict) @@ -113,6 +114,9 @@ def have_tracked(): else: vts = doBackTracks(bboxes, TracksDict) + + Intrude = vts.isintrude() + vts.classify() alltracks.append(vts) @@ -124,9 +128,9 @@ def have_tracked(): cv2.imwrite(str(trackpath), img_tracking) print(file+f" need time: {gt.dt:.2f}s") - # k += 1 - # if k==1: - # break + k += 1 + if k==1: + break if len(alltracks): drawFeatures(alltracks, save_dir) diff --git a/tracking/utils/__pycache__/drawtracks.cpython-39.pyc b/tracking/utils/__pycache__/drawtracks.cpython-39.pyc index 568c628..d1e5e1e 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 c48daf6..a35e79e 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 651004b..024c22b 100644 --- a/tracking/utils/drawtracks.py +++ b/tracking/utils/drawtracks.py @@ -7,11 +7,13 @@ Created on Mon Jan 15 15:26:38 2024 import numpy as np import cv2 import os +from pathlib import Path import matplotlib.pyplot as plt from sklearn.decomposition import PCA -from utils.annotator import TrackAnnotator -from utils.plotting import colors -from pathlib import Path + +from tracking.utils.annotator import TrackAnnotator +from tracking.utils.plotting import colors + def plot_frameID_y2(vts): diff --git a/tracking/utils/read_data.py b/tracking/utils/read_data.py index 7d4395b..663890d 100644 --- a/tracking/utils/read_data.py +++ b/tracking/utils/read_data.py @@ -10,10 +10,10 @@ import numpy as np import re import os from collections import OrderedDict +import warnings import matplotlib.pyplot as plt - def str_to_float_arr(s): # 移除字符串末尾的逗号(如果存在) if s.endswith(','): @@ -31,7 +31,9 @@ def find_samebox_in_array(arr, target): return i return -1 -import warnings + + + def extract_data(datapath): @@ -41,30 +43,26 @@ def extract_data(datapath): trackerfeats = np.empty((0, 256), dtype=np.float64) boxes, feats, tboxes, tfeats = [], [], [], [] + + timestamps, frameIds = [], [] + with open(datapath, 'r', encoding='utf-8') as lines: for line in lines: line = line.strip() # 去除行尾的换行符和可能的空白字符 if not line: # 跳过空行 continue - + if line.find("CameraId")>=0: if len(boxes): bboxes.append(np.array(boxes)) if len(feats): ffeats.append(np.array(feats)) - - # with warnings.catch_warnings(record=True) as w: - # if len(boxes): bboxes.append(np.array(boxes)) - # if len(feats): ffeats.append(np.array(feats)) - # if w: - # print(f"捕获到 {len(w)} 个警告:") - # for warning in w: - # print(f"警告类型: {warning.category}") - # print(f"警告消息: {warning.message}") - # print(f"警告发生的地方: {warning.filename}:{warning.lineno}") - - if len(tboxes): + if len(tboxes): trackerboxes = np.concatenate((trackerboxes, np.array(tboxes))) if len(tfeats): trackerfeats = np.concatenate((trackerfeats, np.array(tfeats))) + + timestamp, frameId = [int(ln.split(":")[1]) for ln in line.split(",")[1:]] + timestamps.append(timestamp) + frameIds.append(frameId) boxes, feats, tboxes, tfeats = [], [], [], [] @@ -103,6 +101,9 @@ def extract_data(datapath): assert(len(trackerboxes)==len(trackerfeats)), "Error at tracker output!" tracker_feat_dict = {} + tracker_feat_dict["timestamps"] = timestamps + tracker_feat_dict["frameIds"] = frameIds + for i in range(len(trackerboxes)): tid, fid, bid = int(trackerboxes[i, 4]), int(trackerboxes[i, 7]), int(trackerboxes[i, 8]) if f"frame_{fid}" not in tracker_feat_dict: @@ -169,8 +170,8 @@ def read_tracking_output(filepath): return np.array(boxes), np.array(feats) -def read_deletedBarcode_file(filePth): - with open(filePth, 'r', encoding='utf-8') as f: +def read_deletedBarcode_file(filePath): + with open(filePath, 'r', encoding='utf-8') as f: lines = f.readlines() split_flag, all_list = False, [] @@ -179,6 +180,9 @@ def read_deletedBarcode_file(filePth): clean_lines = [line.strip().replace("'", '').replace('"', '') for line in lines] for i, line in enumerate(clean_lines): + if line.endswith(','): + line = line[:-1] + stripped_line = line.strip() if not stripped_line: if len(barcode_list): dict['barcode'] = barcode_list @@ -210,11 +214,106 @@ def read_deletedBarcode_file(filePth): return all_list +def read_returnGoods_file(filePath): + ''' + 20241030开始,原 deletedBarcode.txt 中数据格式修改为 returnGoods.txt,读数方式随之变化 + ''' + + with open(filePath, 'r', encoding='utf-8') as f: + lines = f.readlines() + clean_lines = [line.strip().replace("'", '').replace('"', '') for line in lines] + + + + all_list = [] + split_flag, dict = False, {} + barcode_list, similarity_list = [], [] + event_list, type_list = [], [] + + + for i, line in enumerate(clean_lines): + stripped_line = line.strip() + if line.endswith(','): + line = line[:-1] + + if not stripped_line: + if len(barcode_list): dict['barcode'] = barcode_list + if len(similarity_list): dict['similarity'] = similarity_list + if len(event_list): dict['event'] = event_list + if len(type_list): dict['type'] = type_list + + if len(dict) and dict['SeqDir'].find('*')<0: + all_list.append(dict) + + split_flag, dict = False, {} + barcode_list, similarity_list = [], [] + event_list, type_list = [], [] + continue + + if line.find(':')<0: continue + if line.find('1:n')==0: continue + + label = line.split(':')[0].strip() + value = line.split(':')[1].strip() + + if label == 'SeqDir': + dict['SeqDir'] = value + dict['Deleted'] = value.split('_')[-1] + if label == 'List': + split_flag = True + continue + if split_flag: + event_list.append(label) + barcode_list.append(label.split('_')[-1]) + similarity_list.append(value.split(',')[0]) + type_list.append(value.split('=')[-1]) + + if len(barcode_list): dict['barcode'] = barcode_list + if len(similarity_list): dict['similarity'] = similarity_list + if len(event_list): dict['event'] = event_list + if len(type_list): dict['type'] = type_list + if len(dict) and dict['SeqDir'].find('*')<0: + all_list.append(dict) + + return all_list + + + + + + + + + + + + + + + +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_weight_timeConsuming(filePth): WeightDict, SensorDict, ProcessTimeDict = OrderedDict(), OrderedDict(), OrderedDict() with open(filePth, 'r', encoding='utf-8') as f: lines = f.readlines() + # label = '' for i, line in enumerate(lines): line = line.strip() diff --git a/utils/__pycache__/dataloaders.cpython-39.pyc b/utils/__pycache__/dataloaders.cpython-39.pyc index 95b4e57..c77703a 100644 Binary files a/utils/__pycache__/dataloaders.cpython-39.pyc and b/utils/__pycache__/dataloaders.cpython-39.pyc differ diff --git a/utils/__pycache__/getsource.cpython-39.pyc b/utils/__pycache__/getsource.cpython-39.pyc new file mode 100644 index 0000000..2253c09 Binary files /dev/null and b/utils/__pycache__/getsource.cpython-39.pyc differ diff --git a/utils/dataloaders.py b/utils/dataloaders.py index 26201c3..4ef1874 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -257,6 +257,8 @@ class LoadImages: videos = [x for x in files if x.split('.')[-1].lower() in VID_FORMATS] ni, nv = len(images), len(videos) + + self.img_size = img_size self.stride = stride self.files = images + videos diff --git a/utils/getsource.py b/utils/getsource.py new file mode 100644 index 0000000..6c918c1 --- /dev/null +++ b/utils/getsource.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +""" +Created on Wed Oct 30 13:18:59 2024 + +@author: ym +""" + +import os +import glob + +IMGFORMATS = '.bmp', '.jpeg', '.jpg', 'png', 'tif', 'tiff', 'webp', 'pfm' +VIDFORMATS = '.avi', '.gif', '.m4v', '.mkv', '.mov', '.mp4', '.ts', '.wmv' + +def get_image_pairs(p): + files = [] + files.extend(sorted(glob.glob(os.path.join(p, '*.jpg')))) + # images = [x for x in files if x.split('.')[-1].lower() in IMG_FORMATS] + + tamps_0, tamps_1 = [], [] + files_0, files_1 = [], [] + for file in files: + basename = os.path.basename(file) + if basename.find('frameId')<0: continue + + + f, ext = os.path.splitext(basename) + camer, tamp, _, frameId = f.split('_') + + if camer == '0': + tamps_0.append(int(tamp)) + files_0.append(file) + + if camer == '1': + tamps_1.append(int(tamp)) + files_1.append(file) + + idx0 = sorted(range(len(tamps_0)), key=lambda k: tamps_0[k]) + files0 = [files_0[i] for i in idx0] + + idx1 = sorted(range(len(tamps_1)), key=lambda k: tamps_1[k]) + files1 = [files_1[i] for i in idx1] + + files = (files0, files1) + + return files + + +def get_video_pairs(vpath): + vdieopath = [] + for filename in os.listdir(vpath): + file, ext = os.path.splitext(filename) + if ext in VIDFORMATS: + vdieopath.append(os.path.join(vpath, filename)) + return vdieopath + + + + + + diff --git a/说明文档.txt b/说明文档.txt index e9f2775..90b9d34 100644 --- a/说明文档.txt +++ b/说明文档.txt @@ -1,4 +1,4 @@ -三个功能模块 +五个功能模块 1. Yolo + Tracker + Resnet, 其中 Resnet 的实现在./contrast中 track_reid.py @@ -12,7 +12,8 @@ 3. 比对分析模块,目录为:./contrast 2个场景:1:1,1:n 1:1场景: - (1) OneToOneCompare.txt + (1) 利用现场保存数据进行比对 + OneToOneCompare.txt(现场保存数据) one2one_onsite.py (2) 利用本地算法进行特征提取 one2one_contrast.py @@ -23,6 +24,29 @@ feat_select.py +4. 整体流程仿真 + pipeline.py + SourceType: "image", "video", yolo+resent+tracker模块输入数据类型 + + + + + + +5. 全实时时间切分仿真分析 + time_devide.py + 需分 2 步运行模块: + (1) runyolo() + + 该模块调用 imgs_inference.py 中模块 run_yolo + 后续工作: + 1). 将run_yolo模块与track_redi.yolo_resnet_tracker模块合并 + 2). 图像文件名标准化 + + (2) show_seri() + 该模块调用 event_time_specify.py 中模块 devide_motion_state + + 具体实现: ./tracking tracking_test.py @@ -50,6 +74,7 @@ (b) 本地tracking输出; (c) 现场算法轨迹选择前轨迹; (d) 现场算法轨迹选择后的轨迹 + do_tracking(fpath, savedir, event_name) @@ -57,10 +82,10 @@ fpath: 0/1_track.data文件,并核验是否存在 0/1_tracking_output.data,若不存在该文件,直接返回 None, None savedir: 在该文件夹下会建立3个子文件夹及一个png轨迹图 - ./savedir/event_name - ./savedir/event_name_subimgs - ./savedir/trajectory - ./savedir/event_name_ts.png + ./savedir/event_name_images, 画boxes后的图像序列 + ./savedir/event_name_subimgs, 轨迹分析后的目标子图,无 _x 为PC机结果,有 _x 为平板单摄像头轨迹选择后的输出 + ./savedir/trajectory, 存储每一个轨迹图 + ./savedir/event_name_tracking_select.png 或 enent_name_tracking.png 或 enent_name_select.png outputs: img_tracking:本机tracker、tracking 输出的结果比较图 @@ -126,4 +151,27 @@ main(): 循环读取不同文件夹中的 deletedBarcode.txt,合并评估。 main1(): - 指定deletedBarcode.txt进行1:n性能评估 \ No newline at end of file + 指定deletedBarcode.txt进行1:n性能评估 + + one2one_onsite.py + 现场试验输出数据的 1:1 性能评估; + 适用于202410前数据保存版本的,需调用 OneToOneCompare.txt + + 标准特征向量生成 + std_sample_path:图像样本的存储地址 + std_barcode_path:对 std_sample_path 中文件列表进行遍历,形成{barcode: 图像样本地址}形式字典并进行存储 + std_feature_path:调用 inference_image(), 对每一个barcode,生成字典并进行存储 + + + genfeats.py + genfeatures(imgpath, bcdpath, featpath) + 功能:生成标准特征向量 + 参数: + (1) imgpath:图像样本的存储地址 + (2) bcdpath:对 imgpath 中文件列表进行遍历,形成{barcode: 图像样本地址}形式字典并进行存储 + (3) featpath:调用 inference_image(), 对每一个barcode,生成字典并进行存储 + + + + + \ No newline at end of file