This commit is contained in:
王庆刚
2024-11-04 18:06:52 +08:00
parent dfb2272a15
commit 5ecc1285d4
41 changed files with 2552 additions and 440 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

209
contrast/genfeats.py Normal file
View File

@ -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()

View File

@ -16,60 +16,13 @@ import shutil
import numpy as np import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import cv2 import cv2
from pathlib import Path
import sys import sys
sys.path.append(r"D:\DetectTracking") sys.path.append(r"D:\DetectTracking")
from tracking.utils.plotting import Annotator, colors from tracking.utils.plotting import Annotator, colors
from tracking.utils.read_data import extract_data, read_deletedBarcode_file, read_tracking_output from tracking.utils.read_data import extract_data, read_deletedBarcode_file, read_tracking_output, read_returnGoods_file
from tracking.utils.plotting import draw_tracking_boxes from tracking.utils.plotting import draw_tracking_boxes
from contrast.utils.tools import showHist, show_recall_prec, compute_recall_precision
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
# ============================================================================= # =============================================================================
@ -287,27 +240,9 @@ def save_tracking_imgpairs(pair, basepath, savepath):
cv2.imwrite(imgpath, img) cv2.imwrite(imgpath, img)
# def performance_evaluate(all_list, isshow=False):
# corrpairs, correct_barcode_list, correct_similarity, errpairs, err_barcode_list, err_similarity = [], [], [], [], [], [] def one2n_old(all_list):
# for s_list in all_list: corrpairs, errpairs, correct_similarity, err_similarity = [], [], [], []
# 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 = [], [], [], [], [], []
for s_list in all_list: for s_list in all_list:
seqdir = s_list['SeqDir'].strip() seqdir = s_list['SeqDir'].strip()
delete = s_list['Deleted'].strip() delete = s_list['Deleted'].strip()
@ -332,70 +267,136 @@ def performance_evaluate(all_list, isshow=False):
matched_barcode = barcodes[index] matched_barcode = barcodes[index]
if matched_barcode == delete: if matched_barcode == delete:
corrpairs.append((seqdir, delete)) corrpairs.append((seqdir, delete))
correct_barcode_list.append(delete)
correct_similarity.append(max(similarity)) correct_similarity.append(max(similarity))
else: else:
errpairs.append((seqdir, delete, matched_barcode)) errpairs.append((seqdir, delete, matched_barcode))
err_barcode_list.append(delete)
err_similarity.append(max(similarity)) err_similarity.append(max(similarity))
'''3. 计算比对性能 '''
if isshow: return corrpairs, errpairs, correct_similarity, err_similarity
recall, prec, ths = compute_recall_precision(err_similarity, correct_similarity)
show_recall_prec(recall, prec, ths)
showHist(err_similarity, correct_similarity)
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 return errpairs, corrpairs, err_similarity, correct_similarity
# def contrast_analysis(del_barcode_file, basepath, savepath, saveimgs=False):
def contrast_analysis(del_barcode_file, basepath, savepath, saveimgs=False): def get_relative_paths(del_barcode_file, basepath, savepath, saveimgs=False):
''' '''
del_barcode_file: 测试数据文件,利用该文件进行算法性能分析 del_barcode_file:
deletedBarcode.txt 格式的 1:n 数据结果文件
returnGoods.txt格式数据文件不需要调用该函数one2n_old() 函数返回的 errpairs
中元素为三元元组(取出,放入, 错误匹配)
''' '''
relative_paths = []
'''1. 读取 deletedBarcode 文件 ''' '''1. 读取 deletedBarcode 文件 '''
all_list = read_deletedBarcode_file(del_barcode_file) all_list = read_deletedBarcode_file(del_barcode_file)
'''2. 算法性能评估,并输出 (取出,删除, 错误匹配) 对 ''' '''2. 算法性能评估,并输出 (取出,删除, 错误匹配) 对 '''
errpairs, corrpairs, _, _ = performance_evaluate(all_list) errpairs, corrpairs, _, _ = one2n_old(all_list)
'''3. 获取 (取出,删除, 错误匹配) 对应路径,保存相应轨迹图像''' '''3. 构造事件组合(取出,放入并删除, 错误匹配) 对应路径 '''
relative_paths = []
for errpair in errpairs: for errpair in errpairs:
GetoutPath, InputPath, ErrorPath = get_contrast_paths(errpair, basepath) GetoutPath, InputPath, ErrorPath = get_contrast_paths(errpair, basepath)
relative_paths.append((GetoutPath, InputPath, ErrorPath)) relative_paths.append((GetoutPath, InputPath, ErrorPath))
'''3. 获取 (取出,放入并删除, 错误匹配) 对应路径,保存相应轨迹图像'''
if saveimgs: if saveimgs:
save_tracking_imgpairs(errpair, basepath, savepath) save_tracking_imgpairs(errpair, basepath, savepath)
return relative_paths 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'\\192.168.1.28\share\测试_202406\deletedBarcode\illustration'
# savepath = r'D:\contrast\dataset\1_to_n\illustration'
if not os.path.exists(savepath): if not os.path.exists(savepath):
os.mkdir(savepath) os.mkdir(savepath)
if os.path.isfile(fpath): if os.path.isdir(fpath):
fpath, filename = os.path.split(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 = {}, [] BarLists, blists = {}, []
for filename in os.listdir(fpath): for pth in filepaths:
file = os.path.splitext(filename)[0][15:] 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
filepath = os.path.join(fpath, filename)
blist = read_deletedBarcode_file(filepath)
BarLists.update({file: blist}) BarLists.update({file: blist})
blists.extend(blist) blists.extend(blist)
BarLists.update({file: blist}) BarLists.update({file: blist})
BarLists.update({"Total": blists}) BarLists.update({"Total": blists})
for file, blist in BarLists.items(): for file, blist in BarLists.items():
errpairs, corrpairs, err_similarity, correct_similarity = performance_evaluate(blist) 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) recall, prec, ths = compute_recall_precision(err_similarity, correct_similarity)
@ -411,25 +412,33 @@ def contrast_loop(fpath):
# plt.close() # 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' del_barcode_file = r'\\192.168.1.28\share\测试_202406\709\deletedBarcode.txt'
basepath = r'\\192.168.1.28\share\测试_202406\709' 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: 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: except Exception as e:
print(f'Error Type: {e}') print(f'Error Type: {e}')
if __name__ == '__main__': if __name__ == '__main__':
main()
# main1() one2n_test()
# test_getreltpath()

View File

@ -239,71 +239,71 @@ def creat_shopping_event(eventPath, subimgPath=False):
return event return event
def get_std_barcodeDict(bcdpath, savepath): # def get_std_barcodeDict(bcdpath, savepath):
''' # '''
inputs: # inputs:
bcdpath: 已清洗的barcode样本图像如果barcode下有'base'文件夹,只选用该文件夹下图像 # bcdpath: 已清洗的barcode样本图像如果barcode下有'base'文件夹,只选用该文件夹下图像
(default = r'\\192.168.1.28\share\已标注数据备份\对比数据\barcode\barcode_1771') # (default = r'\\192.168.1.28\share\已标注数据备份\对比数据\barcode\barcode_1771')
功能: # 功能:
生成并保存只有一个key值的字典 {barcode: [imgpath1, imgpath1, ...]} # 生成并保存只有一个key值的字典 {barcode: [imgpath1, imgpath1, ...]}
savepath: 字典存储地址文件名格式barcode.pickle # 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 列表''' # '''读取数据集中 barcode 列表'''
stdBarcodeList = [] # stdBarcodeList = []
for filename in os.listdir(bcdpath): # for filename in os.listdir(bcdpath):
filepath = os.path.join(bcdpath, filename) # filepath = os.path.join(bcdpath, filename)
# if not os.path.isdir(filepath) or not filename.isdigit() or len(filename)<8: # # if not os.path.isdir(filepath) or not filename.isdigit() or len(filename)<8:
# continue # # continue
stdBarcodeList.append(filename) # 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, ...]}''' # '''遍历数据集针对每一个barcode生成并保存字典{barcode: [imgpath1, imgpath1, ...]}'''
k = 0 # k = 0
errbarcodes = [] # errbarcodes = []
for barcode, bpath in bcdPaths: # for barcode, bpath in bcdPaths:
pickpath = os.path.join(savepath, f"{barcode}.pickle") # pickpath = os.path.join(savepath, f"{barcode}.pickle")
if os.path.isfile(pickpath): # if os.path.isfile(pickpath):
continue # continue
stdBarcodeDict = {} # stdBarcodeDict = {}
stdBarcodeDict[barcode] = [] # stdBarcodeDict[barcode] = []
for root, dirs, files in os.walk(bpath): # for root, dirs, files in os.walk(bpath):
imgpaths = [] # imgpaths = []
if "base" in dirs: # if "base" in dirs:
broot = os.path.join(root, "base") # broot = os.path.join(root, "base")
for imgname in os.listdir(broot): # for imgname in os.listdir(broot):
imgpath = os.path.join(broot, imgname) # imgpath = os.path.join(broot, imgname)
file, ext = os.path.splitext(imgpath) # file, ext = os.path.splitext(imgpath)
if ext not in IMG_FORMAT: # if ext not in IMG_FORMAT:
continue # continue
imgpaths.append(imgpath) # imgpaths.append(imgpath)
stdBarcodeDict[barcode].extend(imgpaths) # stdBarcodeDict[barcode].extend(imgpaths)
break # break
else: # else:
for imgname in files: # for imgname in files:
imgpath = os.path.join(root, imgname) # imgpath = os.path.join(root, imgname)
_, ext = os.path.splitext(imgpath) # _, ext = os.path.splitext(imgpath)
if ext not in IMG_FORMAT: continue # if ext not in IMG_FORMAT: continue
imgpaths.append(imgpath) # imgpaths.append(imgpath)
stdBarcodeDict[barcode].extend(imgpaths) # stdBarcodeDict[barcode].extend(imgpaths)
pickpath = os.path.join(savepath, f"{barcode}.pickle") # pickpath = os.path.join(savepath, f"{barcode}.pickle")
with open(pickpath, 'wb') as f: # with open(pickpath, 'wb') as f:
pickle.dump(stdBarcodeDict, f) # pickle.dump(stdBarcodeDict, f)
print(f"Barcode: {barcode}") # print(f"Barcode: {barcode}")
# k += 1 # # k += 1
# if k == 10: # # if k == 10:
# break # # break
print(f"Len of errbarcodes: {len(errbarcodes)}") # print(f"Len of errbarcodes: {len(errbarcodes)}")
return # return
def save_event_subimg(event, savepath): def save_event_subimg(event, savepath):
''' '''
@ -355,92 +355,92 @@ def batch_inference(imgpaths, batch):
features = np.concatenate(features, axis=0) features = np.concatenate(features, axis=0)
return features return features
def stdfeat_infer(imgPath, featPath, bcdSet=None): # def stdfeat_infer(imgPath, featPath, bcdSet=None):
''' # '''
inputs: # inputs:
imgPath: 该文件夹下的 pickle 文件格式 {barcode: [imgpath1, imgpath1, ...]} # imgPath: 该文件夹下的 pickle 文件格式 {barcode: [imgpath1, imgpath1, ...]}
featPath: imgPath图像对应特征的存储地址 # featPath: imgPath图像对应特征的存储地址
功能: # 功能:
对 imgPath中图像进行特征提取生成只有一个key值的字典 # 对 imgPath中图像进行特征提取生成只有一个key值的字典
{barcode: features}features.shape=(nsample, 256),并保存至 featPath 中 # {barcode: features}features.shape=(nsample, 256),并保存至 featPath 中
''' # '''
# imgPath = r"\\192.168.1.28\share\测试_202406\contrast\std_barcodes" # # imgPath = r"\\192.168.1.28\share\测试_202406\contrast\std_barcodes"
# featPath = r"\\192.168.1.28\share\测试_202406\contrast\std_features" # # featPath = r"\\192.168.1.28\share\测试_202406\contrast\std_features"
stdBarcodeDict = {} # stdBarcodeDict = {}
stdBarcodeDict_ft16 = {} # stdBarcodeDict_ft16 = {}
'''4处同名: (1)barcode原始图像文件夹; (2)imgPath中的 .pickle 文件名、该pickle文件中字典的key值''' # '''4处同名: (1)barcode原始图像文件夹; (2)imgPath中的 .pickle 文件名、该pickle文件中字典的key值'''
k = 0 # k = 0
for filename in os.listdir(imgPath): # for filename in os.listdir(imgPath):
bcd, ext = os.path.splitext(filename) # bcd, ext = os.path.splitext(filename)
pkpath = os.path.join(featPath, f"{bcd}.pickle") # pkpath = os.path.join(featPath, f"{bcd}.pickle")
if os.path.isfile(pkpath): continue # if os.path.isfile(pkpath): continue
if bcdSet is not None and bcd not in bcdSet: # if bcdSet is not None and bcd not in bcdSet:
continue # continue
filepath = os.path.join(imgPath, filename) # filepath = os.path.join(imgPath, filename)
stdbDict = {} # stdbDict = {}
stdbDict_ft16 = {} # stdbDict_ft16 = {}
stdbDict_uint8 = {} # stdbDict_uint8 = {}
t1 = time.time() # t1 = time.time()
try: # try:
with open(filepath, 'rb') as f: # with open(filepath, 'rb') as f:
bpDict = pickle.load(f) # bpDict = pickle.load(f)
for barcode, imgpaths in bpDict.items(): # for barcode, imgpaths in bpDict.items():
# feature = batch_inference(imgpaths, 8) #from vit distilled model of LiChen # # feature = batch_inference(imgpaths, 8) #from vit distilled model of LiChen
feature = inference_image(imgpaths, conf.test_transform, model, conf.device) # feature = inference_image(imgpaths, conf.test_transform, model, conf.device)
feature /= np.linalg.norm(feature, axis=1)[:, None] # feature /= np.linalg.norm(feature, axis=1)[:, None]
# float16 # # float16
feature_ft16 = feature.astype(np.float16) # feature_ft16 = feature.astype(np.float16)
feature_ft16 /= np.linalg.norm(feature_ft16, axis=1)[:, None] # feature_ft16 /= np.linalg.norm(feature_ft16, axis=1)[:, None]
# uint8, 两种策略1) 精度损失小, 2) 计算复杂度小 # # uint8, 两种策略1) 精度损失小, 2) 计算复杂度小
# feature_uint8, _ = ft16_to_uint8(feature_ft16) # # feature_uint8, _ = ft16_to_uint8(feature_ft16)
feature_uint8 = (feature_ft16*128).astype(np.int8) # feature_uint8 = (feature_ft16*128).astype(np.int8)
except Exception as e: # except Exception as e:
print(f"Error accured at: {filename}, with Exception is: {e}") # print(f"Error accured at: {filename}, with Exception is: {e}")
'''================ 保存单个barcode特征 ================''' # '''================ 保存单个barcode特征 ================'''
##================== float32 # ##================== float32
stdbDict["barcode"] = barcode # stdbDict["barcode"] = barcode
stdbDict["imgpaths"] = imgpaths # stdbDict["imgpaths"] = imgpaths
stdbDict["feats_ft32"] = feature # stdbDict["feats_ft32"] = feature
stdbDict["feats_ft16"] = feature_ft16 # stdbDict["feats_ft16"] = feature_ft16
stdbDict["feats_uint8"] = feature_uint8 # stdbDict["feats_uint8"] = feature_uint8
with open(pkpath, 'wb') as f: # with open(pkpath, 'wb') as f:
pickle.dump(stdbDict, f) # pickle.dump(stdbDict, f)
stdBarcodeDict[barcode] = feature # stdBarcodeDict[barcode] = feature
stdBarcodeDict_ft16[barcode] = feature_ft16 # stdBarcodeDict_ft16[barcode] = feature_ft16
t2 = time.time() # t2 = time.time()
print(f"Barcode: {barcode}, need time: {t2-t1:.1f} secs") # print(f"Barcode: {barcode}, need time: {t2-t1:.1f} secs")
# k += 1 # # k += 1
# if k == 10: # # if k == 10:
# break # # break
##================== float32 # ##================== float32
# pickpath = os.path.join(featPath, f"barcode_features_{k}.pickle") # # pickpath = os.path.join(featPath, f"barcode_features_{k}.pickle")
# with open(pickpath, 'wb') as f: # # with open(pickpath, 'wb') as f:
# pickle.dump(stdBarcodeDict, f) # # pickle.dump(stdBarcodeDict, f)
##================== float16 # ##================== float16
# pickpath_ft16 = os.path.join(featPath, f"barcode_features_ft16_{k}.pickle") # # pickpath_ft16 = os.path.join(featPath, f"barcode_features_ft16_{k}.pickle")
# with open(pickpath_ft16, 'wb') as f: # # with open(pickpath_ft16, 'wb') as f:
# pickle.dump(stdBarcodeDict_ft16, f) # # pickle.dump(stdBarcodeDict_ft16, f)
return # return
def contrast_performance_evaluate(resultPath): def contrast_performance_evaluate(resultPath):
@ -789,30 +789,28 @@ def main():
compute_precise_recall(pickpath) compute_precise_recall(pickpath)
def main_std(): # def main_std():
std_sample_path = r"\\192.168.1.28\share\已标注数据备份\对比数据\barcode\barcode_500_2192_已清洗" # 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_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" # 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 = [] # # fileList = []
# for filename in os.listdir(std_barcode_path): # # for filename in os.listdir(std_barcode_path):
# filepath = os.path.join(std_barcode_path, filename) # # filepath = os.path.join(std_barcode_path, filename)
# with open(filepath, 'rb') as f: # # with open(filepath, 'rb') as f:
# bpDict = pickle.load(f) # # bpDict = pickle.load(f)
# for v in bpDict.values(): # # for v in bpDict.values():
# fileList.append(len(v)) # # fileList.append(len(v))
# print("done") # # print("done")
if __name__ == '__main__': if __name__ == '__main__':
# main() main()
# main_std()
main_std()

View File

@ -1,9 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Created on Wed Sep 11 11:57:30 2024 Created on Wed Sep 11 11:57:30 2024
永辉现场试验输出数据的 1:1 性能评估
永辉现场 1:1 比对测试 适用于202410前数据保存版本的需调用 OneToOneCompare.txt
@author: ym @author: ym
""" """
import os import os
@ -65,14 +64,14 @@ def plot_pr_curve(matrix):
axs[1].set_title(f'Cross Barcode, Num: {TPFN_mean}') axs[1].set_title(f'Cross Barcode, Num: {TPFN_mean}')
# plt.savefig(f'./result/{file}_hist.png') # svg, png, pdf # plt.savefig(f'./result/{file}_hist.png') # svg, png, pdf
Recall_Pos = [] Recall_Neg = []
Thresh = np.linspace(-0.2, 1, 100) Thresh = np.linspace(-0.2, 1, 100)
for th in Thresh: for th in Thresh:
TN = np.sum(simimax < th) TN = np.sum(simimax < th)
Recall_Pos.append(TN/TPFN_max) Recall_Neg.append(TN/TPFN_max)
fig, ax = plt.subplots() 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_xlim([0, 1])
ax.set_ylim([0, 1]) ax.set_ylim([0, 1])
ax.grid(True) ax.grid(True)
@ -96,10 +95,8 @@ def main():
simiList = [] simiList = []
for fp in filepaths: for fp in filepaths:
slist = read_one2one_data(fp) slist = read_one2one_data(fp)
simiList.extend(slist) simiList.extend(slist)
plot_pr_curve(simiList) plot_pr_curve(simiList)

Binary file not shown.

Binary file not shown.

56
contrast/utils/tools.py Normal file
View File

@ -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

301
event_time_specify.py Normal file
View File

@ -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_min<tmin:
# tmin = t_min
# if t_max>tmax:
# 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()

435
imgs_inference.py Normal file
View File

@ -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))

243
move_detect.py Normal file
View File

@ -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_idx1y1x2y2 格式
[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]

View File

@ -7,24 +7,20 @@ Created on Sun Sep 29 08:59:21 2024
import os import os
import cv2 import cv2
import pickle import pickle
import numpy as np
from pathlib import Path from pathlib import Path
from track_reid import parse_opt, yolo_resnet_tracker from track_reid import parse_opt, yolo_resnet_tracker
from tracking.dotrack.dotracks_back import doBackTracks from tracking.dotrack.dotracks_back import doBackTracks
from tracking.dotrack.dotracks_front import doFrontTracks 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(): def get_interbcd_inputenents():
bcdpath = r"\\192.168.1.28\share\测试_202406\contrast\std_barcodes_2192" bcdpath = r"\\192.168.1.28\share\测试_202406\contrast\std_barcodes_2192"
@ -45,107 +41,117 @@ def get_interbcd_inputenents():
return input_enents return input_enents
def pipeline(eventpath, stdfeat_path=None, SourceType = "image"):
'''
inputs:
eventpath: 事件文件夹
stdfeat_path: 标准特征文件地址
outputs:
'''
SourceType = "image" # image
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):
# eventpath = r"\\192.168.1.28\share\测试_202406\0918\images1\20240918-110822-1bc3902e-5a8e-4e23-8eca-fb3f02738551_6938314601726" # eventpath = r"\\192.168.1.28\share\测试_202406\0918\images1\20240918-110822-1bc3902e-5a8e-4e23-8eca-fb3f02738551_6938314601726"
savepath = r"D:\contrast\detect" savepath = r"D:\contrast\detect"
opt = parse_opt()
optdict = vars(opt)
optdict["project"] = savepath optdict["project"] = savepath
eventname = os.path.basename(eventpath) eventname = os.path.basename(eventpath)
barcode = eventname.split('_')[-1] # barcode = eventname.split('_')[-1]
if SourceType == "video":
vpaths = get_video_pairs(eventpath) vpaths = get_video_pairs(eventpath)
elif SourceType == "image":
vpaths = get_image_pairs(eventpath)
event_tracks = [] event_tracks = []
for vpath in vpaths: for vpath in vpaths:
'''事件结果文件夹''' '''事件结果文件夹'''
save_dir_event = Path(savepath) / Path(eventname) save_dir_event = Path(savepath) / Path(eventname)
save_dir_img = save_dir_event / Path(str(Path(vpath).stem)) if isinstance(vpath, list):
if not save_dir_img.exists(): save_dir_video = save_dir_event / Path("images")
save_dir_img.mkdir(parents=True, exist_ok=True) 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''' '''Yolo + Resnet + Tracker'''
optdict["source"] = vpath optdict["source"] = vpath
optdict["save_dir"] = save_dir_img optdict["save_dir"] = save_dir_video
optdict["nosave"] = False optdict["is_save_img"] = True
optdict["is_save_video"] = True
tracksdict = yolo_resnet_tracker(**optdict) tracksdict = yolo_resnet_tracker(**optdict)
bboxes = tracksdict['TrackBoxes'] 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: if bname.split('_')[0] == "0" or bname.find('back')>=0:
vts = doFrontTracks(bboxes, tracksdict) vts = doBackTracks(bboxes, tracksdict)
vts.classify() vts.classify()
event_tracks.append(("back", vts)) event_tracks.append(("back", vts))
if bname.split('_')[0] == "1" or bname.find('front')>=0: if bname.split('_')[0] == "1" or bname.find('front')>=0:
vts = doBackTracks(bboxes, tracksdict) vts = doFrontTracks(bboxes, tracksdict)
vts.classify() vts.classify()
event_tracks.append(("front", vts)) event_tracks.append(("front", vts))
'''轨迹显示模块'''
illus = [None, None]
for CamerType, vts in event_tracks: for CamerType, vts in event_tracks:
if CamerType == 'back':
pass
if CamerType == 'front': 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: if stdfeat_path is not None:
with open(stdfeat_path, 'rb') as f: with open(stdfeat_path, 'rb') as f:
featDict = pickle.load(f) featDict = pickle.load(f)
def main_loop():
def main():
bcdpath = r"\\192.168.1.28\share\测试_202406\contrast\std_barcodes_2192" bcdpath = r"\\192.168.1.28\share\测试_202406\contrast\std_barcodes_2192"
eventpath = r"\\192.168.1.28\share\测试_202406\0918\images1" eventpath = r"\\192.168.1.28\share\测试_202406\0918\images1"
SourceType = "image" # video, image
barcodes = [] barcodes = []
input_enents = [] input_enents = []
output_events = [] output_events = []
# input_enents = get_interbcd_inputenents()
# k = 0
# for event in input_enents:
# pipeline(event)
# k += 1
# if k ==1:
# break
'''1. 获得barcode标准特征集列表''' '''1. 获得barcode标准特征集列表'''
for featname in os.listdir(bcdpath): for featname in os.listdir(bcdpath):
barcode, ext = os.path.splitext(featname) barcode, ext = os.path.splitext(featname)
@ -153,30 +159,29 @@ def main():
continue continue
barcodes.append(barcode) barcodes.append(barcode)
'''2. 构造(放入事件,标准特征)对'''
for filename in os.listdir(eventpath): for filename in os.listdir(eventpath):
'''barcode为时间文件夹的最后一个字段'''
bcd = filename.split('_')[-1] bcd = filename.split('_')[-1]
event_path = os.path.join(eventpath, filename) event_path = os.path.join(eventpath, filename)
stdfeat_path = None stdfeat_path = None
if bcd in barcodes: 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)) input_enents.append((event_path, stdfeat_path))
for eventpath, stdfeat_path in input_enents: 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)
@ -188,3 +193,9 @@ def main():
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -2,6 +2,8 @@
""" """
Created on Sun Sep 29 08:59:21 2024 Created on Sun Sep 29 08:59:21 2024
针对现场采集的视频利用算法pipeline提取运动轨迹内的subimg代替人工图像筛选、标注
@author: ym @author: ym
""" """
import os import os

451
time_devide.py Normal file
View File

@ -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 # 单位msCV状态和重力状态进行与运算时的时间间隔阈值
'''==================== 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)

View File

@ -150,6 +150,8 @@ def yolo_resnet_tracker(
save_crop=False, # save cropped prediction boxes save_crop=False, # save cropped prediction boxes
nosave=False, # do not save images/videos 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 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 vid_stride=1, # video frame-rate stride
data=ROOT / 'data/coco128.yaml', # dataset.yaml path data=ROOT / 'data/coco128.yaml', # dataset.yaml path
): ):
source = str(source) # source = str(source)
save_img = not nosave and not source.endswith('.txt') # save inference images
# Load model # Load model
device = select_device(device) device = select_device(device)
model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) 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 for i, det in enumerate(pred): # per image
im0 = im0s.copy() im0 = im0s.copy()
save_path = str(save_dir / Path(path).name) # im.jpg
s += '%gx%g ' % im.shape[2:] # print string s += '%gx%g ' % im.shape[2:] # print string
annotator = Annotator(im0.copy(), line_width=line_thickness, example=str(names)) 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) tracks = tracker.update(det_tracking, im0)
if len(tracks) == 0: if len(tracks) == 0:
continue continue
tracks[:, 7] = dataset.frame
if dataset.mode == "video":
frameId = dataset.frame
else:
frameId = dataset.count
tracks[:, 7] = frameId
'''================== 1. 存储 dets/subimgs/features Dict =============''' '''================== 1. 存储 dets/subimgs/features Dict ============='''
imgs, features = inference_image(im0, tracks) 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] imgdict.update({int(bid): imgs[ii]}) # [f"img_{int(bid)}"] = imgs[i]
boxdict.update({int(bid): tracks[ii, :]}) # [f"box_{int(bid)}"] = tracks[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, :] 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) track_boxes = np.concatenate([track_boxes, tracks], axis=0)
@ -257,19 +263,20 @@ def yolo_resnet_tracker(
color = colors(int(id), True) color = colors(int(id), True)
else: else:
color = colors(19, True) # 19为调色板的最后一个元素 color = colors(19, True) # 19为调色板的最后一个元素
annotator.box_label(xyxy, label, color=color) 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() im0 = annotator.result()
if is_save_img:
save_path_img, ext = os.path.splitext(save_path) save_path_img, ext = os.path.splitext(save_path)
if save_img: if dataset.mode == 'image':
# if dataset.mode == 'image': imgpath = save_path_img + ".png"
# imgpath = save_path_img + f"_{dataset}.png" else:
# else: imgpath = save_path_img + f"_{frameId}.png"
# imgpath = save_path_img + f"_{dataset.frame}.png" cv2.imwrite(Path(imgpath), im0)
# cv2.imwrite(Path(imgpath), im0)
if dataset.mode == 'video' and is_save_video:
if vid_path[i] != save_path: # new video if vid_path[i] != save_path: # new video
vid_path[i] = save_path vid_path[i] = save_path
if isinstance(vid_writer[i], cv2.VideoWriter): if isinstance(vid_writer[i], cv2.VideoWriter):
@ -396,8 +403,8 @@ def run(
imgshow = im0s.copy() imgshow = im0s.copy()
## ============================= tracking 功能只处理视频writed by WQG ## ============================= tracking 功能只处理视频writed by WQG
if dataset.mode == 'image': # if dataset.mode == 'image':
continue # continue
with dt[0]: with dt[0]:
im = torch.from_numpy(im).to(model.device) im = torch.from_numpy(im).to(model.device)
@ -482,7 +489,14 @@ def run(
tracks = tracker.update(det_tracking, im0) tracks = tracker.update(det_tracking, im0)
if len(tracks) == 0: if len(tracks) == 0:
continue 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 =============''' '''================== 1. 存储 dets/subimgs/features Dict ============='''
imgs, features = inference_image(im0, tracks) imgs, features = inference_image(im0, tracks)
@ -496,7 +510,7 @@ def run(
imgdict.update({int(bid): imgs[ii]}) # [f"img_{int(bid)}"] = imgs[i] imgdict.update({int(bid): imgs[ii]}) # [f"img_{int(bid)}"] = imgs[i]
boxdict.update({int(bid): tracks[ii, :]}) # [f"box_{int(bid)}"] = tracks[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, :] 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) track_boxes = np.concatenate([track_boxes, tracks], axis=0)
@ -535,7 +549,7 @@ def run(
if dataset.mode == 'image': if dataset.mode == 'image':
imgpath = save_path_img + f"_{dataset}.png" imgpath = save_path_img + f"_{dataset}.png"
else: else:
imgpath = save_path_img + f"_{dataset.frame}.png" imgpath = save_path_img + f"_{frameId}.png"
cv2.imwrite(Path(imgpath), im0) cv2.imwrite(Path(imgpath), im0)
@ -664,24 +678,38 @@ print('=======')
def main(opt): def main(opt):
check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop'))
p = r"D:\datasets\ym\永辉测试数据_202404\20240402"
optdict = vars(opt) optdict = vars(opt)
p = r"D:\datasets\ym"
p = r"D:\datasets\ym\exhibition\153112511_0_seek_105.mp4"
files = [] files = []
k = 0 k = 0
if os.path.isdir(p): if os.path.isdir(p):
files.extend(sorted(glob.glob(os.path.join(p, '*.*')))) files.extend(sorted(glob.glob(os.path.join(p, '*.*'))))
for file in files: for file in files:
optdict["source"] = file optdict["source"] = file
run(**optdict) run(**optdict)
k += 1 k += 1
if k == 2: if k == 1:
break break
elif os.path.isfile(p): elif os.path.isfile(p):
optdict["source"] = p
run(**vars(opt)) 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): def main_loop(opt):
check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop'))
@ -725,8 +753,9 @@ def main_loop(opt):
if __name__ == '__main__': if __name__ == '__main__':
opt = parse_opt() opt = parse_opt()
# main(opt) main(opt)
main_loop(opt) # main_imgdir(opt)
# main_loop(opt)

View File

@ -59,21 +59,21 @@ class ShoppingCart:
@property @property
def incart(self): 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) ret, binary = cv2.threshold(img, 250, 255, cv2.THRESH_BINARY)
return binary return binary
@property @property
def outcart(self): 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) ret, binary = cv2.threshold(img, 250, 255, cv2.THRESH_BINARY)
return binary return binary
@property @property
def cartedge(self): 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) ret, binary = cv2.threshold(img, 250, 255, cv2.THRESH_BINARY)
return binary return binary
@ -521,7 +521,6 @@ class doTracks:
return mergedTracks return mergedTracks
@staticmethod @staticmethod
def join_tracks(tlista, tlistb): def join_tracks(tlista, tlistb):
"""Combine two lists of stracks into a single one.""" """Combine two lists of stracks into a single one."""
@ -541,6 +540,93 @@ class doTracks:
def sub_tracks(tlista, tlistb): def sub_tracks(tlista, tlistb):
track_ids_b = {t.tid for t in tlistb} track_ids_b = {t.tid for t in tlistb}
return [t for t in tlista if t.tid not in track_ids_b] 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

View File

@ -5,8 +5,15 @@ Created on Mon Mar 4 18:36:31 2024
@author: ym @author: ym
""" """
import numpy as np import numpy as np
import cv2
from tracking.utils.mergetrack import track_equal_track from tracking.utils.mergetrack import track_equal_track
from scipy.spatial.distance import cdist 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 .dotracks import doTracks, ShoppingCart
from .track_back import backTrack from .track_back import backTrack
@ -19,9 +26,25 @@ class doBackTracks(doTracks):
self.tracks = [backTrack(b, f) for b, f in zip(self.lboxes, self.lfeats)] 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): def classify(self):
'''功能:对 tracks 中元素分类 ''' '''功能:对 tracks 中元素分类 '''

View File

@ -4,7 +4,13 @@ Created on Mon Mar 4 18:38:20 2024
@author: ym @author: ym
""" """
import cv2
import numpy as np 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 tracking.utils.mergetrack import track_equal_track
from .dotracks import doTracks from .dotracks import doTracks
from .track_front import frontTrack 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) for b in self.lboxes]
self.tracks = [frontTrack(b, f) for b, f in zip(self.lboxes, self.lfeats)] 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): def classify(self):
'''功能:对 tracks 中元素分类 ''' '''功能:对 tracks 中元素分类 '''

View File

@ -49,7 +49,7 @@ class backTrack(Track):
self.incartrates = incartrates''' self.incartrates = incartrates'''
self.compute_ious_feat() self.compute_ious_feat()
# self.PCA()
def isimgborder(self, BoundPixel=10, BoundThresh=0.3): def isimgborder(self, BoundPixel=10, BoundThresh=0.3):

View File

@ -5,9 +5,15 @@ Created on Mon Mar 4 18:33:01 2024
@author: ym @author: ym
""" """
import numpy as np import numpy as np
from sklearn.cluster import KMeans import cv2
# from sklearn.cluster import KMeans
from .dotracks import MoveState, Track from .dotracks import MoveState, Track
from pathlib import Path
curpath = Path(__file__).resolve().parents[0]
curpath = Path(curpath)
parpath = curpath.parent
class frontTrack(Track): class frontTrack(Track):
# boxes: [x1, y1, x2, y2, track_id, score, cls, frame_index, box_index] # boxes: [x1, y1, x2, y2, track_id, score, cls, frame_index, box_index]
@ -37,9 +43,6 @@ class frontTrack(Track):
self.CART_POSIT_0 = 430 self.CART_POSIT_0 = 430
self.CART_POSIT_1 = 620 self.CART_POSIT_1 = 620
def is_left_or_right_cornpoint(self): def is_left_or_right_cornpoint(self):
''' 基于 all(boxes) ''' 基于 all(boxes)
boxes左下角点和图像左下角点重叠 或 boxes左下角点和图像左下角点重叠 或

View File

@ -22,9 +22,9 @@ from tracking.dotrack.dotracks_back import doBackTracks
from tracking.dotrack.dotracks_front import doFrontTracks from tracking.dotrack.dotracks_front import doFrontTracks
from tracking.utils.drawtracks import plot_frameID_y2, draw_all_trajectories 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 from tracking.utils.annotator import TrackAnnotator
W, H = 1024, 1280 W, H = 1024, 1280
@ -32,6 +32,7 @@ Mode = 'front' #'back'
ImgFormat = ['.jpg', '.jpeg', '.png', '.bmp'] ImgFormat = ['.jpg', '.jpeg', '.png', '.bmp']
'''调用tracking()函数,利用本地跟踪算法获取各目标轨迹,可以比较本地跟踪算法与现场跟踪算法的区别。''' '''调用tracking()函数,利用本地跟踪算法获取各目标轨迹,可以比较本地跟踪算法与现场跟踪算法的区别。'''
def init_tracker(tracker_yaml = None, bs=1): 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) # trackerboxes, tracker_feat_dict = tracking(bboxes, ffeats)
'''1.3 分别构造 2 个文件夹,(1) 存储画框后的图像; (2) 运动轨迹对应的 boxes子图''' '''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') subimg_dir = os.path.join(savedir, event_name + '_subimgs')
if not os.path.exists(save_dir): if not os.path.exists(save_dir):
os.makedirs(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' ) subimg_path = os.path.join(subimg_dir, f'{CamerType}_tid{int(tid)}_{int(fid)}_{int(bid)}.png' )
cv2.imwrite(subimg_path, subimg) 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]
# subimg_path = os.path.join(subimg_dir, f'{CamerType}_tid{int(tid)}_{int(fid-1)}_{int(bid)}_x.png' ) for track in tracking_output_boxes:
# cv2.imwrite(subimg_path, subimg) 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'x_{CamerType}_tid{int(tid)}_{int(fid)}_{int(bid)}.png' )
cv2.imwrite(subimg_path, subimg)
return img_tracking, abimg return img_tracking, abimg
@ -267,9 +269,13 @@ def tracking_simulate(eventpath, savepath):
# else: # else:
# return # return
# ============================================================================= # =============================================================================
bname = os.path.basename(eventpath) enent_name = os.path.basename(eventpath)
idx = bname.find('2024')
enent_name = bname[idx:(idx+15)] ## 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 中数据,进行仿真''' '''2. 依次读取 0/1_track.data 中数据,进行仿真'''
illu_tracking, illu_select = [], [] illu_tracking, illu_select = [], []
@ -309,26 +315,33 @@ def tracking_simulate(eventpath, savepath):
Img_t = None Img_t = None
'''3.1 单独另存保存完好的 8 轨迹图''' '''3.1 保存输出轨迹图若tracking、select的shape相同则合并输出否则单独输出'''
basepath, _ = os.path.split(savepath) imgpath_tracking = os.path.join(savepath, enent_name + '_tracking.png')
trajpath = os.path.join(basepath, 'trajs') imgpath_select = os.path.join(savepath, enent_name + '_select.png')
if not os.path.exists(trajpath): imgpath_ts = os.path.join(savepath, enent_name + '_tracking_select.png')
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')
if Img_t is not None and Img_s is not None and np.all(Img_s.shape==Img_t.shape): 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) Img_ts = np.concatenate((Img_t, Img_s), axis = 1)
H, W = Img_ts.shape[:2] H, W = Img_ts.shape[:2]
cv2.line(Img_ts, (int(W/2), 0), (int(W/2), int(H)), (0, 0, 255), 4) 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(imgpath_ts, Img_ts)
cv2.imwrite(traj_path, Img_ts)
else: else:
if Img_s: cv2.imwrite(imgpath_select, Img_s) # 不会执行到该处 if Img_s: cv2.imwrite(imgpath_select, Img_s) # 不会执行到该处
if Img_t: cv2.imwrite(imgpath_tracking, Img_t) # 不会执行到该处 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) # warnings.simplefilter("error", category=np.VisibleDeprecationWarning)
def main_loop(): def main_loop():
del_barcode_file = r'\\192.168.1.28\share\测试_202406\0723\0723_3\deletedBarcode.txt' 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' # 测试数据文件夹地址 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 k = 0
for tuple_paths in relative_paths: for tuple_paths in relative_paths:
@ -383,12 +412,12 @@ def main():
SavePath: 包含二级目录,一级目录为轨迹图像;二级目录为与data文件对应的序列图像存储地址。 SavePath: 包含二级目录,一级目录为轨迹图像;二级目录为与data文件对应的序列图像存储地址。
''' '''
# eventPaths = r'\\192.168.1.28\share\测试_202406\0723\0723_3' # 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' savePath = r'D:\contrast\dataset\result'
k=0 k=0
for pathname in os.listdir(eventPaths): for pathname in os.listdir(eventPaths):
pathname = "20240925-142635-3e3cb61a-8bbe-45f2-aed7-a40de7f2d624_6924743924161" pathname = "放入薯片识别为辣条"
eventpath = os.path.join(eventPaths, pathname) eventpath = os.path.join(eventPaths, pathname)
savepath = os.path.join(savePath, pathname) savepath = os.path.join(savePath, pathname)
@ -396,6 +425,7 @@ def main():
os.makedirs(savepath) os.makedirs(savepath)
tracking_simulate(eventpath, savepath) tracking_simulate(eventpath, savepath)
# try: # try:
# tracking_simulate(eventpath, savepath) # tracking_simulate(eventpath, savepath)
# except Exception as e: # except Exception as e:

View File

@ -85,9 +85,7 @@ def have_tracked():
k = 0 k = 0
gt = Profile() gt = Profile()
for filename in os.listdir(trackdict): for filename in os.listdir(trackdict):
# filename = 'test_20240402-173935_6920152400975_back_174037372.pkl' filename = '153112511_0_seek_105.pkl'
# filename = '6907149227609_20240508-174733_back_returnGood_70f754088050_425_17327712807.pkl'
# filename = '6907149227609_20240508-174733_front_returnGood_70f754088050_425_17327712807.pkl'
file, ext = os.path.splitext(filename) file, ext = os.path.splitext(filename)
filepath = os.path.join(trackdict, filename) filepath = os.path.join(trackdict, filename)
@ -97,6 +95,9 @@ def have_tracked():
with gt: with gt:
if filename.find("front") >= 0: if filename.find("front") >= 0:
vts = doFrontTracks(bboxes, TracksDict) vts = doFrontTracks(bboxes, TracksDict)
Intrude = vts.isintrude()
vts.classify() vts.classify()
save_subimgs(vts, file, TracksDict) save_subimgs(vts, file, TracksDict)
@ -113,6 +114,9 @@ def have_tracked():
else: else:
vts = doBackTracks(bboxes, TracksDict) vts = doBackTracks(bboxes, TracksDict)
Intrude = vts.isintrude()
vts.classify() vts.classify()
alltracks.append(vts) alltracks.append(vts)
@ -124,9 +128,9 @@ def have_tracked():
cv2.imwrite(str(trackpath), img_tracking) cv2.imwrite(str(trackpath), img_tracking)
print(file+f" need time: {gt.dt:.2f}s") print(file+f" need time: {gt.dt:.2f}s")
# k += 1 k += 1
# if k==1: if k==1:
# break break
if len(alltracks): if len(alltracks):
drawFeatures(alltracks, save_dir) drawFeatures(alltracks, save_dir)

View File

@ -7,11 +7,13 @@ Created on Mon Jan 15 15:26:38 2024
import numpy as np import numpy as np
import cv2 import cv2
import os import os
from pathlib import Path
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from sklearn.decomposition import PCA from sklearn.decomposition import PCA
from utils.annotator import TrackAnnotator
from utils.plotting import colors from tracking.utils.annotator import TrackAnnotator
from pathlib import Path from tracking.utils.plotting import colors
def plot_frameID_y2(vts): def plot_frameID_y2(vts):

View File

@ -10,10 +10,10 @@ import numpy as np
import re import re
import os import os
from collections import OrderedDict from collections import OrderedDict
import warnings
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
def str_to_float_arr(s): def str_to_float_arr(s):
# 移除字符串末尾的逗号(如果存在) # 移除字符串末尾的逗号(如果存在)
if s.endswith(','): if s.endswith(','):
@ -31,7 +31,9 @@ def find_samebox_in_array(arr, target):
return i return i
return -1 return -1
import warnings
def extract_data(datapath): def extract_data(datapath):
@ -41,6 +43,9 @@ def extract_data(datapath):
trackerfeats = np.empty((0, 256), dtype=np.float64) trackerfeats = np.empty((0, 256), dtype=np.float64)
boxes, feats, tboxes, tfeats = [], [], [], [] boxes, feats, tboxes, tfeats = [], [], [], []
timestamps, frameIds = [], []
with open(datapath, 'r', encoding='utf-8') as lines: with open(datapath, 'r', encoding='utf-8') as lines:
for line in lines: for line in lines:
line = line.strip() # 去除行尾的换行符和可能的空白字符 line = line.strip() # 去除行尾的换行符和可能的空白字符
@ -50,22 +55,15 @@ def extract_data(datapath):
if line.find("CameraId")>=0: if line.find("CameraId")>=0:
if len(boxes): bboxes.append(np.array(boxes)) if len(boxes): bboxes.append(np.array(boxes))
if len(feats): ffeats.append(np.array(feats)) 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))) trackerboxes = np.concatenate((trackerboxes, np.array(tboxes)))
if len(tfeats): if len(tfeats):
trackerfeats = np.concatenate((trackerfeats, np.array(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 = [], [], [], [] boxes, feats, tboxes, tfeats = [], [], [], []
if line.find("box:") >= 0 and line.find("output_box:") < 0: if line.find("box:") >= 0 and line.find("output_box:") < 0:
@ -103,6 +101,9 @@ def extract_data(datapath):
assert(len(trackerboxes)==len(trackerfeats)), "Error at tracker output!" assert(len(trackerboxes)==len(trackerfeats)), "Error at tracker output!"
tracker_feat_dict = {} tracker_feat_dict = {}
tracker_feat_dict["timestamps"] = timestamps
tracker_feat_dict["frameIds"] = frameIds
for i in range(len(trackerboxes)): for i in range(len(trackerboxes)):
tid, fid, bid = int(trackerboxes[i, 4]), int(trackerboxes[i, 7]), int(trackerboxes[i, 8]) tid, fid, bid = int(trackerboxes[i, 4]), int(trackerboxes[i, 7]), int(trackerboxes[i, 8])
if f"frame_{fid}" not in tracker_feat_dict: 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) return np.array(boxes), np.array(feats)
def read_deletedBarcode_file(filePth): def read_deletedBarcode_file(filePath):
with open(filePth, 'r', encoding='utf-8') as f: with open(filePath, 'r', encoding='utf-8') as f:
lines = f.readlines() lines = f.readlines()
split_flag, all_list = False, [] split_flag, all_list = False, []
@ -179,6 +180,9 @@ def read_deletedBarcode_file(filePth):
clean_lines = [line.strip().replace("'", '').replace('"', '') for line in lines] clean_lines = [line.strip().replace("'", '').replace('"', '') for line in lines]
for i, line in enumerate(clean_lines): for i, line in enumerate(clean_lines):
if line.endswith(','):
line = line[:-1]
stripped_line = line.strip() stripped_line = line.strip()
if not stripped_line: if not stripped_line:
if len(barcode_list): dict['barcode'] = barcode_list if len(barcode_list): dict['barcode'] = barcode_list
@ -210,11 +214,106 @@ def read_deletedBarcode_file(filePth):
return all_list 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): def read_weight_timeConsuming(filePth):
WeightDict, SensorDict, ProcessTimeDict = OrderedDict(), OrderedDict(), OrderedDict() WeightDict, SensorDict, ProcessTimeDict = OrderedDict(), OrderedDict(), OrderedDict()
with open(filePth, 'r', encoding='utf-8') as f: with open(filePth, 'r', encoding='utf-8') as f:
lines = f.readlines() lines = f.readlines()
# label = ''
for i, line in enumerate(lines): for i, line in enumerate(lines):
line = line.strip() line = line.strip()

Binary file not shown.

View File

@ -257,6 +257,8 @@ class LoadImages:
videos = [x for x in files if x.split('.')[-1].lower() in VID_FORMATS] videos = [x for x in files if x.split('.')[-1].lower() in VID_FORMATS]
ni, nv = len(images), len(videos) ni, nv = len(images), len(videos)
self.img_size = img_size self.img_size = img_size
self.stride = stride self.stride = stride
self.files = images + videos self.files = images + videos

60
utils/getsource.py Normal file
View File

@ -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

View File

@ -1,4 +1,4 @@
个功能模块 个功能模块
1. Yolo + Tracker + Resnet, 其中 Resnet 的实现在./contrast中 1. Yolo + Tracker + Resnet, 其中 Resnet 的实现在./contrast中
track_reid.py track_reid.py
@ -12,7 +12,8 @@
3. 比对分析模块,目录为:./contrast 3. 比对分析模块,目录为:./contrast
2个场景1:11:n 2个场景1:11:n
1:1场景 1:1场景
(1) OneToOneCompare.txt (1) 利用现场保存数据进行比对
OneToOneCompare.txt现场保存数据
one2one_onsite.py one2one_onsite.py
(2) 利用本地算法进行特征提取 (2) 利用本地算法进行特征提取
one2one_contrast.py one2one_contrast.py
@ -23,6 +24,29 @@
feat_select.py 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
tracking_test.py tracking_test.py
@ -52,15 +76,16 @@
(d) 现场算法轨迹选择后的轨迹 (d) 现场算法轨迹选择后的轨迹
do_tracking(fpath, savedir, event_name) do_tracking(fpath, savedir, event_name)
inputs inputs
fpath: 0/1_track.data文件并核验是否存在 0/1_tracking_output.data若不存在该文件直接返回 None, None fpath: 0/1_track.data文件并核验是否存在 0/1_tracking_output.data若不存在该文件直接返回 None, None
savedir: 在该文件夹下会建立3个子文件夹及一个png轨迹图 savedir: 在该文件夹下会建立3个子文件夹及一个png轨迹图
./savedir/event_name ./savedir/event_name_images, 画boxes后的图像序列
./savedir/event_name_subimgs ./savedir/event_name_subimgs, 轨迹分析后的目标子图,无 _x 为PC机结果有 _x 为平板单摄像头轨迹选择后的输出
./savedir/trajectory ./savedir/trajectory, 存储每一个轨迹图
./savedir/event_name_ts.png ./savedir/event_name_tracking_select.png 或 enent_name_tracking.png 或 enent_name_select.png
outputs: outputs:
img_tracking本机tracker、tracking 输出的结果比较图 img_tracking本机tracker、tracking 输出的结果比较图
@ -127,3 +152,26 @@
循环读取不同文件夹中的 deletedBarcode.txt合并评估。 循环读取不同文件夹中的 deletedBarcode.txt合并评估。
main1(): main1():
指定deletedBarcode.txt进行1:n性能评估 指定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生成字典并进行存储