Files
detecttracking/contrast/contrast_one2one.py
2024-09-03 18:45:07 +08:00

474 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

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

# -*- coding: utf-8 -*-
"""
Created on Fri Aug 30 17:53:03 2024
1. 确认在相同CamerType下track.data 中 CamerID 项数量 = 图像数 = 帧ID数 = 最大帧ID
2. 读取0/1_tracking_output.data 中数据boxes、featslen(boxes)=len(feats)
帧ID约束
3. 优先选择前摄
4. 保存图像数据
5. 一次购物事件类型
shopEvent: {barcode:
type: getout, input
front_traj:[{imgpath: str,
box: arrar(1, 9),
feat: array(1, 256)
}]
back_traj: [{imgpath: str,
box: arrar(1, 9),
feat: array(1, 256)
}]
}
@author: ym
"""
import numpy as np
import cv2
import os
import sys
import pickle
import torch
import time
import json
from config import config as conf
from model import resnet18
from inference import load_contrast_model
from inference import featurize
sys.path.append(r"D:\DetectTracking")
from tracking.utils.read_data import extract_data, read_tracking_output, read_deletedBarcode_file
IMG_FORMAT = ['.bmp', '.jpg', '.jpeg', '.png']
model = load_contrast_model()
def creat_shopping_event(basePath, savePath, subimgPath=False):
eventList = []
'''一、构造放入商品事件列表'''
k = 0
for filename in os.listdir(basePath):
# filename = "20240723-155413_6904406215720"
'''filename下为一次购物事件'''
filepath = os.path.join(basePath, filename)
'''================ 0. 检查 filename 及 filepath 正确性和有效性 ================'''
nmlist = filename.split('_')
if filename.find('2024')<0 or len(nmlist)!=2 or len(nmlist[0])!=15 or len(nmlist[1])<11:
continue
if not os.path.isdir(filepath): continue
'''================ 1. 构造事件描述字典,暂定 9 items ==============='''
event = {}
event['barcode'] = nmlist[1]
event['type'] = 'input'
event['filepath'] = filepath
event['back_imgpaths'] = []
event['front_imgpaths'] = []
event['back_boxes'] = np.empty((0, 9), dtype=np.float64)
event['front_boxes'] = np.empty((0, 9), dtype=np.float64)
event['back_feats'] = np.empty((0, 256), dtype=np.float64)
event['front_feats'] = np.empty((0, 256), dtype=np.float64)
event['feats_compose'] = np.empty((0, 256), dtype=np.float64)
# event['feats_select'] = np.empty((0, 256), dtype=np.float64)
'''================= 2. 读取 data 文件 ============================='''
for dataname in os.listdir(filepath):
# filename = '1_track.data'
datapath = os.path.join(filepath, dataname)
if not os.path.isfile(datapath): continue
CamerType = dataname.split('_')[0]
''' 2.1 读取 0/1_track.data 中数据,暂不考虑'''
# if dataname.find("_track.data")>0:
# bboxes, ffeats, trackerboxes, tracker_feat_dict, trackingboxes, tracking_feat_dict = extract_data(datapath)
''' 2.2 读取 0/1_tracking_output.data 中数据'''
if dataname.find("_tracking_output.data")>0:
tracking_output_boxes, tracking_output_feats = read_tracking_output(datapath)
if len(tracking_output_boxes) != len(tracking_output_feats): continue
if CamerType == '0':
event['back_boxes'] = tracking_output_boxes
event['back_feats'] = tracking_output_feats
elif CamerType == '1':
event['front_boxes'] = tracking_output_boxes
event['front_feats'] = tracking_output_feats
'''2.3 事件的特征表征方式: 特征选择、特征集成'''
bk_feats = event['back_feats']
ft_feats = event['front_feats']
'''2.3.1 特征集成'''
feats_compose = np.empty((0, 256), dtype=np.float64)
if len(ft_feats):
feats_compose = np.concatenate((feats_compose, ft_feats), axis=0)
if len(bk_feats):
feats_compose = np.concatenate((feats_compose, bk_feats), axis=0)
event['feats_compose'] = feats_compose
'''2.3.1 特征选择'''
if len(ft_feats):
event['feats_select'] = ft_feats
pickpath = os.path.join(savePath, f"{filename}.pickle")
with open(pickpath, 'wb') as f:
pickle.dump(event, f)
print(f"Event: {filename}")
if subimgPath==False:
eventList.append(event)
continue
'''================ 2. 读取图像文件地址并按照帧ID排序 ============='''
frontImgs, frontFid = [], []
backImgs, backFid = [], []
for imgname in os.listdir(filepath):
name, ext = os.path.splitext(imgname)
if ext not in IMG_FORMAT or name.find('frameId')<0: continue
CamerType = name.split('_')[0]
frameId = int(name.split('_')[3])
imgpath = os.path.join(filepath, imgname)
if CamerType == '0':
backImgs.append(imgpath)
backFid.append(frameId)
if CamerType == '1':
frontImgs.append(imgpath)
frontFid.append(frameId)
frontIdx = np.argsort(np.array(frontFid))
backIdx = np.argsort(np.array(backFid))
'''2.1 生成依据帧 ID 排序的前后摄图像地址列表'''
frontImgs = [frontImgs[i] for i in frontIdx]
backImgs = [backImgs[i] for i in backIdx]
'''2.2 将前、后摄图像路径添加至事件字典'''
bfid = event['back_boxes'][:, 7].astype(np.int64)
ffid = event['front_boxes'][:, 7].astype(np.int64)
if len(bfid) and max(bfid) <= len(backImgs):
event['back_imgpaths'] = [backImgs[i-1] for i in bfid]
if len(ffid) and max(ffid) <= len(frontImgs):
event['front_imgpaths'] = [frontImgs[i-1] for i in ffid]
'''================ 3. 判断当前事件有效性,并添加至事件列表 =========='''
condt1 = len(event['back_imgpaths'])==0 or len(event['front_imgpaths'])==0
condt2 = len(event['front_feats'])==0 and len(event['back_feats'])==0
if condt1 or condt2:
print(f" Error, condt1: {condt1}, condt2: {condt2}")
continue
eventList.append(event)
# k += 1
# if k==1:
# continue
'''一、构造放入商品事件列表,暂不处理'''
# delepath = os.path.join(basePath, 'deletedBarcode.txt')
# bcdList = read_deletedBarcode_file(delepath)
# for slist in bcdList:
# getoutFold = slist['SeqDir'].strip()
# getoutPath = os.path.join(basePath, getoutFold)
# '''取出事件文件夹不存在,跳出循环'''
# if not os.path.exists(getoutPath) and not os.path.isdir(getoutPath):
# continue
# ''' 生成取出事件字典 '''
# event = {}
# event['barcode'] = slist['Deleted'].strip()
# event['type'] = 'getout'
# event['basePath'] = getoutPath
return eventList
def get_std_barcodeDict(bcdpath, bpath):
'''
inputs:
bcdpath: 已清洗的barcode样本图像如果barcode下有'base'文件夹,只选用该文件夹下图像
(default = r'\\192.168.1.28\share\已标注数据备份\对比数据\barcode\barcode_1771')
功能:
生成并保存只有一个key值的字典 {barcode: [imgpath1, imgpath1, ...]}
bpath: 字典存储地址
'''
# bpath = r'\\192.168.1.28\share\测试_202406\contrast\barcodes'
'''读取数据集中 barcode 列表'''
stdBlist = []
for filename in os.listdir(bcdpath):
filepath = os.path.join(bcdpath, filename)
if not os.path.isdir(filepath) or not filename.isdigit(): continue
stdBlist.append(filename)
bcdpaths = [(barcode, os.path.join(bcdpath, barcode)) for barcode in stdBlist]
'''遍历数据集针对每一个barcode生成并保存字典{barcode: [imgpath1, imgpath1, ...]}'''
k = 0
for barcode, bpath in bcdpaths:
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)
_, 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(bpath, f"{barcode}.pickle")
with open(pickpath, 'wb') as f:
pickle.dump(stdBarcodeDict, f)
print(f"Barcode: {barcode}")
# k += 1
# if k == 10:
# break
return
def extract_save_trajture_subimgs(shoppingEventPath, shoppingFeatPath, subimgPath):
'''用于保存一次购物事件的轨迹图像子图'''
shoppingFeatPath = r"\\192.168.1.28\share\测试_202406\contrast\events"
subimgPath = r'\\192.168.1.28\share\测试_202406\contrast\subimgs'
eventList = creat_shopping_event(shoppingEventPath, shoppingFeatPath, subimgPath=True)
print("======= eventList have generated and features have saved! =======")
barcodeDict = {}
for event in eventList:
'''9 items: barcode, type, filepath, back_imgpaths, front_imgpaths,
back_boxes, front_boxes, back_feats, front_feats
'''
if len(event['feats_select']):
event_feats = event['feats_select']
elif len(event['back_feats']):
event_feats = event['back_feats']
else:
continue
'''保存一次购物事件的轨迹子图'''
basename = os.path.basename(event['filepath'])
spath = os.path.join(subimgPath, basename)
if not os.path.exists(spath):
os.makedirs(spath)
cameras = ('front', 'back')
for camera in cameras:
if camera == 'front':
boxes = event['front_boxes']
imgpaths = event['front_imgpaths']
else:
boxes = event['back_boxes']
imgpaths = event['back_imgpaths']
for i, box in enumerate(boxes):
x1, y1, x2, y2, tid, score, cls, fid, bid = box
imgpath = imgpaths[i]
image = cv2.imread(imgpath)
subimg = image[int(y1/2):int(y2/2), int(x1/2):int(x2/2), :]
camerType, timeTamp, _, frameID = os.path.basename(imgpath).split('.')[0].split('_')
subimgName = f"{camerType}_{tid}_fid({fid}, {frameID}).png"
subimgPath = os.path.join(spath, subimgName)
cv2.imwrite(subimgPath, subimg)
print(f"Image saved: {basename}")
def batch_inference(imgpaths, batch):
size = len(imgpaths)
groups = []
for i in range(0, size, batch):
end = min(batch + i, size)
groups.append(imgpaths[i: end])
features = []
for group in groups:
feature = featurize(group, conf.test_transform, model, conf.device)
features.append(feature)
features = np.concatenate(features, axis=0)
return features
def stdfeat_infer(imgPath, featPath):
'''
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\barcodes"
# featPath = r"\\192.168.1.28\share\测试_202406\contrast\features"
stdBarcodeDict = {}
k = 0
for filename in os.listdir(imgPath):
filepath = os.path.join(imgPath, filename)
stdbDict = {}
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)
except Exception as e:
print(f"Error accured at: {filename}, with Exception is: {e}")
'''================ 保存单个barcode特征 ================'''
stdbDict[barcode] = feature
pkpath = os.path.join(featPath, f"{barcode}.pickle")
with open(pkpath, 'wb') as f:
pickle.dump(stdbDict, f)
stdBarcodeDict[barcode] = feature
t2 = time.time()
print(f"Barcode: {barcode}, need time: {t2-t1:.1f} secs")
k += 1
if k == 10:
break
pickpath = os.path.join(featPath, f"barcode_features_{k}.pickle")
with open(pickpath, 'wb') as f:
pickle.dump(stdBarcodeDict, f)
def contrast_performance_evaluate():
eventFeatPath = r"\\192.168.1.28\share\测试_202406\contrast\events"
stdFeatPath = r"\\192.168.1.28\share\测试_202406\contrast\features"
def generate_event_and_standard_features():
stdSamplePath = r"\\192.168.1.28\share\已标注数据备份\对比数据\barcode\barcode_1771"
stdBarcodePath = r"\\192.168.1.28\share\测试_202406\contrast\barcodes"
stdFeaturePath = r"\\192.168.1.28\share\测试_202406\contrast\features"
'''=========================== 1. 生成标准特征集 ========================'''
'''1.1 提取并保存标准特征库原始图像文件地址字典'''
# get_std_barcodeDict(stdSamplePath, stdBarcodePath)
# print("standard imgpath have extracted and saved")
'''1.2 特征提取,并保存至文件夹 stdFeaturePath 中'''
stdfeat_infer(stdBarcodePath, stdFeaturePath)
# print("standard features have generated!")
'''=========================== 2. 提取并存储事件特征 ========================'''
shoppingEventPath = [r'\\192.168.1.28\share\测试_202406\0723\0723_1',
r'\\192.168.1.28\share\测试_202406\0723\0723_2',
r'\\192.168.1.28\share\测试_202406\0723\0723_3',
r'\\192.168.1.28\share\测试_202406\0722\0722_01',
r'\\192.168.1.28\share\测试_202406\0722\0722_02']
shoppingFeatPath = r"\\192.168.1.28\share\测试_202406\contrast\events"
# for sPath in shoppingEventPath:
# eventList = creat_shopping_event(sPath, shoppingFeatPath)
def shopping_event_test():
fplist = [#r'\\192.168.1.28\share\测试_202406\0723\0723_1',
#r'\\192.168.1.28\share\测试_202406\0723\0723_2',
r'\\192.168.1.28\share\测试_202406\0723\0723_3',
#r'\\192.168.1.28\share\测试_202406\0722\0722_01',
#r'\\192.168.1.28\share\测试_202406\0722\0722_02'
]
shoppingFeatPath = r"\\192.168.1.28\share\测试_202406\contrast\events"
subimgPath = r'\\192.168.1.28\share\测试_202406\contrast\subimgs'
for filepath in fplist:
'''用于保存一次购物事件的轨迹轨迹特征、及对应的图像子图'''
extract_save_trajture_subimgs(filepath, shoppingFeatPath, subimgPath)
def main():
generate_event_and_standard_features()
# shopping_event_test()
pass
if __name__ == '__main__':
main()