更新 detacttracking

This commit is contained in:
lee
2025-01-22 13:16:44 +08:00
parent 2320468c40
commit c9d79f8059
355 changed files with 61097 additions and 1 deletions

View File

@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
"""
Created on Thu Sep 26 08:53:58 2024
@author: ym
"""

View File

@ -0,0 +1,352 @@
# -*- coding: utf-8 -*-
"""
Created on Mon Dec 16 18:56:18 2024
@author: ym
"""
import os
import cv2
import json
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rcParams
from matplotlib.font_manager import FontProperties
from scipy.spatial.distance import cdist
from utils.event import ShoppingEvent, save_data
rcParams['font.sans-serif'] = ['SimHei'] # 用黑体显示中文
rcParams['axes.unicode_minus'] = False # 正确显示负号
'''*********** USearch ***********'''
def read_usearch():
stdFeaturePath = r"D:\contrast\stdlib\v11_test.json"
stdBarcode = []
stdlib = {}
with open(stdFeaturePath, 'r', encoding='utf-8') as f:
data = json.load(f)
for dic in data['total']:
barcode = dic['key']
feature = np.array(dic['value'])
stdBarcode.append(barcode)
stdlib[barcode] = feature
return stdlib
def get_eventlist():
'''
读取一次测试中的错误事件
'''
evtpaths = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\images"
text1 = "one2n_Error.txt"
text2 = "one2SN_Error.txt"
events = []
text = (text1, text2)
for txt in text:
txtfile = os.path.join(evtpaths, txt)
with open(txtfile, "r") as f:
lines = f.readlines()
for i, line in enumerate(lines):
line = line.strip()
if line:
fpath=os.path.join(evtpaths, line)
events.append(fpath)
events = list(set(events))
return events
def single_event():
events = get_eventlist()
'''定义当前事件存储地址及生成相应文件件'''
resultPath = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\result\single_event"
for evtpath in events:
event = ShoppingEvent(evtpath)
save_data(event, resultPath)
print(event.evtname)
def get_topk_percent(data, k):
"""
获取数据中最大的 k% 的元素
"""
# 将数据转换为 NumPy 数组
if isinstance(data, list):
data = np.array(data)
percentile = np.percentile(data, 100-k)
top_k_percent = data[data >= percentile]
return top_k_percent
def cluster(data, thresh=0.15):
# data = np.array([0.1, 0.13, 0.7, 0.2, 0.8, 0.52, 0.3, 0.7, 0.85, 0.58])
# data = np.array([0.1, 0.13, 0.2, 0.3])
# data = np.array([0.1])
if isinstance(data, list):
data = np.array(data)
data1 = np.sort(data)
cluter, Cluters, = [data1[0]], []
for i in range(1, len(data1)):
if data1[i] - data1[i-1]< thresh:
cluter.append(data1[i])
else:
Cluters.append(cluter)
cluter = [data1[i]]
Cluters.append(cluter)
clt_center = []
for clt in Cluters:
## 是否应该在此处限制一个聚类中的最小轨迹样本数,应该将该因素放在轨迹分析中
# if len(clt)>=3:
# clt_center.append(np.mean(clt))
clt_center.append(np.mean(clt))
# print(clt_center)
return clt_center
def calc_simil(event, stdfeat):
def calsiml(feat1, feat2):
'''轨迹样本和标准特征集样本相似度的选择策略'''
matrix = 1 - cdist(feat1, feat2, 'cosine')
simi_max = []
for i in range(len(matrix)):
sim = np.mean(get_topk_percent(matrix[i, :], 75))
simi_max.append(sim)
cltc_max = cluster(simi_max)
Simi = max(cltc_max)
## cltc_max为空属于编程考虑不周应予以排查解决
# if len(cltc_max):
# Simi = max(cltc_max)
# else:
# Simi = 0 #不应该走到该处
return Simi
front_boxes = np.empty((0, 9), dtype=np.float64) ##和类doTracks兼容
front_feats = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容
for i in range(len(event.front_boxes)):
front_boxes = np.concatenate((front_boxes, event.front_boxes[i]), axis=0)
front_feats = np.concatenate((front_feats, event.front_feats[i]), axis=0)
back_boxes = np.empty((0, 9), dtype=np.float64) ##和类doTracks兼容
back_feats = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容
for i in range(len(event.back_boxes)):
back_boxes = np.concatenate((back_boxes, event.back_boxes[i]), axis=0)
back_feats = np.concatenate((back_feats, event.back_feats[i]), axis=0)
if len(front_feats):
front_simi = calsiml(front_feats, stdfeat)
if len(back_feats):
back_simi = calsiml(back_feats, stdfeat)
'''前后摄相似度融合策略'''
if len(front_feats) and len(back_feats):
diff_simi = abs(front_simi - back_simi)
if diff_simi>0.15:
Similar = max([front_simi, back_simi])
else:
Similar = (front_simi+back_simi)/2
elif len(front_feats) and len(back_feats)==0:
Similar = front_simi
elif len(front_feats)==0 and len(back_feats):
Similar = back_simi
else:
Similar = None # 在event.front_feats和event.back_feats同时为空时
return Similar
def simi_matrix():
resultPath = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\result\single_event"
stdlib = read_usearch()
events = get_eventlist()
for evtpath in events:
evtname = os.path.basename(evtpath)
_, barcode = evtname.split("_")
# 生成事件与相应标准特征集
event = ShoppingEvent(evtpath)
stdfeat = stdlib[barcode]
Similar = calc_simil(event, stdfeat)
# 构造 boxes 子图存储路径
subimgpath = os.path.join(resultPath, f"{event.evtname}", "subimg")
if not os.path.exists(subimgpath):
os.makedirs(subimgpath)
histpath = os.path.join(resultPath, "simi_hist")
if not os.path.exists(histpath):
os.makedirs(histpath)
mean_values, max_values = [], []
cameras = ('front', 'back')
fig, ax = plt.subplots(2, 3, figsize=(16, 9), dpi=100)
kpercent = 25
for camera in cameras:
boxes = np.empty((0, 9), dtype=np.float64) ##和类doTracks兼容
evtfeat = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容
if camera == 'front':
for i in range(len(event.front_boxes)):
boxes = np.concatenate((boxes, event.front_boxes[i]), axis=0)
evtfeat = np.concatenate((evtfeat, event.front_feats[i]), axis=0)
imgpaths = event.front_imgpaths
else:
for i in range(len(event.back_boxes)):
boxes = np.concatenate((boxes, event.back_boxes[i]), axis=0)
evtfeat = np.concatenate((evtfeat, event.back_feats[i]), axis=0)
imgpaths = event.back_imgpaths
assert len(boxes)==len(evtfeat), f"Please check the Event: {evtname}"
if len(boxes)==0: continue
print(evtname)
matrix = 1 - cdist(evtfeat, stdfeat, 'cosine')
simi_1d = matrix.flatten()
simi_mean = np.mean(matrix, axis=1)
# simi_max = np.max(matrix, axis=1)
'''以相似度矩阵每一行最大的 k% 的相似度做均值计算'''
simi_max = []
for i in range(len(matrix)):
sim = np.mean(get_topk_percent(matrix[i, :], kpercent))
simi_max.append(sim)
mean_values.append(np.mean(matrix))
max_values.append(np.mean(simi_max))
diff_max_mean = np.mean(simi_max) - np.mean(matrix)
'''相似度统计特性图示'''
k =0
if camera == 'front': k = 1
'''********************* 相似度全体数据 *********************'''
ax[k, 0].hist(simi_1d, bins=60, range=(-0.2, 1), edgecolor='black')
ax[k, 0].set_xlim([-0.2, 1])
ax[k, 0].set_title(camera)
_, y_max = ax[k, 0].get_ylim() # 获取y轴范围
'''相似度变动范围'''
ax[k, 0].text(-0.1, 0.15*y_max, f"rng:{max(simi_1d)-min(simi_1d):.3f}", fontsize=18, color='b')
'''********************* 均值********************************'''
ax[k, 1].hist(simi_mean, bins=24, range=(-0.2, 1), edgecolor='black')
ax[k, 1].set_xlim([-0.2, 1])
ax[k, 1].set_title("mean")
_, y_max = ax[k, 1].get_ylim() # 获取y轴范围
'''相似度变动范围'''
ax[k, 1].text(-0.1, 0.15*y_max, f"rng:{max(simi_mean)-min(simi_mean):.3f}", fontsize=18, color='b')
'''********************* 最大值 ******************************'''
ax[k, 2].hist(simi_max, bins=24, range=(-0.2, 1), edgecolor='black')
ax[k, 2].set_xlim([-0.2, 1])
ax[k, 2].set_title("max")
_, y_max = ax[k, 2].get_ylim() # 获取y轴范围
'''相似度变动范围'''
ax[k, 2].text(-0.1, 0.15*y_max, f"rng:{max(simi_max)-min(simi_max):.3f}", fontsize=18, color='b')
'''绘制聚类中心'''
cltc_mean = cluster(simi_mean)
for value in cltc_mean:
ax[k, 1].axvline(x=value, color='m', linestyle='--', linewidth=3)
cltc_max = cluster(simi_max)
for value in cltc_max:
ax[k, 2].axvline(x=value, color='m', linestyle='--', linewidth=3)
'''绘制相似度均值与最大值均值'''
ax[k, 1].axvline(x=np.mean(matrix), color='r', linestyle='-', linewidth=3)
ax[k, 2].axvline(x=np.mean(simi_max), color='g', linestyle='-', linewidth=3)
'''绘制相似度最大值均值 - 均值'''
_, y_max = ax[k, 2].get_ylim() # 获取y轴范围
ax[k, 2].text(-0.1, 0.05*y_max, f"g-r={diff_max_mean:.3f}", fontsize=18, color='m')
plt.show()
# for i, box in enumerate(boxes):
# x1, y1, x2, y2, tid, score, cls, fid, bid = box
# imgpath = imgpaths[int(fid-1)]
# image = cv2.imread(imgpath)
# subimg = image[int(y1/2):int(y2/2), int(x1/2):int(x2/2), :]
# camerType, timeTamp, _, frameID = os.path.basename(imgpath).split('.')[0].split('_')
# subimgName = f"cam{camerType}_{i}_tid{int(tid)}_fid({int(fid)}, {frameID})_{simi_mean[i]:.3f}.png"
# imgpairs.append((subimgName, subimg))
# spath = os.path.join(subimgpath, subimgName)
# cv2.imwrite(spath, subimg)
# oldname = f"cam{camerType}_{i}_tid{int(tid)}_fid({int(fid)}, {frameID}).png"
# oldpath = os.path.join(subimgpath, oldname)
# if os.path.exists(oldpath):
# os.remove(oldpath)
if len(mean_values)==2:
mean_diff = abs(mean_values[1]-mean_values[0])
ax[0, 1].set_title(f"mean diff: {mean_diff:.3f}")
if len(max_values)==2:
max_values = abs(max_values[1]-max_values[0])
ax[0, 2].set_title(f"max diff: {max_values:.3f}")
try:
fig.suptitle(f"Similar: {Similar:.3f}", fontsize=16)
except Exception as e:
print(e)
print(f"Similar: {Similar}")
pltpath = os.path.join(subimgpath, f"hist_max_{kpercent}%_.png")
plt.savefig(pltpath)
pltpath1 = os.path.join(histpath, f"{evtname}_.png")
plt.savefig(pltpath1)
plt.close()
def main():
simi_matrix()
if __name__ == "__main__":
main()
# cluster()

View File

@ -0,0 +1,87 @@
# import torch
# import torchvision.transforms as T
#
#
# class Config:
# # network settings
# backbone = 'resnet18' # [resnet18, mobilevit_s, mobilenet_v2, mobilenetv3_small, mobilenetv3_large, mobilenet_v1, PPLCNET_x1_0, PPLCNET_x0_5, PPLCNET_x2_5]
# metric = 'arcface' # [cosface, arcface]
# cbam = True
# embedding_size = 256
# drop_ratio = 0.5
# img_size = 224
#
# batch_size = 8
#
# # data preprocess
# # input_shape = [1, 128, 128]
# """transforms.RandomCrop(size),
# transforms.RandomVerticalFlip(p=0.5),
# transforms.RandomHorizontalFlip(),
# RandomRotate(15, 0.3),
# # RandomGaussianBlur()"""
#
# train_transform = T.Compose([
# T.ToTensor(),
# T.Resize((img_size, img_size)),
# # T.RandomCrop(img_size),
# # T.RandomHorizontalFlip(p=0.5),
# T.RandomRotation(180),
# T.ColorJitter(brightness=0.5),
# T.ConvertImageDtype(torch.float32),
# T.Normalize(mean=[0.5], std=[0.5]),
# ])
# test_transform = T.Compose([
# T.ToTensor(),
# T.Resize((img_size, img_size)),
# T.ConvertImageDtype(torch.float32),
# T.Normalize(mean=[0.5], std=[0.5]),
# ])
#
# # dataset
# train_root = './data/2250_train/train' # 初始筛选过一次的数据集
# # train_root = './data/0612_train/train'
# test_root = "./data/2250_train/val/"
# # test_root = "./data/0612_train/val"
# test_list = "./data/2250_train/val_pair.txt"
#
# test_group_json = "./2250_train/cross_same_0508.json"
#
#
# # test_list = "./data/test_data_100/val_pair.txt"
#
# # training settings
# checkpoints = "checkpoints/resnet18_0613/" # [resnet18, mobilevit_s, mobilenet_v2, mobilenetv3]
# restore = False
# # restore_model = "checkpoints/renet18_2250_0315/best_resnet18_2250_0315.pth" # best_resnet18_1491_0306.pth
# restore_model = "checkpoints/resnet18_0515/best.pth" # best_resnet18_1491_0306.pth
#
# # test_model = "checkpoints/renet18_2250_0314/best_resnet18_2250_0314.pth"
# testbackbone = 'resnet18' # [resnet18, mobilevit_s, mobilenet_v2, mobilenetv3_small, mobilenetv3_large, mobilenet_v1, PPLCNET_x1_0, PPLCNET_x0_5]
# test_val = "D:/比对/cl"
# # test_val = "./data/test_data_100"
#
# # test_model = "checkpoints/zhanting_res_801.pth"
# test_model = "checkpoints/resnet18_0515/v11.pth"
#
#
#
# train_batch_size = 512 # 256
# test_batch_size = 256 # 256
#
# epoch = 300
# optimizer = 'sgd' # ['sgd', 'adam']
# lr = 1.5e-2 # 1e-2
# lr_step = 5 # 10
# lr_decay = 0.95 # 0.98
# weight_decay = 5e-4
# loss = 'cross_entropy' # ['focal_loss', 'cross_entropy']
# # device = torch.device('cuda:1' if torch.cuda.is_available() else 'cpu')
# device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
#
# pin_memory = True # if memory is large, set it True to speed up a bit
# num_workers = 4 # dataloader
#
# group_test = True
#
# config = Config()

View File

@ -0,0 +1,547 @@
# -*- coding: utf-8 -*-
"""
@author: LiChen
"""
import numpy as np
import torch
from pathlib import Path
from utils.config import config as cfg
curpath = Path(__file__).resolve().parents[0]
class FeatsInterface:
def __init__(self, resnetModel=None):
self.device = cfg.device
self.transform = cfg.test_transform
self.batch_size = cfg.batch_size
self.embedding_size = cfg.embedding_size
assert resnetModel is not None, "resnetModel is None"
self.model = resnetModel
print(f"Model type: {type(self.model)}")
def inference(self, images, detections=None):
'''
如果是BGR需要转变为RGB格式
'''
if isinstance(images, np.ndarray):
imgs, features = self.inference_image(images, detections)
return imgs, features
batch_patches = []
patches = []
for i, img in enumerate(images):
img = img.copy()
patch = self.transform(img)
if str(self.device) != "cpu":
# patch = patch.to(device=self.device).half()
patch = patch.to(device=self.device)
else:
patch = patch.to(device=self.device)
patches.append(patch)
if (i + 1) % self.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, self.embedding_size))
for patches in batch_patches:
pred = self.model(patches)
pred[torch.isinf(pred)] = 1.0
feat = pred.cpu().data.numpy()
features = np.vstack((features, feat))
return features
def inference_image(self, image, detections):
H, W, _ = np.shape(image)
batch_patches = []
patches = []
imgs = []
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])
img = image[tlbr[1]:tlbr[3], tlbr[0]:tlbr[2], :]
imgs.append(img)
img1 = img[:, :, ::-1].copy() # the model expects RGB inputs
patch = self.transform(img1)
# patch = patch.to(device=self.device).half()
if str(self.device) != "cpu":
# patch = patch.to(device=self.device).half()
patch = patch.to(device=self.device)
else:
patch = patch.to(device=self.device)
patches.append(patch)
if (d + 1) % self.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, self.embedding_size))
for patches in batch_patches:
pred = self.model(patches)
pred[torch.isinf(pred)] = 1.0
feat = pred.cpu().data.numpy()
features = np.vstack((features, feat))
return imgs, features
# def unique_image(pair_list) -> set:
# """Return unique image path in pair_list.txt"""
# with open(pair_list, 'r') as fd:
# pairs = fd.readlines()
# unique = set()
# for pair in pairs:
# id1, id2, _ = pair.split()
# unique.add(id1)
# unique.add(id2)
# return unique
#
#
# def group_image(images: set, batch) -> list:
# """Group image paths by batch size"""
# images = list(images)
# size = len(images)
# res = []
# for i in range(0, size, batch):
# end = min(batch + i, size)
# res.append(images[i: end])
# return res
#
#
# def _preprocess(images: list, transform) -> torch.Tensor:
# res = []
# for img in images:
# im = Image.open(img)
# im = transform(im)
# res.append(im)
# # data = torch.cat(res, dim=0) # shape: (batch, 128, 128)
# # data = data[:, None, :, :] # shape: (batch, 1, 128, 128)
# data = torch.stack(res)
# return data
#
#
# def test_preprocess(images: list, transform) -> torch.Tensor:
# res = []
# for img in images:
# im = Image.open(img)
# im = transform(im)
# res.append(im)
# # data = torch.cat(res, dim=0) # shape: (batch, 128, 128)
# # data = data[:, None, :, :] # shape: (batch, 1, 128, 128)
# data = torch.stack(res)
# return data
#
#
# def featurize(images: list, transform, net, device, train=False) -> dict:
# """featurize each image and save into a dictionary
# Args:
# images: image paths
# transform: test transform
# net: pretrained model
# device: cpu or cuda
# Returns:
# Dict (key: imagePath, value: feature)
# """
# if train:
# data = _preprocess(images, transform)
# data = data.to(device)
# net = net.to(device)
# with torch.no_grad():
# features = net(data)
# res = {img: feature for (img, feature) in zip(images, features)}
# else:
# data = test_preprocess(images, transform)
# data = data.to(device)
# net = net.to(device)
# with torch.no_grad():
# features = net(data)
# res = {img: feature for (img, feature) in zip(images, features)}
# return res
#
#
# # def inference_image(images: list, transform, net, device, bs=16, embedding_size=256) -> dict:
# # batch_patches = []
# # patches = []
# # for d, img in enumerate(images):
# # img = Image.open(img)
# # patch = transform(img)
#
# # if str(device) != "cpu":
# # patch = patch.to(device).half()
# # else:
# # patch = patch.to(device)
#
# # patches.append(patch)
# # if (d + 1) % bs == 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, embedding_size), dtype=np.float32)
# # for patches in batch_patches:
# # pred = net(patches)
# # pred[torch.isinf(pred)] = 1.0
# # feat = pred.cpu().data.numpy()
# # features = np.vstack((features, feat))
#
#
# # return features
#
#
# def featurize_1(images: list, transform, net, device, train=False) -> dict:
# """featurize each image and save into a dictionary
# Args:
# images: image paths
# transform: test transform
# net: pretrained model
# device: cpu or cuda
# Returns:
# Dict (key: imagePath, value: feature)
# """
#
# data = test_preprocess(images, transform)
# data = data.to(device)
# net = net.to(device)
# with torch.no_grad():
# features = net(data).data.numpy()
#
# return features
#
#
# def cosin_metric(x1, x2):
# return np.dot(x1, x2) / (np.linalg.norm(x1) * np.linalg.norm(x2))
#
#
# def threshold_search(y_score, y_true):
# y_score = np.asarray(y_score)
# y_true = np.asarray(y_true)
# best_acc = 0
# best_th = 0
# for i in range(len(y_score)):
# th = y_score[i]
# y_test = (y_score >= th)
# acc = np.mean((y_test == y_true).astype(int))
# if acc > best_acc:
# best_acc = acc
# best_th = th
# return best_acc, best_th
#
#
# def showgrid(recall, recall_TN, PrecisePos, PreciseNeg):
# x = np.linspace(start=-1.0, stop=1.0, num=50, endpoint=True).tolist()
# plt.figure(figsize=(10, 6))
# plt.plot(x, recall, color='red', label='recall')
# plt.plot(x, recall_TN, color='black', label='recall_TN')
# plt.plot(x, PrecisePos, color='blue', label='PrecisePos')
# plt.plot(x, PreciseNeg, color='green', label='PreciseNeg')
# plt.legend()
# plt.xlabel('threshold')
# # plt.ylabel('Similarity')
# plt.grid(True, linestyle='--', alpha=0.5)
# plt.savefig('accuracy_recall_grid.png')
# plt.show()
# plt.close()
#
#
# def compute_accuracy_recall(score, labels):
# th = 0.1
# squence = np.linspace(-1, 1, num=50)
# # squence = [0.4]
# recall, PrecisePos, PreciseNeg, recall_TN = [], [], [], []
# for th in squence:
# t_score = (score > th)
# t_labels = (labels == 1)
# # print(t_score)
# # print(t_labels)
# TP = np.sum(np.logical_and(t_score, t_labels))
# FN = np.sum(np.logical_and(np.logical_not(t_score), t_labels))
# f_score = (score < th)
# f_labels = (labels == 0)
# TN = np.sum(np.logical_and(f_score, f_labels))
# FP = np.sum(np.logical_and(np.logical_not(f_score), f_labels))
# print("Threshold:{} TP:{},FP:{},TN:{},FN:{}".format(th, TP, FP, TN, FN))
#
# PrecisePos.append(0 if TP / (TP + FP) == 'nan' else TP / (TP + FP))
# PreciseNeg.append(0 if TN == 0 else TN / (TN + FN))
# recall.append(0 if TP == 0 else TP / (TP + FN))
# recall_TN.append(0 if TN == 0 else TN / (TN + FP))
# showgrid(recall, recall_TN, PrecisePos, PreciseNeg)
#
#
# def compute_accuracy(feature_dict, pair_list, test_root):
# with open(pair_list, 'r') as f:
# pairs = f.readlines()
#
# similarities = []
# labels = []
# for pair in pairs:
# img1, img2, label = pair.split()
# img1 = osp.join(test_root, img1)
# img2 = osp.join(test_root, img2)
# feature1 = feature_dict[img1].cpu().numpy()
# feature2 = feature_dict[img2].cpu().numpy()
# label = int(label)
#
# similarity = cosin_metric(feature1, feature2)
# similarities.append(similarity)
# labels.append(label)
#
# accuracy, threshold = threshold_search(similarities, labels)
# # print('similarities >> {}'.format(similarities))
# # print('labels >> {}'.format(labels))
# compute_accuracy_recall(np.array(similarities), np.array(labels))
# return accuracy, threshold
# def deal_group_pair(pairList1, pairList2):
# allsimilarity = []
# one_similarity = []
# for pair1 in pairList1:
# for pair2 in pairList2:
# similarity = cosin_metric(pair1.cpu().numpy(), pair2.cpu().numpy())
# one_similarity.append(similarity)
# allsimilarity.append(max(one_similarity)) # 最大值
# # allsimilarity.append(sum(one_similarity)/len(one_similarity)) # 均值
# # allsimilarity.append(statistics.median(one_similarity)) # 中位数
# # print(allsimilarity)
# # print(labels)
# return allsimilarity
# def compute_group_accuracy(content_list_read):
# allSimilarity, allLabel = [], []
# for data_loaded in content_list_read:
# one_group_list = []
# for i in range(2):
# images = [osp.join(conf.test_val, img) for img in data_loaded[i]]
# group = group_image(images, conf.test_batch_size)
# d = featurize(group[0], conf.test_transform, model, conf.device)
# one_group_list.append(d.values())
# similarity = deal_group_pair(one_group_list[0], one_group_list[1])
# allLabel.append(data_loaded[-1])
# allSimilarity.extend(similarity)
# # print(allSimilarity)
# # print(allLabel)
# return allSimilarity, allLabel
# def compute_contrast_accuracy(content_list_read):
# npairs = 50
#
# same_folder_pairs = content_list_read['same_folder_pairs']
# cross_folder_pairs = content_list_read['cross_folder_pairs']
#
# npairs = min((len(same_folder_pairs), len(cross_folder_pairs)))
#
# Encoder = FeatsInterface(conf)
#
# same_pairs = same_folder_pairs[:npairs]
# cross_pairs = cross_folder_pairs[:npairs]
#
# same_pairs_similarity = []
# for i in range(len(same_pairs)):
# images_a = [osp.join(conf.test_val, img) for img in same_pairs[i][0]]
# images_b = [osp.join(conf.test_val, img) for img in same_pairs[i][1]]
#
# feats_a = Encoder.inference(images_a)
# feats_b = Encoder.inference(images_b)
# # matrix = 1- np.maximum(0.0, cdist(feats_a, feats_b, 'cosine'))
# matrix = 1 - cdist(feats_a, feats_b, 'cosine')
#
# feats_am = np.mean(feats_a, axis=0, keepdims=True)
# feats_bm = np.mean(feats_b, axis=0, keepdims=True)
# matrixm = 1 - np.maximum(0.0, cdist(feats_am, feats_bm, 'cosine'))
#
# same_pairs_similarity.append(np.mean(matrix))
#
# '''保存相同 Barcode 图像对'''
# # foldi = os.path.join('./result/same', f'{i}')
# # if os.path.exists(foldi):
# # shutil.rmtree(foldi)
# # os.makedirs(foldi)
# # else:
# # os.makedirs(foldi)
# # for ipt in range(len(images_a)):
# # source_path = images_a[ipt]
# # destination_path = os.path.join(foldi, f'a_{ipt}.png')
# # shutil.copy2(source_path, destination_path)
# # for ipt in range(len(images_b)):
# # source_path = images_b[ipt]
# # destination_path = os.path.join(foldi, f'b_{ipt}.png')
# # shutil.copy2(source_path, destination_path)
#
# cross_pairs_similarity = []
# for i in range(len(cross_pairs)):
# images_a = [osp.join(conf.test_val, img) for img in cross_pairs[i][0]]
# images_b = [osp.join(conf.test_val, img) for img in cross_pairs[i][1]]
#
# feats_a = Encoder.inference(images_a)
# feats_b = Encoder.inference(images_b)
# # matrix = 1- np.maximum(0.0, cdist(feats_a, feats_b, 'cosine'))
# matrix = 1 - cdist(feats_a, feats_b, 'cosine')
#
# feats_am = np.mean(feats_a, axis=0, keepdims=True)
# feats_bm = np.mean(feats_b, axis=0, keepdims=True)
# matrixm = 1 - np.maximum(0.0, cdist(feats_am, feats_bm, 'cosine'))
#
# cross_pairs_similarity.append(np.mean(matrix))
#
# '''保存不同 Barcode 图像对'''
# # foldi = os.path.join('./result/cross', f'{i}')
# # if os.path.exists(foldi):
# # shutil.rmtree(foldi)
# # os.makedirs(foldi)
# # else:
# # os.makedirs(foldi)
# # for ipt in range(len(images_a)):
# # source_path = images_a[ipt]
# # destination_path = os.path.join(foldi, f'a_{ipt}.png')
# # shutil.copy2(source_path, destination_path)
# # for ipt in range(len(images_b)):
# # source_path = images_b[ipt]
# # destination_path = os.path.join(foldi, f'b_{ipt}.png')
# # shutil.copy2(source_path, destination_path)
#
# Thresh = np.linspace(-0.2, 1, 100)
#
# Same = np.array(same_pairs_similarity)
# Cross = np.array(cross_pairs_similarity)
#
# fig, axs = plt.subplots(2, 1)
# axs[0].hist(Same, bins=60, edgecolor='black')
# axs[0].set_xlim([-0.2, 1])
# axs[0].set_title('Same Barcode')
#
# axs[1].hist(Cross, bins=60, edgecolor='black')
# axs[1].set_xlim([-0.2, 1])
# axs[1].set_title('Cross Barcode')
#
# TPFN = len(Same)
# TNFP = len(Cross)
# Recall_Pos, Recall_Neg = [], []
# Precision_Pos, Precision_Neg = [], []
# Correct = []
# for th in Thresh:
# TP = np.sum(Same > th)
# FN = TPFN - TP
# TN = np.sum(Cross < th)
# FP = TNFP - TN
#
# Recall_Pos.append(TP / TPFN)
# Recall_Neg.append(TN / TNFP)
# Precision_Pos.append(TP / (TP + FP))
# Precision_Neg.append(TN / (TN + FN))
# Correct.append((TN + TP) / (TPFN + TNFP))
#
# fig, ax = plt.subplots()
# ax.plot(Thresh, Correct, 'r', label='Correct: (TN+TP)/(TPFN+TNFP)')
# ax.plot(Thresh, Recall_Pos, 'b', label='Recall_Pos: TP/TPFN')
# ax.plot(Thresh, Recall_Neg, 'g', label='Recall_Neg: TN/TNFP')
# ax.plot(Thresh, Precision_Pos, 'c', label='Precision_Pos: TP/(TP+FP)')
# ax.plot(Thresh, Precision_Neg, 'm', label='Precision_Neg: TN/(TN+FN)')
#
# ax.set_xlim([0, 1])
# ax.set_ylim([0, 1])
# ax.grid(True)
# ax.set_title('PrecisePos & PreciseNeg')
# ax.legend()
# plt.show()
#
# print("Haved done!!!")
#
#
# if __name__ == '__main__':
#
# # Network Setup
# if conf.testbackbone == 'resnet18':
# # model = ResIRSE(conf.img_size, conf.embedding_size, conf.drop_ratio).to(conf.device)
# model = resnet18().to(conf.device)
# # elif conf.testbackbone == 'resnet34':
# # model = resnet34().to(conf.device)
# # elif conf.testbackbone == 'resnet50':
# # model = resnet50().to(conf.device)
# # elif conf.testbackbone == 'mobilevit_s':
# # model = mobilevit_s().to(conf.device)
# # elif conf.testbackbone == 'mobilenetv3':
# # model = MobileNetV3_Small().to(conf.device)
# # elif conf.testbackbone == 'mobilenet_v1':
# # model = mobilenet_v1().to(conf.device)
# # elif conf.testbackbone == 'PPLCNET_x1_0':
# # model = PPLCNET_x1_0().to(conf.device)
# # elif conf.testbackbone == 'PPLCNET_x0_5':
# # model = PPLCNET_x0_5().to(conf.device)
# # elif conf.backbone == 'PPLCNET_x2_5':
# # model = PPLCNET_x2_5().to(conf.device)
# # elif conf.testbackbone == 'mobilenet_v2':
# # model = mobilenet_v2().to(conf.device)
# # elif conf.testbackbone == 'resnet14':
# # model = resnet14().to(conf.device)
# else:
# raise ValueError('Have not model {}'.format(conf.backbone))
#
# print('load model {} '.format(conf.testbackbone))
# # model = nn.DataParallel(model).to(conf.device)
# model.load_state_dict(torch.load(conf.test_model, map_location=conf.device))
# model.eval()
# if not conf.group_test:
# images = unique_image(conf.test_list)
# images = [osp.join(conf.test_val, img) for img in images]
#
# groups = group_image(images, conf.test_batch_size) ##根据batch_size取图片
#
# feature_dict = dict()
# for group in groups:
# d = featurize(group, conf.test_transform, model, conf.device)
# feature_dict.update(d)
# # print('feature_dict', feature_dict)
# accuracy, threshold = compute_accuracy(feature_dict, conf.test_list, conf.test_val)
#
# print(
# f"Test Model: {conf.test_model}\n"
# f"Accuracy: {accuracy:.3f}\n"
# f"Threshold: {threshold:.3f}\n"
# )
# elif conf.group_test:
# """
# conf.test_val: 测试数据集地址
# conf.test_group_json测试数据分组配置文件
# """
# filename = conf.test_group_json
#
# filename = "../cl/images_1.json"
# with open(filename, 'r', encoding='utf-8') as file:
# content_list_read = json.load(file)
#
# compute_contrast_accuracy(content_list_read)
# =============================================================================
# Similarity, Label = compute_group_accuracy(content_list_read)
# print('allSimilarity >> {}'.format(Similarity))
# print('allLabel >> {}'.format(Label))
# compute_accuracy_recall(np.array(Similarity), np.array(Label))
# # compute_group_accuracy(data_loaded)
#
# =============================================================================

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.8 (my_env)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
</module>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PublishConfigData" remoteFilesAllowedToDisappearOnAutoupload="false">
<serverData>
<paths name="lc@192.168.1.142:22 password">
<serverdata>
<mappings>
<mapping local="$PROJECT_DIR$" web="/" />
</mappings>
</serverdata>
</paths>
</serverData>
</component>
</project>

View File

@ -0,0 +1,12 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="N803" />
</list>
</option>
</inspection_tool>
</profile>
</component>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.8 (my_env)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (my_env)" project-jdk-type="Python SDK" />
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/contrastInference.iml" filepath="$PROJECT_DIR$/.idea/contrastInference.iml" />
</modules>
</component>
</project>

View File

@ -0,0 +1 @@
# from .config import config

View File

@ -0,0 +1,84 @@
import torch
import torchvision.transforms as T
class Config:
# network settings
backbone = 'vit' # [resnet18, mobilevit_s, mobilenet_v2, mobilenetv3_small, mobilenetv3_large, mobilenet_v1, PPLCNET_x1_0, PPLCNET_x0_5, PPLCNET_x2_5]
metric = 'softmax' # [cosface, arcface, softmax]
cbam = True
embedding_size = 256 # 256
drop_ratio = 0.5
img_size = 224
teacher = 'vit' # [resnet18, mobilevit_s, mobilenet_v2, mobilenetv3_small, mobilenetv3_large, mobilenet_v1, PPLCNET_x1_0, PPLCNET_x0_5, PPLCNET_x2_5]
student = 'resnet'
# data preprocess
# input_shape = [1, 128, 128]
"""transforms.RandomCrop(size),
transforms.RandomVerticalFlip(p=0.5),
transforms.RandomHorizontalFlip(),
RandomRotate(15, 0.3),
# RandomGaussianBlur()"""
train_transform = T.Compose([
T.ToTensor(),
T.Resize((img_size, img_size)),
# T.RandomCrop(img_size*4//5),
# T.RandomHorizontalFlip(p=0.5),
T.RandomRotation(180),
T.ColorJitter(brightness=0.5),
T.ConvertImageDtype(torch.float32),
T.Normalize(mean=[0.5], std=[0.5]),
])
test_transform = T.Compose([
T.ToTensor(),
T.Resize((img_size, img_size)),
T.ConvertImageDtype(torch.float32),
T.Normalize(mean=[0.5], std=[0.5]),
])
# dataset
train_root = './data/2250_train/train' # 初始筛选过一次的数据集
# train_root = './data/0625_train/train'
test_root = "./data/2250_train/val/"
# test_root = "./data/0625_train/val"
test_list = "./data/2250_train/val_pair.txt"
test_group_json = "./data/2250_train/cross_same.json"
# test_group_json = "./data/0625_train/cross_same.json"
# test_list = "./data/test_data_100/val_pair.txt"
# training settings
checkpoints = "checkpoints/vit_b_16_0815/" # [resnet18, mobilevit_s, mobilenet_v2, mobilenetv3]
restore = True
# restore_model = "checkpoints/renet18_2250_0315/best_resnet18_2250_0315.pth" # best_resnet18_1491_0306.pth
restore_model = "checkpoints/vit_b_16_0730/best.pth" # best_resnet18_1491_0306.pth
# test_model = "./checkpoints/renet18_1887_0311/best_resnet18_1887_0311.pth"
testbackbone = 'resnet18' # [resnet18, mobilevit_s, mobilenet_v2, mobilenetv3_small, mobilenetv3_large, mobilenet_v1, PPLCNET_x1_0, PPLCNET_x0_5]
# test_val = "./data/2250_train"
test_val = "./data/0625_train"
test_model = "checkpoints/resnet18_0721/best.pth"
train_batch_size = 128 # 256
test_batch_size = 256 # 256
epoch = 300
optimizer = 'adamw' # ['sgd', 'adam' 'adamw']
lr = 1e-3 # 1e-2
lr_step = 10 # 10
lr_decay = 0.95 # 0.98
weight_decay = 5e-4
loss = 'focal_loss' # ['focal_loss', 'cross_entropy']
device = torch.device('cuda:1' if torch.cuda.is_available() else 'cpu')
# device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
pin_memory = True # if memory is large, set it True to speed up a bit
num_workers = 4 # dataloader
group_test = True
# group_test = False
config = Config()

View File

@ -0,0 +1,103 @@
import os
import os.path as osp
import torch
import numpy as np
from model import resnet18
from PIL import Image
from torch.nn.functional import softmax
from config import config as conf
import time
embedding_size = conf.embedding_size
img_size = conf.img_size
device = conf.device
def load_contrast_model():
model = resnet18().to(conf.device)
model.load_state_dict(torch.load(conf.test_model, map_location=conf.device))
model.eval()
print('load model {} '.format(conf.testbackbone))
return model
def group_image(imageDirs, batch) -> list:
images = []
"""Group image paths by batch size"""
with os.scandir(imageDirs) as entries:
for imgpth in entries:
print(imgpth)
images.append(os.sep.join([imageDirs, imgpth.name]))
print(f"{len(images)} images in {imageDirs}")
size = len(images)
res = []
for i in range(0, size, batch):
end = min(batch + i, size)
res.append(images[i: end])
return res
def test_preprocess(images: list, transform) -> torch.Tensor:
res = []
for img in images:
# print(img)
im = Image.open(img)
im = transform(im)
res.append(im)
# data = torch.cat(res, dim=0) # shape: (batch, 128, 128)
# data = data[:, None, :, :] # shape: (batch, 1, 128, 128)
data = torch.stack(res)
return data
def featurize(images: list, transform, net, device) -> dict:
"""featurize each image and save into a dictionary
Args:
images: image paths
transform: test transform
net: pretrained model
device: cpu or cuda
Returns:
Dict (key: imagePath, value: feature)
"""
data = test_preprocess(images, transform)
data = data.to(device)
net = net.to(device)
with torch.no_grad():
features = net(data)
# res = {img: feature for (img, feature) in zip(images, features)}
return features
if __name__ == '__main__':
# Network Setup
if conf.testbackbone == 'resnet18':
model = resnet18().to(device)
else:
raise ValueError('Have not model {}'.format(conf.backbone))
print('load model {} '.format(conf.testbackbone))
# model = nn.DataParallel(model).to(conf.device)
model.load_state_dict(torch.load(conf.test_model, map_location=conf.device))
model.eval()
# images = unique_image(conf.test_list)
# images = [osp.join(conf.test_val, img) for img in images]
# print('images', images)
# images = ['./data/2250_train/val/6920616313186/6920616313186_6920616313186_20240220-124502_53d2e103-ae3a-4689-b745-9d8723b770fe_front_returnGood_70f75407b7ae_31_01.jpg']
# groups = group_image(conf.test_val, conf.test_batch_size) ##根据batch_size取图片
groups = group_image('img_test', 1) ##根据batch_size取图片, 默认batch_size = 8
feature_dict = dict()
for group in groups:
s = time.time()
features = featurize(group, conf.test_transform, model, conf.device)
e = time.time()
print('time: {}'.format(e - s))
# out = softmax(features, dim=1).argmax(dim=1)
# print('d >>> {}'. format(out))
# feature_dict.update(d)

View File

@ -0,0 +1 @@
from .resnet_pre import resnet18, resnet34, resnet50, resnet14

View File

@ -0,0 +1,462 @@
import torch
import torch.nn as nn
from config import config as conf
try:
from torch.hub import load_state_dict_from_url
except ImportError:
from torch.utils.model_zoo import load_url as load_state_dict_from_url
# from .utils import load_state_dict_from_url
__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101',
'resnet152', 'resnext50_32x4d', 'resnext101_32x8d',
'wide_resnet50_2', 'wide_resnet101_2']
model_urls = {
'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',
'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',
'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',
'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',
'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',
'resnext50_32x4d': 'https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth',
'resnext101_32x8d': 'https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth',
'wide_resnet50_2': 'https://download.pytorch.org/models/wide_resnet50_2-95faca4d.pth',
'wide_resnet101_2': 'https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth',
}
def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1):
"""3x3 convolution with padding"""
return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
padding=dilation, groups=groups, bias=False, dilation=dilation)
def conv1x1(in_planes, out_planes, stride=1):
"""1x1 convolution"""
return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
class SpatialAttention(nn.Module):
def __init__(self, kernel_size=7):
super(SpatialAttention, self).__init__()
assert kernel_size in (3, 7), 'kernel size must be 3 or 7'
padding = 3 if kernel_size == 7 else 1
self.conv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
avg_out = torch.mean(x, dim=1, keepdim=True)
max_out, _ = torch.max(x, dim=1, keepdim=True)
x = torch.cat([avg_out, max_out], dim=1)
x = self.conv1(x)
return self.sigmoid(x)
class BasicBlock(nn.Module):
expansion = 1
def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1,
base_width=64, dilation=1, norm_layer=None, cam=False, bam=False):
super(BasicBlock, self).__init__()
if norm_layer is None:
norm_layer = nn.BatchNorm2d
if groups != 1 or base_width != 64:
raise ValueError('BasicBlock only supports groups=1 and base_width=64')
if dilation > 1:
raise NotImplementedError("Dilation > 1 not supported in BasicBlock")
self.cam = cam
self.bam = bam
# Both self.conv1 and self.downsample layers downsample the input when stride != 1
self.conv1 = conv3x3(inplanes, planes, stride)
self.bn1 = norm_layer(planes)
self.relu = nn.ReLU(inplace=True)
self.conv2 = conv3x3(planes, planes)
self.bn2 = norm_layer(planes)
self.downsample = downsample
self.stride = stride
if self.cam:
if planes == 64:
self.globalAvgPool = nn.AvgPool2d(56, stride=1)
elif planes == 128:
self.globalAvgPool = nn.AvgPool2d(28, stride=1)
elif planes == 256:
self.globalAvgPool = nn.AvgPool2d(14, stride=1)
elif planes == 512:
self.globalAvgPool = nn.AvgPool2d(7, stride=1)
self.fc1 = nn.Linear(in_features=planes, out_features=round(planes / 16))
self.fc2 = nn.Linear(in_features=round(planes / 16), out_features=planes)
self.sigmod = nn.Sigmoid()
if self.bam:
self.bam = SpatialAttention()
def forward(self, x):
identity = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
if self.downsample is not None:
identity = self.downsample(x)
if self.cam:
ori_out = self.globalAvgPool(out)
out = out.view(out.size(0), -1)
out = self.fc1(out)
out = self.relu(out)
out = self.fc2(out)
out = self.sigmod(out)
out = out.view(out.size(0), out.size(-1), 1, 1)
out = out * ori_out
if self.bam:
out = out*self.bam(out)
out += identity
out = self.relu(out)
return out
class Bottleneck(nn.Module):
# Bottleneck in torchvision places the stride for downsampling at 3x3 convolution(self.conv2)
# while original implementation places the stride at the first 1x1 convolution(self.conv1)
# according to "Deep residual learning for image recognition"https://arxiv.org/abs/1512.03385.
# This variant is also known as ResNet V1.5 and improves accuracy according to
# https://ngc.nvidia.com/catalog/model-scripts/nvidia:resnet_50_v1_5_for_pytorch.
expansion = 4
def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1,
base_width=64, dilation=1, norm_layer=None, cam=False, bam=False):
super(Bottleneck, self).__init__()
if norm_layer is None:
norm_layer = nn.BatchNorm2d
width = int(planes * (base_width / 64.)) * groups
self.cam = cam
self.bam = bam
# Both self.conv2 and self.downsample layers downsample the input when stride != 1
self.conv1 = conv1x1(inplanes, width)
self.bn1 = norm_layer(width)
self.conv2 = conv3x3(width, width, stride, groups, dilation)
self.bn2 = norm_layer(width)
self.conv3 = conv1x1(width, planes * self.expansion)
self.bn3 = norm_layer(planes * self.expansion)
self.relu = nn.ReLU(inplace=True)
self.downsample = downsample
self.stride = stride
if self.cam:
if planes == 64:
self.globalAvgPool = nn.AvgPool2d(56, stride=1)
elif planes == 128:
self.globalAvgPool = nn.AvgPool2d(28, stride=1)
elif planes == 256:
self.globalAvgPool = nn.AvgPool2d(14, stride=1)
elif planes == 512:
self.globalAvgPool = nn.AvgPool2d(7, stride=1)
self.fc1 = nn.Linear(planes * self.expansion, round(planes / 4))
self.fc2 = nn.Linear(round(planes / 4), planes * self.expansion)
self.sigmod = nn.Sigmoid()
def forward(self, x):
identity = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
out = self.relu(out)
out = self.conv3(out)
out = self.bn3(out)
if self.downsample is not None:
identity = self.downsample(x)
if self.cam:
ori_out = self.globalAvgPool(out)
out = out.view(out.size(0), -1)
out = self.fc1(out)
out = self.relu(out)
out = self.fc2(out)
out = self.sigmod(out)
out = out.view(out.size(0), out.size(-1), 1, 1)
out = out * ori_out
out += identity
out = self.relu(out)
return out
class ResNet(nn.Module):
def __init__(self, block, layers, num_classes=conf.embedding_size, zero_init_residual=False,
groups=1, width_per_group=64, replace_stride_with_dilation=None,
norm_layer=None, scale=0.75):
super(ResNet, self).__init__()
if norm_layer is None:
norm_layer = nn.BatchNorm2d
self._norm_layer = norm_layer
self.inplanes = 64
self.dilation = 1
if replace_stride_with_dilation is None:
# each element in the tuple indicates if we should replace
# the 2x2 stride with a dilated convolution instead
replace_stride_with_dilation = [False, False, False]
if len(replace_stride_with_dilation) != 3:
raise ValueError("replace_stride_with_dilation should be None "
"or a 3-element tuple, got {}".format(replace_stride_with_dilation))
self.groups = groups
self.base_width = width_per_group
self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3,
bias=False)
self.bn1 = norm_layer(self.inplanes)
self.relu = nn.ReLU(inplace=True)
self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
self.layer1 = self._make_layer(block, int(64*scale), layers[0])
self.layer2 = self._make_layer(block, int(128*scale), layers[1], stride=2,
dilate=replace_stride_with_dilation[0])
self.layer3 = self._make_layer(block, int(256*scale), layers[2], stride=2,
dilate=replace_stride_with_dilation[1])
self.layer4 = self._make_layer(block, int(512*scale), layers[3], stride=2,
dilate=replace_stride_with_dilation[2])
self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
self.fc = nn.Linear(int(512 * block.expansion*scale), num_classes)
for m in self.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
nn.init.constant_(m.weight, 1)
nn.init.constant_(m.bias, 0)
# Zero-initialize the last BN in each residual branch,
# so that the residual branch starts with zeros, and each residual block behaves like an identity.
# This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677
if zero_init_residual:
for m in self.modules():
if isinstance(m, Bottleneck):
nn.init.constant_(m.bn3.weight, 0)
elif isinstance(m, BasicBlock):
nn.init.constant_(m.bn2.weight, 0)
def _make_layer(self, block, planes, blocks, stride=1, dilate=False):
norm_layer = self._norm_layer
downsample = None
previous_dilation = self.dilation
if dilate:
self.dilation *= stride
stride = 1
if stride != 1 or self.inplanes != planes * block.expansion:
downsample = nn.Sequential(
conv1x1(self.inplanes, planes * block.expansion, stride),
norm_layer(planes * block.expansion),
)
layers = []
layers.append(block(self.inplanes, planes, stride, downsample, self.groups,
self.base_width, previous_dilation, norm_layer))
self.inplanes = planes * block.expansion
for _ in range(1, blocks):
layers.append(block(self.inplanes, planes, groups=self.groups,
base_width=self.base_width, dilation=self.dilation,
norm_layer=norm_layer))
return nn.Sequential(*layers)
def _forward_impl(self, x):
# See note [TorchScript super()]
x = self.conv1(x)
x = self.bn1(x)
x = self.relu(x)
x = self.maxpool(x)
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
# print('poolBefore', x.shape)
x = self.avgpool(x)
# print('poolAfter', x.shape)
x = torch.flatten(x, 1)
# print('fcBefore',x.shape)
x = self.fc(x)
# print('fcAfter',x.shape)
return x
def forward(self, x):
return self._forward_impl(x)
# def _resnet(arch, block, layers, pretrained, progress, **kwargs):
# model = ResNet(block, layers, **kwargs)
# if pretrained:
# state_dict = load_state_dict_from_url(model_urls[arch],
# progress=progress)
# model.load_state_dict(state_dict, strict=False)
# return model
def _resnet(arch, block, layers, pretrained, progress, **kwargs):
model = ResNet(block, layers, **kwargs)
if pretrained:
state_dict = load_state_dict_from_url(model_urls[arch],
progress=progress)
src_state_dict = state_dict
target_state_dict = model.state_dict()
skip_keys = []
# skip mismatch size tensors in case of pretraining
for k in src_state_dict.keys():
if k not in target_state_dict:
continue
if src_state_dict[k].size() != target_state_dict[k].size():
skip_keys.append(k)
for k in skip_keys:
del src_state_dict[k]
missing_keys, unexpected_keys = model.load_state_dict(src_state_dict, strict=False)
return model
def resnet14(pretrained=True, progress=True, **kwargs):
r"""ResNet-14 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet18', BasicBlock, [2, 1, 1, 2], pretrained, progress,
**kwargs)
def resnet18(pretrained=True, progress=True, **kwargs):
r"""ResNet-18 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet18', BasicBlock, [2, 2, 2, 2], pretrained, progress,
**kwargs)
def resnet34(pretrained=False, progress=True, **kwargs):
r"""ResNet-34 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet34', BasicBlock, [3, 4, 6, 3], pretrained, progress,
**kwargs)
def resnet50(pretrained=False, progress=True, **kwargs):
r"""ResNet-50 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet50', Bottleneck, [3, 4, 6, 3], pretrained, progress,
**kwargs)
def resnet101(pretrained=False, progress=True, **kwargs):
r"""ResNet-101 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet101', Bottleneck, [3, 4, 23, 3], pretrained, progress,
**kwargs)
def resnet152(pretrained=False, progress=True, **kwargs):
r"""ResNet-152 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet152', Bottleneck, [3, 8, 36, 3], pretrained, progress,
**kwargs)
def resnext50_32x4d(pretrained=False, progress=True, **kwargs):
r"""ResNeXt-50 32x4d model from
`"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
kwargs['groups'] = 32
kwargs['width_per_group'] = 4
return _resnet('resnext50_32x4d', Bottleneck, [3, 4, 6, 3],
pretrained, progress, **kwargs)
def resnext101_32x8d(pretrained=False, progress=True, **kwargs):
r"""ResNeXt-101 32x8d model from
`"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
kwargs['groups'] = 32
kwargs['width_per_group'] = 8
return _resnet('resnext101_32x8d', Bottleneck, [3, 4, 23, 3],
pretrained, progress, **kwargs)
def wide_resnet50_2(pretrained=False, progress=True, **kwargs):
r"""Wide ResNet-50-2 model from
`"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_
The model is the same as ResNet except for the bottleneck number of channels
which is twice larger in every block. The number of channels in outer 1x1
convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048
channels, and in Wide ResNet-50-2 has 2048-1024-2048.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
kwargs['width_per_group'] = 64 * 2
return _resnet('wide_resnet50_2', Bottleneck, [3, 4, 6, 3],
pretrained, progress, **kwargs)
def wide_resnet101_2(pretrained=False, progress=True, **kwargs):
r"""Wide ResNet-101-2 model from
`"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_
The model is the same as ResNet except for the bottleneck number of channels
which is twice larger in every block. The number of channels in outer 1x1
convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048
channels, and in Wide ResNet-50-2 has 2048-1024-2048.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
kwargs['width_per_group'] = 64 * 2
return _resnet('wide_resnet101_2', Bottleneck, [3, 4, 23, 3],
pretrained, progress, **kwargs)

View File

@ -0,0 +1,215 @@
# -*- coding: utf-8 -*-
"""
Created on Sun Nov 3 12:05:19 2024
@author: ym
"""
import os
import time
# import torch
import pickle
# import json
import numpy as np
from PIL import Image
from feat_extract.config import config as conf
# from model import resnet18 as resnet18
from feat_extract.inference import FeatsInterface #, inference_image
IMG_FORMAT = ['.bmp', '.jpg', '.jpeg', '.png']
# def model_init(conf, mpath=None):
# '''======= 0. 配置特征提取模型地址 ======='''
# if mpath is None:
# model_path = conf.test_model
# else:
# model_path = mpath
# ##============ 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))
# return model
def get_std_barcodeDict(bcdpath, savepath, bcdSet):
'''
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
if bcdSet is None:
stdBarcodeList.append(filename)
elif filename in bcdSet:
stdBarcodeList.append(filename)
bcdPaths = [(barcode, os.path.join(bcdpath, barcode)) for barcode in stdBarcodeList]
'''遍历数据集针对每一个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 = {}
Encoder = FeatsInterface(conf)
'''4处同名: (1)barcode原始图像文件夹; (2)imgPath中的 .pickle 文件名;
(3)该pickle文件中字典的key值; (4)特征向量字典中的一个key值'''
k = 0
for filename in os.listdir(imgPath):
bcd, ext = os.path.splitext(filename)
filepath = os.path.join(imgPath, filename)
if ext != ".pickle": continue
if bcdSet is not None and bcd not in bcdSet:
continue
featpath = os.path.join(featPath, f"{bcd}.pickle")
if os.path.isfile(featpath):
continue
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) #from vit distilled model of LiChen
# feature = inference_image(imgpaths, conf.test_transform, model, conf.device)
imgs = []
for d, imgpath in enumerate(imgpaths):
img = Image.open(imgpath)
imgs.append(img)
feature = Encoder.inference(imgs)
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(featpath, '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
return
def gen_bcd_features(imgpath, bcdpath, featpath, bcdSet=None):
''' 生成标准特征集 '''
'''1. 提取 imgpath 中样本地址,生成字典{barcode: [imgpath1, imgpath1, ...]}
并存储于: bcdpath, 格式为 barcode.pickle'''
get_std_barcodeDict(imgpath, bcdpath, bcdSet)
'''2. 特征提取,并保存至文件夹 featpath 中,也根据 bcdSet 交集执行'''
stdfeat_infer(bcdpath, featpath, bcdSet)
def main():
imgpath = r"\\192.168.1.28\share\数据\已完成数据\展厅数据\v1.0\比对数据\整理\zhantingBase"
bcdpath = r"D:\exhibition\dataset\bcdpath"
featpath = r"D:\exhibition\dataset\feats"
gen_bcd_features(imgpath, bcdpath, featpath)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,277 @@
# -*- coding: utf-8 -*-
"""
Created on Wed Dec 18 11:49:01 2024
@author: ym
"""
import os
import pickle
import numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
from scipy.spatial.distance import cdist
from utils.event import ShoppingEvent
def init_eventdict(sourcePath, stype="data"):
'''stype: str,
'source': 由 videos 或 images 生成的 pickle 文件
'data': 从 data 文件中读取的现场运行数据
'''
k, errEvents = 0, []
for bname in os.listdir(sourcePath):
# bname = r"20241126-135911-bdf91cf9-3e9a-426d-94e8-ddf92238e175_6923555210479"
source_path = os.path.join(sourcePath, bname)
if stype=="data":
pickpath = os.path.join(eventDataPath, f"{bname}.pickle")
if not os.path.isdir(source_path) or os.path.isfile(pickpath):
continue
if stype=="source":
pickpath = os.path.join(eventDataPath, bname)
if not os.path.isfile(source_path) or os.path.isfile(pickpath):
continue
try:
event = ShoppingEvent(source_path, stype)
with open(pickpath, 'wb') as f:
pickle.dump(event, f)
print(bname)
except Exception as e:
errEvents.append(source_path)
print(e)
# k += 1
# if k==1:
# break
errfile = os.path.join(resultPath, 'error_events.txt')
with open(errfile, 'a', encoding='utf-8') as f:
for line in errEvents:
f.write(line + '\n')
def read_eventdict(eventDataPath):
evtDict = {}
for filename in os.listdir(eventDataPath):
evtname, ext = os.path.splitext(filename)
if ext != ".pickle": continue
evtpath = os.path.join(eventDataPath, filename)
with open(evtpath, 'rb') as f:
evtdata = pickle.load(f)
evtDict[evtname] = evtdata
return evtDict
def simi_calc(event, o2nevt, typee=None):
if typee == "11":
boxes1 = event.front_boxes
boxes2 = o2nevt.front_boxes
feat1 = event.front_feats
feat2 = o2nevt.front_feats
if typee == "10":
boxes1 = event.front_boxes
boxes2 = o2nevt.back_boxes
feat1 = event.front_feats
feat2 = o2nevt.back_feats
if typee == "00":
boxes1 = event.back_boxes
boxes2 = o2nevt.back_boxes
feat1 = event.back_feats
feat2 = o2nevt.back_feats
if typee == "01":
boxes1 = event.back_boxes
boxes2 = o2nevt.front_boxes
feat1 = event.back_feats
feat2 = o2nevt.front_feats
'''自定义事件特征选择'''
if typee==3:
feat1 = event.feats_compose
feat2 = o2nevt.feats_compose
if len(feat1) and len(feat2):
matrix = 1 - cdist(feat1[0], feat2[0], 'cosine')
simi = np.mean(matrix)
else:
simi = None
return simi
def one2n_pr(evtDicts, pattern=1):
'''
pattern:
1: process.data 中记录的相似度
2: 根据 process.data 中标记的 type 选择特征计算
3: 以其它方式选择特征计算
'''
tpevents, fnevents, fpevents, tnevents = [], [], [], []
tpsimi, fnsimi, tnsimi, fpsimi = [], [], [], []
errorFile_one2n = []
for evtname, event in evtDicts.items():
evt_names, evt_barcodes, evt_similars, evt_types = [], [], [], []
for ndict in event.one2n:
nname = ndict["event"]
barcode = ndict["barcode"]
similar = ndict["similar"]
typee = ndict["type"].strip()
evt_names.append(nname)
evt_barcodes.append(barcode)
evt_types.append(typee)
if pattern==1:
evt_similars.append(similar)
if pattern==2 or pattern==3:
o2n_evt = [evt for name, evt in evtDicts.items() if name.find(nname[:15])==0]
if len(o2n_evt)==1:
o2nevt = o2n_evt[0]
else:
continue
if pattern==2:
simival = simi_calc(event, o2nevt, typee)
if pattern==3:
simival = simi_calc(event, o2nevt, typee=pattern)
if simival==None:
continue
evt_similars.append(simival)
if len(evt_names)==len(evt_barcodes) and len(evt_barcodes)==len(evt_similars) \
and len(evt_similars)==len(evt_types) and len(evt_names)>0:
# maxsim = evt_similars[evt_similars.index(max(evt_similars))]
maxsim = max(evt_similars)
for i in range(len(evt_names)):
bcd, simi = evt_barcodes[i], evt_similars[i]
if bcd==event.barcode and simi==maxsim:
tpsimi.append(simi)
tpevents.append(evtname)
elif bcd==event.barcode and simi!=maxsim:
fnsimi.append(simi)
fnevents.append(evtname)
elif bcd!=event.barcode and simi!=maxsim:
tnsimi.append(simi)
tnevents.append(evtname)
elif bcd!=event.barcode and simi==maxsim and event.barcode in evt_barcodes:
fpsimi.append(simi)
fpevents.append(evtname)
else:
errorFile_one2n.append(evtname)
''' 1:n 数据存储,需根据相似度排序'''
PPrecise, PRecall = [], []
NPrecise, NRecall = [], []
Thresh = np.linspace(-0.2, 1, 100)
for th in Thresh:
'''============================= 1:n 计算'''
TP = sum(np.array(tpsimi) >= th)
FP = sum(np.array(fpsimi) >= th)
FN = sum(np.array(fnsimi) < th)
TN = sum(np.array(tnsimi) < th)
PPrecise.append(TP/(TP+FP+1e-6))
PRecall.append(TP/(len(tpsimi)+len(fnsimi)+1e-6))
NPrecise.append(TN/(TN+FN+1e-6))
NRecall.append(TN/(len(tnsimi)+len(fpsimi)+1e-6))
'''4. ============================= 1:n 曲线,'''
fig, ax = plt.subplots()
ax.plot(Thresh, PPrecise, 'r', label='Precise_Pos: TP/TPFP')
ax.plot(Thresh, PRecall, 'b', label='Recall_Pos: TP/TPFN')
ax.plot(Thresh, NPrecise, 'g', label='Precise_Neg: TN/TNFP')
ax.plot(Thresh, NRecall, 'c', label='Recall_Neg: TN/TNFN')
ax.set_xlim([0, 1])
ax.set_ylim([0, 1])
ax.grid(True)
ax.set_title('1:n Precise & Recall')
ax.set_xlabel(f"Event Num: {len(tpsimi)+len(fnsimi)}")
ax.legend()
plt.show()
## ============================= 1:n 直方图'''
fig, axes = plt.subplots(2, 2)
axes[0, 0].hist(tpsimi, bins=60, range=(-0.2, 1), edgecolor='black')
axes[0, 0].set_xlim([-0.2, 1])
axes[0, 0].set_title('TP')
axes[0, 1].hist(fpsimi, bins=60, range=(-0.2, 1), edgecolor='black')
axes[0, 1].set_xlim([-0.2, 1])
axes[0, 1].set_title('FP')
axes[1, 0].hist(tnsimi, bins=60, range=(-0.2, 1), edgecolor='black')
axes[1, 0].set_xlim([-0.2, 1])
axes[1, 0].set_title('TN')
axes[1, 1].hist(fnsimi, bins=60, range=(-0.2, 1), edgecolor='black')
axes[1, 1].set_xlim([-0.2, 1])
axes[1, 1].set_title('FN')
plt.show()
return fpevents
def main():
'''1. 生成事件字典并保存至 eventDataPath, 只需运行一次 '''
init_eventdict(eventSourcePath, stype="source")
'''2. 读取事件字典 '''
evtDicts = read_eventdict(eventDataPath)
'''3. 1:n 比对事件评估 '''
fpevents = one2n_pr(evtDicts, pattern=3)
fpErrFile = str(Path(resultPath).joinpath("one2n_fp_Error.txt"))
with open(fpErrFile, "w") as file:
for item in fpevents:
file.write(item + "\n")
if __name__ == '__main__':
eventSourcePath = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\result\ShoppingDict_pkfile"
resultPath = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\result\contrast"
eventDataPath = os.path.join(resultPath, "evtobjs")
similPath = os.path.join(resultPath, "simidata")
if not os.path.exists(eventDataPath):
os.makedirs(eventDataPath)
if not os.path.exists(similPath):
os.makedirs(similPath)
main()

View File

@ -0,0 +1,520 @@
# -*- coding: utf-8 -*-
"""
Created on Wed Sep 11 11:57:30 2024
永辉现场试验输出数据的 1:1 性能评估
适用于202410前数据保存版本的需调用 OneToOneCompare.txt
@author: ym
"""
import os
import numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
import sys
sys.path.append(r"D:\DetectTracking")
from tracking.utils.read_data import read_similar
def read_one2one_data(filepath):
simiList = []
with open(filepath, 'r', encoding='utf-8') as f:
lines = f.readlines()
split_flag = False
simi_dict = {}
for i, line in enumerate(lines):
line = line.strip()
if not line:
if len(simi_dict): simiList.append(simi_dict)
simi_dict = {}
continue
label = line.split(':')[0].strip()
value = line.split(':')[1].strip()
if label.find("SeqDir") >= 0:
simi_dict["SeqDir"] = value
if label.isdigit() and len(label) >= 8:
simi_max, simi_min = value.strip(',').split('.')
simi_dict["barcode"] = label
simi_dict["simi_max"] = float(simi_max) / 1000
simi_dict["simi_min"] = float(simi_min) / 1000
if len(simi_dict): simiList.append(simi_dict)
return simiList
def plot_pr_curve(matrix):
simimax, simimean = [], []
need_analysis = []
for simidict in matrix:
simimax.append(simidict["simi_max"])
simimean.append(simidict["simi_min"])
if simidict["simi_max"]>0.6:
need_analysis.append(simidict)
simimax = np.array(simimax)
simimean = np.array(simimean)
TPFN_max = len(simimax)
TPFN_mean = len(simimean)
fig, axs = plt.subplots(2, 1)
axs[0].hist(simimax, bins=60, edgecolor='black')
axs[0].set_xlim([-0.2, 1])
axs[0].set_title(f'Same Barcode, Num: {TPFN_max}')
axs[1].hist(simimean, bins=60, edgecolor='black')
axs[1].set_xlim([-0.2, 1])
axs[1].set_title(f'Cross Barcode, Num: {TPFN_mean}')
# plt.savefig(f'./result/{file}_hist.png') # svg, png, pdf
Recall_Neg = []
Thresh = np.linspace(-0.2, 1, 100)
for th in Thresh:
TN = np.sum(simimax < th)
Recall_Neg.append(TN/TPFN_max)
fig, ax = plt.subplots()
ax.plot(Thresh, Recall_Neg, 'b', label='Recall_Pos: TP/TPFN')
ax.set_xlim([0, 1])
ax.set_ylim([0, 1])
ax.grid(True)
ax.set_title('Positive recall')
ax.set_xlabel(f"Num: {TPFN_max}")
ax.legend()
plt.show()
# plt.savefig(f'./result/{file}_pr.png') # svg, png, pdf
print("Have done!")
pass
def test_compare():
filepaths = [r"\\192.168.1.28\share\测试_202406\0913_扫A放B\0913_1\OneToOneCompare.txt",
r"\\192.168.1.28\share\测试_202406\0913_扫A放B\0913_2\OneToOneCompare.txt",
r"\\192.168.1.28\share\测试_202406\0914_扫A放B\0914_1\OneToOneCompare.txt",
r"\\192.168.1.28\share\测试_202406\0914_扫A放B\0914_2\OneToOneCompare.txt"
]
simiList = []
for fp in filepaths:
slist = read_one2one_data(fp)
simiList.extend(slist)
plot_pr_curve(simiList)
def contrast_pr(paths):
'''
1:1
'''
paths = Path(paths)
evtpaths = []
for p in paths.iterdir():
condt1 = p.is_dir()
condt2 = len(p.name.split('_'))>=2
condt3 = len(p.name.split('_')[-1])>8
condt4 = p.name.split('_')[-1].isdigit()
if condt1 and condt2 and condt3 and condt4:
evtpaths.append(p)
# evtpaths = [p for p in paths.iterdir() if p.is_dir() and len(p.name.split('_'))>=2 and len(p.name.split('_')[-1])>8]
# evtpaths = [p for p in paths.iterdir() if p.is_dir()]
events, similars = [], []
##===================================== 扫A放A, 扫A放B场景()
one2oneAA, one2oneAB = [], []
one2SNAA, one2SNAB = [], []
##===================================== 应用于 11
_tp_events, _fn_events, _fp_events, _tn_events = [], [], [], []
_tp_simi, _fn_simi, _tn_simi, _fp_simi = [], [], [], []
##===================================== 应用于 1SN
tp_events, fn_events, fp_events, tn_events = [], [], [], []
tp_simi, fn_simi, tn_simi, fp_simi = [], [], [], []
##===================================== 应用于1:n
tpevents, fnevents, fpevents, tnevents = [], [], [], []
tpsimi, fnsimi, tnsimi, fpsimi = [], [], [], []
##===================================== barcodes总数、比对错误事件
bcdList = []
one2onePath, one2onePath1 = [], []
one2SNPath, one2SNPath1 = [], []
one2nPath = []
errorFile_one2one, errorFile_one2SN, errorFile_one2n = [], [], []
for path in evtpaths:
barcode = path.stem.split('_')[-1]
datapath = path.joinpath('process.data')
if not barcode.isdigit() or len(barcode)<10: continue
if not datapath.is_file(): continue
bcdList.append(barcode)
try:
SimiDict = read_similar(datapath)
except Exception as e:
print(f"{path.stem}, Error: {e}")
'''放入为 1:1相似度取最大值取出时为 1:SN, 相似度取均值'''
one2one = SimiDict['one2one']
one2SN = SimiDict['one2SN']
one2n = SimiDict['one2n']
'''================== 0. 1:1 ==================='''
barcodes, similars = [], []
for dt in one2one:
one2onePath.append((path.stem))
if dt['similar']==0:
one2onePath1.append((path.stem))
continue
barcodes.append(dt['barcode'])
similars.append(dt['similar'])
if len(barcodes)==len(similars) and len(barcodes)!=0:
## 扫A放A, 扫A放B场景
simAA = [similars[i] for i in range(len(barcodes)) if barcodes[i]==barcode]
simAB = [similars[i] for i in range(len(barcodes)) if barcodes[i]!=barcode]
one2oneAA.extend(simAA)
one2oneAB.extend(simAB)
## 相似度排序barcode相等且排名第一为TP适用于多的barcode相似度比较
max_idx = similars.index(max(similars))
max_sim = similars[max_idx]
# max_bcd = barcodes[max_idx]
for i in range(len(one2one)):
bcd, simi = barcodes[i], similars[i]
if bcd==barcode and simi==max_sim:
_tp_simi.append(simi)
_tp_events.append(path.stem)
elif bcd==barcode and simi!=max_sim:
_fn_simi.append(simi)
_fn_events.append(path.stem)
elif bcd!=barcode and simi!=max_sim:
_tn_simi.append(simi)
_tn_events.append(path.stem)
elif bcd!=barcode and simi==max_sim and barcode in barcodes:
_fp_simi.append(simi)
_fp_events.append(path.stem)
else:
errorFile_one2one.append(path.stem)
'''================== 2. 取出场景下的 1 : Small N ==================='''
barcodes, similars = [], []
for dt in one2SN:
barcodes.append(dt['barcode'])
similars.append(dt['similar'])
if len(barcodes)==len(similars) and len(barcodes)!=0:
## 扫A放A, 扫A放B场景
simAA = [similars[i] for i in range(len(barcodes)) if barcodes[i]==barcode]
simAB = [similars[i] for i in range(len(barcodes)) if barcodes[i]!=barcode]
one2SNAA.extend(simAA)
one2SNAB.extend(simAB)
one2SNPath.append(path.stem)
if len(simAA)==0:
one2SNPath1.append(path.stem)
## 相似度排序barcode相等且排名第一为TP适用于多的barcode相似度比较
max_idx = similars.index(max(similars))
max_sim = similars[max_idx]
# max_bcd = barcodes[max_idx]
for i in range(len(one2SN)):
bcd, simi = barcodes[i], similars[i]
if bcd==barcode and simi==max_sim:
tp_simi.append(simi)
tp_events.append(path.stem)
elif bcd==barcode and simi!=max_sim:
fn_simi.append(simi)
fn_events.append(path.stem)
elif bcd!=barcode and simi!=max_sim:
tn_simi.append(simi)
tn_events.append(path.stem)
elif bcd!=barcode and simi==max_sim and barcode in barcodes:
fp_simi.append(simi)
fp_events.append(path.stem)
else:
errorFile_one2SN.append(path.stem)
'''===================== 3. 取出场景下的 1:n ========================'''
events, evt_barcodes, evt_similars, evt_types = [], [], [], []
for dt in one2n:
events.append(dt["event"])
evt_barcodes.append(dt["barcode"])
evt_similars.append(dt["similar"])
evt_types.append(dt["type"])
if len(events)==len(evt_barcodes) and len(evt_barcodes)==len(evt_similars) \
and len(evt_similars)==len(evt_types) and len(events)>0:
one2nPath.append(path.stem)
maxsim = evt_similars[evt_similars.index(max(evt_similars))]
for i in range(len(one2n)):
bcd, simi = evt_barcodes[i], evt_similars[i]
if bcd==barcode and simi==maxsim:
tpsimi.append(simi)
tpevents.append(path.stem)
elif bcd==barcode and simi!=maxsim:
fnsimi.append(simi)
fnevents.append(path.stem)
elif bcd!=barcode and simi!=maxsim:
tnsimi.append(simi)
tnevents.append(path.stem)
elif bcd!=barcode and simi==maxsim and barcode in evt_barcodes:
fpsimi.append(simi)
fpevents.append(path.stem)
else:
errorFile_one2n.append(path.stem)
'''命名规则:
1:1 (max) 1:1 (max) 1:n 1:N
_TP TP_ TP TPX
_PPrecise PPrecise_ PPrecise PPreciseX
tpsimi tp_simi
'''
''' 1:1 数据存储, 相似度计算方式:最大值、均值'''
_PPrecise, _PRecall = [], []
_NPrecise, _NRecall = [], []
PPrecise_, PRecall_ = [], []
NPrecise_, NRecall_ = [], []
''' 1:SN 数据存储,需根据相似度排序'''
PPreciseX, PRecallX = [], []
NPreciseX, NRecallX = [], []
''' 1:n 数据存储,需根据相似度排序'''
PPrecise, PRecall = [], []
NPrecise, NRecall = [], []
Thresh = np.linspace(-0.2, 1, 100)
for th in Thresh:
'''(Precise, Recall) 计算方式, 若 1:1 与 1:SN 相似度选择方式相同,则可以合并'''
'''===================================== 1:1 最大值'''
_TP = sum(np.array(one2oneAA) >= th)
_FP = sum(np.array(one2oneAB) >= th)
_FN = sum(np.array(one2oneAA) < th)
_TN = sum(np.array(one2oneAB) < th)
_PPrecise.append(_TP/(_TP+_FP+1e-6))
_PRecall.append(_TP/(len(one2oneAA)+1e-6))
_NPrecise.append(_TN/(_TN+_FN+1e-6))
_NRecall.append(_TN/(len(one2oneAB)+1e-6))
'''===================================== 1:SN 均值'''
TP_ = sum(np.array(one2SNAA) >= th)
FP_ = sum(np.array(one2SNAB) >= th)
FN_ = sum(np.array(one2SNAA) < th)
TN_ = sum(np.array(one2SNAB) < th)
PPrecise_.append(TP_/(TP_+FP_+1e-6))
PRecall_.append(TP_/(len(one2SNAA)+1e-6))
NPrecise_.append(TN_/(TN_+FN_+1e-6))
NRecall_.append(TN_/(len(one2SNAB)+1e-6))
'''适用于 (Precise, Recall) 计算方式多个相似度计算并排序barcode相等且排名第一为 TP '''
'''===================================== 1:SN '''
TPX = sum(np.array(tp_simi) >= th)
FPX = sum(np.array(fp_simi) >= th)
FNX = sum(np.array(fn_simi) < th)
TNX = sum(np.array(tn_simi) < th)
PPreciseX.append(TPX/(TPX+FPX+1e-6))
PRecallX.append(TPX/(len(tp_simi)+len(fn_simi)+1e-6))
NPreciseX.append(TNX/(TNX+FNX+1e-6))
NRecallX.append(TNX/(len(tn_simi)+len(fp_simi)+1e-6))
'''===================================== 1:n'''
TP = sum(np.array(tpsimi) >= th)
FP = sum(np.array(fpsimi) >= th)
FN = sum(np.array(fnsimi) < th)
TN = sum(np.array(tnsimi) < th)
PPrecise.append(TP/(TP+FP+1e-6))
PRecall.append(TP/(len(tpsimi)+len(fnsimi)+1e-6))
NPrecise.append(TN/(TN+FN+1e-6))
NRecall.append(TN/(len(tnsimi)+len(fpsimi)+1e-6))
'''1. ============================= 1:1 最大值方案 曲线'''
fig, ax = plt.subplots()
ax.plot(Thresh, _PPrecise, 'r', label='Precise_Pos: TP/TPFP')
ax.plot(Thresh, _PRecall, 'b', label='Recall_Pos: TP/TPFN')
ax.plot(Thresh, _NPrecise, 'g', label='Precise_Neg: TN/TNFP')
ax.plot(Thresh, _NRecall, 'c', label='Recall_Neg: TN/TNFN')
ax.set_xlim([0, 1])
ax.set_ylim([0, 1])
ax.grid(True)
ax.set_title('1:1 Precise & Recall')
ax.set_xlabel(f"Event Num: {len(one2oneAA)+len(one2oneAB)}")
ax.legend()
plt.show()
## ============================= 1:1 最大值方案 直方图'''
fig, axes = plt.subplots(2, 1)
axes[0].hist(np.array(one2oneAA), bins=60, edgecolor='black')
axes[0].set_xlim([-0.2, 1])
axes[0].set_title('AA')
axes[1].hist(np.array(one2oneAB), bins=60, edgecolor='black')
axes[1].set_xlim([-0.2, 1])
axes[1].set_title('BB')
plt.show()
'''2. ============================= 1:1 均值方案 曲线'''
fig, ax = plt.subplots()
ax.plot(Thresh, PPrecise_, 'r', label='Precise_Pos: TP/TPFP')
ax.plot(Thresh, PRecall_, 'b', label='Recall_Pos: TP/TPFN')
ax.plot(Thresh, NPrecise_, 'g', label='Precise_Neg: TN/TNFP')
ax.plot(Thresh, NRecall_, 'c', label='Recall_Neg: TN/TNFN')
ax.set_xlim([0, 1])
ax.set_ylim([0, 1])
ax.grid(True)
ax.set_title('1:1 Precise & Recall')
ax.set_xlabel(f"Event Num: {len(one2SNAA)}")
ax.legend()
plt.show()
## ============================= 1:1 均值方案 直方图'''
fig, axes = plt.subplots(2, 1)
axes[0].hist(np.array(one2SNAA), bins=60, edgecolor='black')
axes[0].set_xlim([-0.2, 1])
axes[0].set_title('AA')
axes[0].set_xlabel(f"Event Num: {len(one2SNAA)}")
axes[1].hist(np.array(one2SNAB), bins=60, edgecolor='black')
axes[1].set_xlim([-0.2, 1])
axes[1].set_title('BB')
axes[1].set_xlabel(f"Event Num: {len(one2SNAB)}")
plt.show()
''''3. ============================= 1:SN 曲线'''
fig, ax = plt.subplots()
ax.plot(Thresh, PPreciseX, 'r', label='Precise_Pos: TP/TPFP')
ax.plot(Thresh, PRecallX, 'b', label='Recall_Pos: TP/TPFN')
ax.plot(Thresh, NPreciseX, 'g', label='Precise_Neg: TN/TNFP')
ax.plot(Thresh, NRecallX, 'c', label='Recall_Neg: TN/TNFN')
ax.set_xlim([0, 1])
ax.set_ylim([0, 1])
ax.grid(True)
ax.set_title('1:SN Precise & Recall')
ax.set_xlabel(f"Event Num: {len(one2SNAA)}")
ax.legend()
plt.show()
## ============================= 1:N 展厅 直方图'''
fig, axes = plt.subplots(2, 2)
axes[0, 0].hist(tp_simi, bins=60, edgecolor='black')
axes[0, 0].set_xlim([-0.2, 1])
axes[0, 0].set_title(f'TP({len(tp_simi)})')
axes[0, 1].hist(fp_simi, bins=60, edgecolor='black')
axes[0, 1].set_xlim([-0.2, 1])
axes[0, 1].set_title(f'FP({len(fp_simi)})')
axes[1, 0].hist(tn_simi, bins=60, edgecolor='black')
axes[1, 0].set_xlim([-0.2, 1])
axes[1, 0].set_title(f'TN({len(tn_simi)})')
axes[1, 1].hist(fn_simi, bins=60, edgecolor='black')
axes[1, 1].set_xlim([-0.2, 1])
axes[1, 1].set_title(f'FN({len(fn_simi)})')
plt.show()
'''4. ============================= 1:n 曲线,'''
fig, ax = plt.subplots()
ax.plot(Thresh, PPrecise, 'r', label='Precise_Pos: TP/TPFP')
ax.plot(Thresh, PRecall, 'b', label='Recall_Pos: TP/TPFN')
ax.plot(Thresh, NPrecise, 'g', label='Precise_Neg: TN/TNFP')
ax.plot(Thresh, NRecall, 'c', label='Recall_Neg: TN/TNFN')
ax.set_xlim([0, 1])
ax.set_ylim([0, 1])
ax.grid(True)
ax.set_title('1:n Precise & Recall')
ax.set_xlabel(f"Event Num: {len(tpsimi)+len(fnsimi)}")
ax.legend()
plt.show()
## ============================= 1:n 直方图'''
fig, axes = plt.subplots(2, 2)
axes[0, 0].hist(tpsimi, bins=60, edgecolor='black')
axes[0, 0].set_xlim([-0.2, 1])
axes[0, 0].set_title(f'TP({len(tpsimi)})')
axes[0, 1].hist(fpsimi, bins=60, edgecolor='black')
axes[0, 1].set_xlim([-0.2, 1])
axes[0, 1].set_title(f'FP({len(fpsimi)})')
axes[1, 0].hist(tnsimi, bins=60, edgecolor='black')
axes[1, 0].set_xlim([-0.2, 1])
axes[1, 0].set_title(f'TN({len(tnsimi)})')
axes[1, 1].hist(fnsimi, bins=60, edgecolor='black')
axes[1, 1].set_xlim([-0.2, 1])
axes[1, 1].set_title(f'FN({len(fnsimi)})')
plt.show()
fpsnErrFile = str(paths.joinpath("one2SN_Error.txt"))
with open(fpsnErrFile, "w") as file:
for item in fp_events:
file.write(item + "\n")
fpErrFile = str(paths.joinpath("one2n_Error.txt"))
with open(fpErrFile, "w") as file:
for item in fpevents:
file.write(item + "\n")
# bcdSet = set(bcdList)
# one2nErrFile = str(paths.joinpath("one_2_Small_n_Error.txt"))
# with open(one2nErrFile, "w") as file:
# for item in fnevents:
# file.write(item + "\n")
# one2NErrFile = str(paths.joinpath("one_2_Big_N_Error.txt"))
# with open(one2NErrFile, "w") as file:
# for item in fn_events:
# file.write(item + "\n")
print('Done!')
if __name__ == "__main__":
evtpaths = r"D:\全实时\source_data\2024122416"
contrast_pr(evtpaths)

View File

@ -0,0 +1,109 @@
# -*- coding: utf-8 -*-
"""
Created on Mon Dec 23 13:58:13 2024
writting for selectting std subimgs to Wuhuaqi
@author: ym
"""
import os
import time
# import torch
import pickle
# import json
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from scipy.spatial.distance import cdist
from feat_extract.config import config as conf
# from model import resnet18 as resnet18
from feat_extract.inference import FeatsInterface #, inference_image
IMG_FORMAT = ['.bmp', '.jpg', '.jpeg', '.png']
def gen_features(imgpath):
Encoder = FeatsInterface(conf)
imgs, imgnames = [], []
for filename in os.listdir(imgpath):
file, ext = os.path.splitext(filename)
if ext not in IMG_FORMAT: continue
fpath = os.path.join(imgpath, filename)
img = Image.open(fpath)
imgs.append(img)
filelist = file.split("_")
newname = "_".join([filelist[0],filelist[1], filelist[2], filelist[-3], filelist[-2], filelist[-1]])
# imgnames.append(newname)
imgnames.append(file)
features = Encoder.inference(imgs)
features /= np.linalg.norm(features, axis=1)[:, None]
return features, imgnames
def top_p_percent_indices(matrix, p):
"""
Finds the indices of the top p% largest elements in a 2D matrix.
Args:
matrix (np.ndarray): A 2D NumPy array.
p: int, 0-100
Returns:
List[Tuple[int, int]]: A list of indices (row, column) for the top 10% largest elements.
"""
# Flatten the matrix
flat_matrix = matrix.flatten()
# Calculate the threshold for the top 10%
num_elements = len(flat_matrix)
threshold_index = int(num_elements * 0.01*p) # Top 10%
threshold_index = max(1, threshold_index) # Ensure at least one element is considered
threshold_value = np.partition(flat_matrix, -threshold_index)[-threshold_index]
# Create a mask for elements >= threshold
mask = matrix >= threshold_value
# Get the indices of elements that satisfy the mask
indices = np.argwhere(mask)
return list(map(tuple, indices))
def main():
imgpath = r"\\192.168.1.28\share\数据\已完成数据\展厅数据\v1.0\比对数据\整理\zhantingBase\6923555210479"
feats, imgnames = gen_features(imgpath)
n = len(feats)
matrix = 1 - cdist(feats, feats, 'cosine')
nmatrix = np.array([[matrix[i][j] for j in range(n) if i != j] for i in range(n)])
top_p_large_index = top_p_percent_indices(nmatrix, 1)
top_p_small_index = top_p_percent_indices(-1*nmatrix, 1)
simi_mean = np.mean(nmatrix, axis=1)
max_simi = np.max(nmatrix)
max_index = np.where(nmatrix==max_simi)
min_simi = np.min(nmatrix)
min_index = np.where(nmatrix==min_simi)
fig, ax = plt.subplots()
simils = [matrix[i][j] for j in range(n) for i in range(n) if j>i]
ax.hist(simils, bins=60, range=(-0.2, 1), edgecolor='black')
ax.set_xlim([-0.2, 1])
ax.set_title("Similarity")
print("done!")
if __name__ == '__main__':
main()

View File

@ -0,0 +1,200 @@
# -*- coding: utf-8 -*-
"""
Created on Fri Aug 9 10:36:45 2024
分析图像对间的相似度
@author: ym
"""
import os
import cv2
import numpy as np
import torch
import sys
from scipy.spatial.distance import cdist
''' 加载 LC 定义的模型形式'''
from config import config as conf
from model import resnet18 as resnet18
from test_ori import inference_image
##============ load resnet mdoel
model = resnet18().to(conf.device)
# model = nn.DataParallel(model).to(conf.device)
model.load_state_dict(torch.load(conf.test_model, map_location=conf.device))
model.eval()
print('load model {} '.format(conf.testbackbone))
IMG_FORMAT = ['.bmp', '.jpg', '.JPG', '.jpeg', '.png']
# =============================================================================
# ''' 加载REID中定义的模型形式'''
# sys.path.append(r"D:\DetectTracking")
# from tracking.trackers.reid.reid_interface import ReIDInterface
# from tracking.trackers.reid.config import config as ReIDConfig
# ReIDEncoder = ReIDInterface(ReIDConfig)
#
# def inference_image_ReID(images):
# batch_patches = []
# patches = []
# for d, img1 in enumerate(images):
#
#
# img = img1[:, :, ::-1].copy() # the model expects RGB inputs
# patch = ReIDEncoder.transform(img)
#
# # 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 features
# =============================================================================
def silimarity_compare():
imgpaths = r"D:\DetectTracking\contrast\images\2"
filepaths = []
for root, dirs, filenames in os.walk(imgpaths):
for filename in filenames:
file, ext = os.path.splitext(filename)
if ext not in IMG_FORMAT: continue
file_path = os.path.join(root, filename)
filepaths.append(file_path)
feature = inference_image(filepaths, conf.test_transform, model, conf.device)
feature /= np.linalg.norm(feature, axis=1)[:, None]
similar = 1 - np.maximum(0.0, cdist(feature, feature, metric='cosine'))
print("Done!")
def similarity_compare_sequence(root_dir):
'''
root_dir包含 "subimgs"字段的文件夹中图像为 subimg子图
功能:相邻帧子图间相似度比较
'''
all_files = []
extensions = ['.png', '.jpg']
for dirpath, dirnames, filenames in os.walk(root_dir):
filepaths = []
for filename in filenames:
if os.path.basename(dirpath).find('subimgs') < 0:
continue
file, ext = os.path.splitext(filename)
if ext in extensions:
imgpath = os.path.join(dirpath, filename)
filepaths.append(imgpath)
nf = len(filepaths)
if nf==0:
continue
fnma = os.path.basename(filepaths[0]).split('.')[0]
imga = cv2.imread(filepaths[0])
ha, wa = imga.shape[:2]
for i in range(1, nf):
fnmb = os.path.basename(filepaths[i]).split('.')[0]
imgb = cv2.imread(filepaths[i])
hb, wb = imgb.shape[:2]
feats = inference_image_ReID(((imga, imgb)))
similar = 1 - np.maximum(0.0, cdist(feats, feats, metric='cosine'))
h, w = max((ha, hb)), max((wa, wb))
img = np.zeros(((h, 2*w, 3)), np.uint8)
img[0:ha, 0:wa], img[0:hb, w:(w+wb)] = imga, imgb
linewidth = max(round(((h+2*w))/2 * 0.001), 2)
cv2.putText(img,
text=f'{similar[0,1]:.2f}', # Text string to be drawn
org=(max(w-20, 10), h-10), # Bottom-left corner of the text string
fontFace=0, # Font type
fontScale=linewidth/3, # Font scale factor
color=(0, 0, 255), # Text color
thickness=linewidth, # Thickness of the lines used to draw a text
lineType=cv2.LINE_AA, # Line type
)
spath = os.path.join(dirpath, 's'+fnma+'-vs-'+fnmb+'.png')
cv2.imwrite(spath, img)
fnma = os.path.basename(filepaths[i]).split('.')[0]
imga = imgb.copy()
ha, wa = imga.shape[:2]
return
def main():
root_dir = r"D:\contrast\dataset\result\20240723-112242_6923790709882"
try:
similarity_compare_sequence(root_dir)
except Exception as e:
print(f'Error: {e}')
if __name__ == '__main__':
# main()
silimarity_compare()

View File

@ -0,0 +1,160 @@
# -*- coding: utf-8 -*-
"""
Created on Wed Nov 20 11:17:29 2024
@author: ym
"""
import os
import cv2
import pickle
import numpy as np
from scipy.spatial.distance import cdist
import matplotlib.pyplot as plt
def save_imgpairs(barcode, imgpaths, matrix, savepath, thresh=(0.4, 0.6), ctype="intra"):
if ctype=="intra":
rows, cols = np.triu_indices(matrix.shape[0], k=1) # k=1 表示不包括对角线
mask = matrix[rows, cols] < thresh[1]
indices = list(zip(rows[mask], cols[mask]))
else:
rows, cols = np.where(matrix > thresh[0])
indices = list(zip(rows, cols))
if len(indices):
savepath = os.path.join(savepath, barcode)
if not os.path.exists(savepath):
os.makedirs (savepath)
for idx1, idx2 in indices:
if len(imgpaths) == 1:
img1 = cv2.imread(imgpaths[0][idx1])
img2 = cv2.imread(imgpaths[0][idx2])
elif len(imgpaths) == 2:
img1 = cv2.imread(imgpaths[0][idx1])
img2 = cv2.imread(imgpaths[1][idx2])
simi = matrix[idx1, idx2]
H1, W1 = img1.shape[:2]
H2, W2 = img2.shape[:2]
H, W = max((H1, H2)), max((W1, W2))
img = np.ones((H, 2*W, 3), dtype=np.uint8) *np.array([255, 128, 128])
img[0:H1, 0:W1, :] = img1
img[0:H2, (2*W-W2):, :] = img2
text = f"sim: {simi:.2f}"
org = (10, H-10)
cv2.putText(img, text, org, fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=0.75,
color=(0, 0, 255), thickness=2, lineType=cv2.LINE_AA)
imgpath = os.path.join(savepath, f"{simi:.2f}_{barcode}_{idx1}_{idx2}.png")
cv2.imwrite(imgpath, img)
def feat_analysis(featpath):
savepath = r"D:\exhibition\result\stdfeat"
InterThresh = (0.4, 0.6)
featDict, features= [], []
for filename in os.listdir(featpath):
file, ext = os.path.splitext(filename)
if ext != ".pickle": continue
filepath = os.path.join(featpath, filename)
with open(filepath, 'rb') as f:
bpDict = pickle.load(f)
feat = bpDict["feats_ft32"]
featDict.append(bpDict)
features.append(feat)
N = len(features)
simMatrix = []
intra_simi = np.empty(0)
low_simi_index = {}
for i, feats in enumerate(features):
matrix = 1 - cdist(feats, feats, 'cosine')
simMatrix.append(matrix)
'''提取相似矩阵上三角元素'''
rows, cols = np.triu_indices(matrix.shape[0], k=1) # k=1 表示不包括对角线
upper_tri= matrix[rows, cols]
intra_simi = np.concatenate((intra_simi, upper_tri))
'''保存相似度小于阈值的图像对'''
barcode = featDict[i]["barcode"]
imgpaths = featDict[i]["imgpaths"]
# save_imgpairs(barcode, [imgpaths], matrix, savepath, InterThresh, "intra")
print(f"{barcode} have done!")
Matrix = np.zeros((N, N))
inter_bcds = []
inter_simi = np.empty(0)
for i, feati in enumerate(features):
bcdi = featDict[i]["barcode"]
imgpathi = featDict[i]["imgpaths"]
for j, featj in enumerate(features):
bcdj = featDict[j]["barcode"]
imgpathj = featDict[j]["imgpaths"]
matrix = 1 - cdist(feati, featj, 'cosine')
inter_bcds.append((i, j, bcdi, bcdj))
Matrix[i, j] = np.mean(matrix)
if j>i:
bcd_ij = bcdi+'_'+bcdj
# save_imgpairs(bcd_ij, [imgpathi, imgpathj], matrix, savepath, InterThresh, "inter")
inter_simi = np.concatenate((inter_simi, matrix.ravel()))
print(f"{bcd_ij} have done!")
fig, axs = plt.subplots(2, 1)
axs[0].hist(intra_simi, bins=100, color='blue', edgecolor='black', alpha=0.7)
axs[0].set_xlim(0, 1)
axs[0].set_xlabel('Performance')
axs[0].set_title("inter similarity")
axs[1].hist(inter_simi, bins=100, color='green', edgecolor='black', alpha=0.7)
axs[1].set_xlim(0, 1)
axs[1].set_xlabel('Performance')
axs[1].set_title("inter similarity")
print("Done")
def main():
stdpath = r"D:\exhibition\dataset\feats"
feat_analysis(stdpath)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
"""
Created on Thu Sep 26 08:53:58 2024
@author: ym
"""

View File

@ -0,0 +1,83 @@
# -*- coding: utf-8 -*-
"""
Created on Fri Sep 13 16:49:05 2024
比较 stdBcdpath 和 filepath 中的 barcodes 列表,求出二者的并集和为包含在
stdBcdpath 中的 barcodes 清单
@author: ym
"""
import os
from openpyxl import load_workbook, Workbook
def read_xlsx():
stdBcdpath = r"\\192.168.1.28\share\已标注数据备份\对比数据\barcode\total_barcode_6588"
filepath = r"\\192.168.1.28\share\联华中环店\中环店商品信息.xlsx"
existingPath = r'\\192.168.1.28\share\联华中环店\中环店商品信息_已有商品.xlsx'
lackingPath = r'\\192.168.1.28\share\联华中环店\中环店商品信息_未包含商品.xlsx'
workbook = load_workbook(filename=filepath)
sheet = workbook['Sheet1']
barcodeCol = [sheet.cell(row=r, column=1).value for r in range(1, sheet.max_row+1)]
zhBarcodeList = [barcodeCol[i] for i in range(1, len(barcodeCol))]
stdBarcodeList = []
for filename in os.listdir(stdBcdpath):
filepath = os.path.join(stdBcdpath, filename)
if not os.path.isdir(filepath) or not filename.isdigit():
continue
stdBarcodeList.append(int(filename))
stdBarcodeSet = set(stdBarcodeList)
zhBarcodeSet = set(zhBarcodeList)
interBarcodes = list(zhBarcodeSet.intersection(stdBarcodeSet))
print(len(interBarcodes))
dest_wb1 = Workbook()
dest_sheet1 = dest_wb1.active
for row in sheet.iter_rows(min_row=1, max_col=sheet.max_column, values_only=True):
if str(row[0]).find("商品条码")>=0:
dest_sheet1.append(row)
if row[0] in interBarcodes:
dest_sheet1.append(row)
dest_wb1.save(filename=existingPath)
dest_wb1.close()
diffBarcodes = list(zhBarcodeSet.difference(stdBarcodeSet))
dest_wb2 = Workbook()
dest_sheet2 = dest_wb2.active
for row in sheet.iter_rows(min_row=1, max_col=sheet.max_column, values_only=True):
if str(row[0]).find("商品条码")>=0:
dest_sheet2.append(row)
if row[0] in diffBarcodes:
dest_sheet2.append(row)
dest_wb2.save(filename=lackingPath)
dest_wb2.close()
workbook.close()
if __name__ == '__main__':
# main()
read_xlsx()

View File

@ -0,0 +1,155 @@
# -*- coding: utf-8 -*-
"""
Created on Tue Dec 10 14:30:16 2024
@author: ym
"""
import os
import sys
import numpy as np
sys.path.append(r"D:\DetectTracking")
from tracking.utils.read_data import read_tracking_output, read_similar #, extract_data, read_deletedBarcode_file
IMG_FORMAT = ['.bmp', '.jpg', '.jpeg', '.png']
def creat_shopping_event(eventPath):
'''构造放入商品事件字典,这些事件需满足条件:
1) 前后摄至少有一条轨迹输出
2) 保存有帧图像,以便裁剪出 boxe 子图
'''
'''evtName 为一次购物事件'''
evtName = os.path.basename(eventPath)
evtList = evtName.split('_')
'''================ 0. 检查 evtName 及 eventPath 正确性和有效性 ================'''
if evtName.find('2024')<0 and len(evtList[0])!=15:
return
if not os.path.isdir(eventPath):
return
if len(evtList)==1 or (len(evtList)==2 and len(evtList[1])==0):
barcode = ''
else:
barcode = evtList[-1]
if len(evtList)==3 and evtList[-1]== evtList[-2]:
evtType = 'input'
else:
evtType = 'other'
'''================ 1. 构造事件描述字典,暂定 9 items ==============='''
event = {}
event['barcode'] = barcode
event['type'] = evtType
event['filepath'] = eventPath
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['one2one'] = None
event['one2n'] = None
event['feats_select'] = np.empty((0, 256), dtype=np.float64)
'''================= 2. 读取 data 文件 ============================='''
for dataname in os.listdir(eventPath):
# filename = '1_track.data'
datapath = os.path.join(eventPath, 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
if dataname.find("process.data")==0:
simiDict = read_similar(datapath)
event['one2one'] = simiDict['one2one']
event['one2n'] = simiDict['one2n']
if len(event['back_boxes'])==0 or len(event['front_boxes'])==0:
return None
'''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
'''================ 3. 读取图像文件地址并按照帧ID排序 ============='''
frontImgs, frontFid = [], []
backImgs, backFid = [], []
for imgname in os.listdir(eventPath):
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(eventPath, 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))
'''3.1 生成依据帧 ID 排序的前后摄图像地址列表'''
frontImgs = [frontImgs[i] for i in frontIdx]
backImgs = [backImgs[i] for i in backIdx]
'''3.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]
'''================ 4. 判断当前事件有效性,并添加至事件列表 =========='''
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"Event: {evtName}, Error, condt1: {condt1}, condt2: {condt2}")
return None
return event

View File

@ -0,0 +1,533 @@
# -*- coding: utf-8 -*-
"""
Created on Tue Nov 26 17:35:05 2024
@author: ym
"""
import os
import cv2
import pickle
import numpy as np
from pathlib import Path
import sys
sys.path.append(r"D:\DetectTracking")
from tracking.utils.plotting import Annotator, colors
from tracking.utils.drawtracks import drawTrack
from tracking.utils.read_data import extract_data, read_tracking_output, read_similar
from tracking.utils.read_data import extract_data_realtime, read_tracking_output_realtime
IMG_FORMAT = ['.bmp', '.jpg', '.jpeg', '.png']
VID_FORMAT = ['.mp4', '.avi']
def save_data(event, resultPath=None):
'''事件轨迹子图保存'''
if resultPath is None:
resultPath = os.path.dirname(os.path.abspath(__file__))
subimgpath = os.path.join(resultPath, f"{event.evtname}", "subimg")
imgspath = os.path.join(resultPath, f"{event.evtname}", "imgs")
if not os.path.exists(subimgpath):
os.makedirs(subimgpath)
if not os.path.exists(imgspath):
os.makedirs(imgspath)
##(2) 保存轨迹中的子图
subimgpairs = event.save_event_subimg(subimgpath)
for subimgName, subimg in subimgpairs:
spath = os.path.join(subimgpath, subimgName)
cv2.imwrite(spath, subimg)
##(3) 保存序列图像
imgpairs = event.plot_save_image(imgspath)
for imgname, img in imgpairs:
spath = os.path.join(imgspath, imgname)
cv2.imwrite(spath, img)
##(4) 保存轨迹散点图
img_cat = event.draw_tracks()
trajpath = os.path.join(resultPath, "trajectory")
if not os.path.exists(trajpath):
os.makedirs(trajpath)
traj_imgpath = os.path.join(trajpath, event.evtname+".png")
cv2.imwrite(traj_imgpath, img_cat)
def array2list(bboxes):
'''
将 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]
'''
lboxes = []
if len(bboxes)==0:
return []
trackID = np.unique(bboxes[:, 4].astype(int))
track_ids = bboxes[:, 4].astype(int)
for t_id in trackID:
idx = np.where(track_ids == t_id)[0]
box = bboxes[idx, :]
lboxes.append(box)
return lboxes
class ShoppingEvent:
def __init__(self, eventpath, stype="data"):
'''stype: str, 'source', 'data', 'realtime', 共三种 '''
self.eventpath = eventpath
self.evtname = str(Path(eventpath).stem)
self.barcode = ''
self.evtType = ''
'''=========== path of image and video =========== '''
self.back_videopath = ''
self.front_videopath = ''
self.back_imgpaths = []
self.front_imgpaths = []
'''=========== process.data ==============================='''
self.one2one = None
self.one2n = None
self.one2SN = None
'''=========== 0/1_track.data ============================='''
self.back_yolobboxes = []
self.back_yolofeats = []
self.back_trackerboxes = np.empty((0, 9), dtype=np.float64) ##和类doTracks兼容
self.back_trackerfeats = {}
self.back_trackingboxes = []
self.back_trackingfeats = []
self.front_yolobboxes = []
self.front_yolofeats = []
self.front_trackerboxes = np.empty((0, 9), dtype=np.float64) ##和类doTracks兼容
self.front_trackerfeats = {}
self.front_trackingboxes = []
self.front_trackingfeats = []
'''=========== 0/1_tracking_output.data ==================='''
self.back_boxes = []
self.back_feats = []
self.front_boxes = []
self.front_feats = []
if stype=="data":
self.from_datafile(eventpath)
if stype=="realtime":
self.from_realtime_datafile(eventpath)
if stype=="source":
self.from_source_pkl(eventpath)
self.feats_select = np.empty((0, 256), dtype=np.float64)
self.feats_compose = np.empty((0, 256), dtype=np.float64)
self.select_feats()
self.compose_feats()
# if stype=="image":
# self.from_image(eventpath)
def kerndata(self, ShoppingDict, camtype="backCamera"):
'''
camtype: str, "backCamera" or "frontCamera"
'''
yoloboxes, resfeats = [], []
trackerboxes = np.empty((0, 9), dtype=np.float64)
trackefeats = {}
trackingboxes, trackingfeats = [], []
frameDictList = ShoppingDict[camtype]["yoloResnetTracker"]
for frameDict in frameDictList:
yoloboxes.append(frameDict["bboxes"])
tboxes = frameDict["tboxes"]
trackefeats.update(frameDict["feats"])
trackerboxes = np.concatenate((trackerboxes, np.array(tboxes)), axis=0)
Residual = ShoppingDict[camtype]["tracking"].Residual
for track in Residual:
trackingboxes.append(track.boxes)
trackingfeats.append(track.features)
kdata = (yoloboxes, resfeats, trackerboxes, trackefeats, trackingboxes, trackingfeats)
tracking_out_boxes, tracking_out_feats = [], []
Confirmed = ShoppingDict[camtype]["tracking"].Confirmed
for track in Confirmed:
tracking_out_boxes.append(track.boxes)
tracking_out_feats.append(track.features)
outdata = (tracking_out_boxes, tracking_out_feats)
return kdata, outdata
def from_source_pkl(self, eventpath):
with open(eventpath, 'rb') as f:
ShoppingDict = pickle.load(f)
self.eventpath = ShoppingDict["eventPath"]
self.evtname = ShoppingDict["eventName"]
self.barcode = ShoppingDict["barcode"]
if len(ShoppingDict["one2n"]):
self.one2n = ShoppingDict["one2n"]
'''=========== path of image and video =========== '''
self.back_videopath = ShoppingDict["backCamera"]["videoPath"]
self.front_videopath = ShoppingDict["frontCamera"]["videoPath"]
self.back_imgpaths = ShoppingDict["backCamera"]["imagePaths"]
self.front_imgpaths = ShoppingDict["frontCamera"]["imagePaths"]
'''===========对应于 0/1_track.data ============================='''
backdata, back_outdata = self.kerndata(ShoppingDict, "backCamera")
frontdata, front_outdata = self.kerndata(ShoppingDict, "frontCamera")
self.back_yolobboxes = backdata[0]
self.back_yolofeats = backdata[1]
self.back_trackerboxes = backdata[2]
self.back_trackerfeats = [3]
self.back_trackingboxes = [4]
self.back_trackingfeats = [5]
self.front_yolobboxes = frontdata[0]
self.front_yolofeats = frontdata[1]
self.front_trackerboxes = frontdata[2]
self.front_trackerfeats = frontdata[3]
self.front_trackingboxes = frontdata[4]
self.front_trackingfeats = frontdata[5]
'''===========对应于 0/1_tracking_output.data ============================='''
self.back_boxes = back_outdata[0]
self.back_feats = back_outdata[1]
self.front_boxes = front_outdata[0]
self.front_feats = front_outdata[1]
def from_datafile(self, eventpath):
evtList = self.evtname.split('_')
if len(evtList)>=2 and len(evtList[-1])>=10 and evtList[-1].isdigit():
self.barcode = evtList[-1]
if len(evtList)==3 and evtList[-1]== evtList[-2]:
self.evtType = 'input'
else:
self.evtType = 'other'
'''================ path of image ============='''
frontImgs, frontFid = [], []
backImgs, backFid = [], []
for imgname in os.listdir(eventpath):
name, ext = os.path.splitext(imgname)
if ext not in IMG_FORMAT or name.find('frameId') < 0: continue
if len(name.split('_')) != 3 and not name.split('_')[3].isdigit(): continue
CamerType = name.split('_')[0]
frameId = int(name.split('_')[3])
imgpath = os.path.join(eventpath, imgname)
if CamerType == '0':
backImgs.append(imgpath)
backFid.append(frameId)
if CamerType == '1':
frontImgs.append(imgpath)
frontFid.append(frameId)
## 生成依据帧 ID 排序的前后摄图像地址列表
frontIdx = np.argsort(np.array(frontFid))
backIdx = np.argsort(np.array(backFid))
self.front_imgpaths = [frontImgs[i] for i in frontIdx]
self.back_imgpaths = [backImgs[i] for i in backIdx]
'''================ path of video ============='''
for vidname in os.listdir(eventpath):
name, ext = os.path.splitext(vidname)
if ext not in VID_FORMAT: continue
vidpath = os.path.join(eventpath, vidname)
CamerType = name.split('_')[0]
if CamerType == '0':
self.back_videopath = vidpath
if CamerType == '1':
self.front_videopath = vidpath
'''================ process.data ============='''
procpath = Path(eventpath).joinpath('process.data')
if procpath.is_file():
SimiDict = read_similar(procpath)
self.one2one = SimiDict['one2one']
self.one2n = SimiDict['one2n']
self.one2SN = SimiDict['one2SN']
'''=========== 0/1_track.data & 0/1_tracking_output.data ======='''
for dataname in os.listdir(eventpath):
datapath = os.path.join(eventpath, dataname)
if not os.path.isfile(datapath): continue
CamerType = dataname.split('_')[0]
'''========== 0/1_track.data =========='''
if dataname.find("_track.data")>0:
bboxes, ffeats, trackerboxes, trackerfeats, trackingboxes, trackingfeats = extract_data(datapath)
if CamerType == '0':
self.back_yolobboxes = bboxes
self.back_yolofeats = ffeats
self.back_trackerboxes = trackerboxes
self.back_trackerfeats = trackerfeats
self.back_trackingboxes = trackingboxes
self.back_trackingfeats = trackingfeats
if CamerType == '1':
self.front_yolobboxes = bboxes
self.front_yolofeats = ffeats
self.front_trackerboxes = trackerboxes
self.front_trackerfeats = trackerfeats
self.front_trackingboxes = trackingboxes
self.front_trackingfeats = trackingfeats
'''========== 0/1_tracking_output.data =========='''
if dataname.find("_tracking_output.data")>0:
tracking_output_boxes, tracking_output_feats = read_tracking_output(datapath)
if CamerType == '0':
self.back_boxes = tracking_output_boxes
self.back_feats = tracking_output_feats
elif CamerType == '1':
self.front_boxes = tracking_output_boxes
self.front_feats = tracking_output_feats
def from_realtime_datafile(self, eventpath):
# evtList = self.evtname.split('_')
# if len(evtList)>=2 and len(evtList[-1])>=10 and evtList[-1].isdigit():
# self.barcode = evtList[-1]
# if len(evtList)==3 and evtList[-1]== evtList[-2]:
# self.evtType = 'input'
# else:
# self.evtType = 'other'
'''================ path of video ============='''
for vidname in os.listdir(eventpath):
name, ext = os.path.splitext(vidname)
if ext not in VID_FORMAT: continue
vidpath = os.path.join(eventpath, vidname)
CamerType = name.split('_')[0]
if CamerType == '0':
self.back_videopath = vidpath
if CamerType == '1':
self.front_videopath = vidpath
'''================ process.data ============='''
procpath = Path(eventpath).joinpath('process.data')
if procpath.is_file():
SimiDict = read_similar(procpath)
self.one2one = SimiDict['one2one']
self.one2n = SimiDict['one2n']
self.one2SN = SimiDict['one2SN']
'''=========== 0/1_track.data & 0/1_tracking_output.data ======='''
for dataname in os.listdir(eventpath):
datapath = os.path.join(eventpath, dataname)
if not os.path.isfile(datapath): continue
CamerType = dataname.split('_')[0]
'''========== 0/1_track.data =========='''
if dataname.find("_track.data")>0:
trackerboxes, trackerfeats = extract_data_realtime(datapath)
if CamerType == '0':
self.back_trackerboxes = trackerboxes
self.back_trackerfeats = trackerfeats
if CamerType == '1':
self.front_trackerboxes = trackerboxes
self.front_trackerfeats = trackerfeats
'''========== 0/1_tracking_output.data =========='''
if dataname.find("_tracking_output.data")>0:
trackingboxes, trackingfeats, tracking_outboxes, tracking_outfeats = read_tracking_output_realtime(datapath)
if CamerType == '0':
self.back_trackingboxes = trackingboxes
self.back_trackingfeats = trackingfeats
self.back_boxes = tracking_outboxes
self.back_feats = tracking_outfeats
elif CamerType == '1':
self.front_trackingboxes = trackingboxes
self.front_trackingfeats = trackingfeats
self.front_boxes = tracking_outboxes
self.front_feats = tracking_outfeats
def compose_feats(self):
'''事件的特征集成'''
feats_compose = np.empty((0, 256), dtype=np.float64)
if len(self.front_feats):
for feat in self.front_feats:
feats_compose = np.concatenate((feats_compose, feat), axis=0)
if len(self.back_feats):
for feat in self.back_feats:
feats_compose = np.concatenate((feats_compose, feat), axis=0)
self.feats_compose = feats_compose
def select_feats(self):
'''事件的特征选择'''
if len(self.front_feats):
self.feats_select = self.front_feats[0]
elif len(self.back_feats):
self.feats_select = self.back_feats[0]
def plot_save_image(self, savepath):
def array2list(bboxes):
'''[x1, y1, x2, y2, track_id, score, cls, frame_index, box_index]'''
frame_ids = bboxes[:, 7].astype(int)
fID = np.unique(bboxes[:, 7].astype(int))
fboxes = []
for f_id in fID:
idx = np.where(frame_ids==f_id)[0]
box = bboxes[idx, :]
fboxes.append((f_id, box))
return fboxes
imgpairs = []
cameras = ('front', 'back')
for camera in cameras:
if camera == 'front':
boxes = self.front_trackerboxes
imgpaths = self.front_imgpaths
else:
boxes = self.back_trackerboxes
imgpaths = self.back_imgpaths
fboxes = array2list(boxes)
for fid, fbox in fboxes:
imgpath = imgpaths[int(fid-1)]
image = cv2.imread(imgpath)
annotator = Annotator(image.copy(), line_width=2)
for i, box in enumerate(fbox):
x1, y1, x2, y2, tid, score, cls, fid, bid = box
label = f'{int(tid), int(cls)}'
if tid >=0 and cls==0:
color = colors(int(cls), True)
elif tid >=0 and cls!=0:
color = colors(int(tid), True)
else:
color = colors(19, True) # 19为调色板的最后一个元素
xyxy = (x1/2, y1/2, x2/2, y2/2)
annotator.box_label(xyxy, label, color=color)
im0 = annotator.result()
imgpairs.append((Path(imgpath).name, im0))
# spath = os.path.join(savepath, Path(imgpath).name)
# cv2.imwrite(spath, im0)
return imgpairs
def save_event_subimg(self, savepath):
'''
功能: 保存一次购物事件的轨迹子图
9 items: barcode, type, filepath, back_imgpaths, front_imgpaths,
back_boxes, front_boxes, back_feats, front_feats,
feats_compose, feats_select
子图保存次序:先前摄、后后摄,以 k 为编号,和 "feats_compose" 中次序相同
'''
imgpairs = []
cameras = ('front', 'back')
for camera in cameras:
boxes = np.empty((0, 9), dtype=np.float64) ##和类doTracks兼容
if camera == 'front':
for b in self.front_boxes:
boxes = np.concatenate((boxes, b), axis=0)
imgpaths = self.front_imgpaths
else:
for b in self.back_boxes:
boxes = np.concatenate((boxes, b), axis=0)
imgpaths = self.back_imgpaths
for i, box in enumerate(boxes):
x1, y1, x2, y2, tid, score, cls, fid, bid = box
imgpath = imgpaths[int(fid-1)]
image = cv2.imread(imgpath)
subimg = image[int(y1/2):int(y2/2), int(x1/2):int(x2/2), :]
camerType, timeTamp, _, frameID = os.path.basename(imgpath).split('.')[0].split('_')
subimgName = f"cam{camerType}_{i}_tid{int(tid)}_fid({int(fid)}, {frameID}).png"
imgpairs.append((subimgName, subimg))
# spath = os.path.join(savepath, subimgName)
# cv2.imwrite(spath, subimg)
return imgpairs
# basename = os.path.basename(event['filepath'])
print(f"Image saved: {os.path.basename(self.eventpath)}")
def draw_tracks(self):
front_edge = cv2.imread(r"D:\DetectTracking\tracking\shopcart\cart_tempt\board_ftmp_line.png")
back_edge = cv2.imread(r"D:\DetectTracking\tracking\shopcart\cart_tempt\edgeline.png")
front_trackerboxes = array2list(self.front_trackerboxes)
back_trackerboxes = array2list(self.back_trackerboxes)
# img1, img2 = edgeline.copy(), edgeline.copy()
img1 = drawTrack(front_trackerboxes, front_edge.copy())
img2 = drawTrack(self.front_trackingboxes, front_edge.copy())
img3 = drawTrack(back_trackerboxes, back_edge.copy())
img4 = drawTrack(self.back_trackingboxes, back_edge.copy())
imgcat1 = np.concatenate((img1, img2), axis = 1)
H, W = imgcat1.shape[:2]
cv2.line(imgcat1, (int(W/2), 0), (int(W/2), H), (128, 255, 128), 2)
imgcat2 = np.concatenate((img3, img4), axis = 1)
H, W = imgcat2.shape[:2]
cv2.line(imgcat2, (int(W/2), 0), (int(W/2), H), (128, 255, 128), 2)
illus = [imgcat1, imgcat2]
if len(illus):
img_cat = np.concatenate(illus, axis = 1)
if len(illus)==2:
H, W = img_cat.shape[:2]
cv2.line(img_cat, (int(W/2), 0), (int(W/2), int(H)), (128, 128, 255), 3)
return img_cat
def main():
# pklpath = r"D:\DetectTracking\evtresult\images2\ShoppingDict.pkl"
# evt = ShoppingEvent(pklpath, stype='source')
evtpath = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\images\20241209-160248-08edd5f6-1806-45ad-babf-7a4dd11cea60_6973226721445"
evt = ShoppingEvent(evtpath, stype='data')
img_cat = evt.draw_tracks()
cv2.imwrite("a.png", img_cat)
if __name__ == "__main__":
main()
# main1()

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

View File

@ -0,0 +1,182 @@
# -*- coding: utf-8 -*-
"""
@author: LiChen
"""
import json
import os
import pickle
import numpy as np
import sys
sys.path.append(r"D:\DetectTracking\contrast")
from config import config as conf
# from img_data import library_imgs, temp_imgs, main_library_imgs, main_imgs_2
# from test_logic import initModel,getFeatureList
from model import resnet18
import torch
from PIL import Image
device = conf.device
def initModel():
model = resnet18().to(device)
model.load_state_dict(torch.load(conf.test_model, map_location=conf.device))
model.eval()
return model
from PIL import Image
def convert_rgba_to_rgb(image_path, output_path=None):
"""
将给定路径的4通道PNG图像转换为3通道并保存到指定输出路径。
:param image_path: 输入图像的路径
:param output_path: 转换后的图像保存路径
"""
# 打开图像
img = Image.open(image_path)
# 转换图像模式从RGBA到RGB
# .convert('RGB')会丢弃Alpha通道并转换为纯RGB图像
if img.mode == 'RGBA':
# 转换为RGB模式
img_rgb = img.convert('RGB')
# 保存转换后的图像
img_rgb.save(image_path)
print(f"Image converted from RGBA to RGB and saved to {image_path}")
# else:
# # 如果已经是RGB或其他模式直接保存
# img.save(image_path)
# print(f"Image already in {img.mode} mode, saved to {image_path}")
def test_preprocess(images: list, actionModel=False) -> torch.Tensor:
res = []
for img in images:
try:
print(img)
im = conf.test_transform(img) if actionModel else conf.test_transform(Image.open(img))
res.append(im)
except:
continue
data = torch.stack(res)
return data
def inference(images, model, actionModel=False):
data = test_preprocess(images, actionModel)
if torch.cuda.is_available():
data = data.to(conf.device)
features = model(data)
return features
def group_image(images, batch=64) -> list:
"""Group image paths by batch size"""
size = len(images)
res = []
for i in range(0, size, batch):
end = min(batch + i, size)
res.append(images[i:end])
return res
def getFeatureList(barList, imgList, model):
featList = [[] for i in range(len(barList))]
for index, feat in enumerate(imgList):
groups = group_image(feat)
for group in groups:
feat_tensor = inference(group, model)
for fe in feat_tensor:
if fe.device == 'cpu':
fe_np = fe.squeeze().detach().numpy()
else:
fe_np = fe.squeeze().detach().cpu().numpy()
featList[index].append(fe_np)
return featList
def get_files(folder):
file_dict = {}
cnt = 0
# barcode_list = ['6944649700065', '6924743915848', '6920459905012', '6901285991219', '6924882406269']
for root, dirs, files in os.walk(folder):
folder_name = os.path.basename(root) # 获取当前文件夹名称
print(folder_name)
# with open('main_barcode.txt','a') as f:
# f.write(folder_name + '\n')
# if len(dirs) == 0 and len(files) > 0 and folder_name in barcode_list: # 如果该文件夹没有子文件夹且有文件
if len(dirs) == 0 and len(files) > 0: # 如果该文件夹没有子文件夹且有文件
file_names = [os.path.join(root, file) for file in files] # 获取所有文件名
for file_name in file_names:
try:
convert_rgba_to_rgb(file_name)
except:
file_names.remove(file_name)
cnt += len(file_names)
file_dict[folder_name] = file_names
print(cnt)
return file_dict
def normalize(queFeatList):
for num1 in range(len(queFeatList)):
for num2 in range(len(queFeatList[num1])):
queFeatList[num1][num2] = queFeatList[num1][num2] / np.linalg.norm(queFeatList[num1][num2])
return queFeatList
def img2feature(imgs_dict, model, barcode_flag):
if not len(imgs_dict) > 0:
raise ValueError("No imgs files provided")
queBarIdList = list(imgs_dict.keys())
queImgsList = list(imgs_dict.values())
queFeatList = getFeatureList(queBarIdList, queImgsList, model)
queFeatList = normalize(queFeatList)
return queBarIdList, queFeatList
def createFeatureDict(imgs_dict, model,
barcode_flag=False): ##imgs->{barcode1:[img1_1...img1_n], barcode2:[img2_1...img2_n]}
dicts_all = {}
value_list = []
barcode_list, imgs_list = img2feature(imgs_dict, model, barcode_flag=False)
for i in range(len(barcode_list)):
dicts = {}
imgs_list_ = []
for j in range(len(imgs_list[i])):
imgs_list_.append(imgs_list[i][j].tolist())
# with open('feature.txt','a') as f:
# f.write(str(imgs_list[i][j].tolist())+'\n')
dicts['key'] = barcode_list[i]
dicts['value'] = imgs_list_
value_list.append(dicts)
dicts_all['total'] = value_list
print('dicts_all', dicts_all)
with open('data_0909.json', 'a') as json_file:
json.dump(dicts_all, json_file)
def read_pkl_file(file_path):
with open(file_path, 'rb') as file:
data = pickle.load(file)
return data
if __name__ == "__main__":
###将图片名称和模型推理特征向量字典存为json文件
img_path = 'data/2000_train/base'
imgs_dict = get_files(img_path)
# print('imgs_dict', imgs_dict)
model = initModel()
createFeatureDict(imgs_dict, model, barcode_flag=False)
###=======================================================
# ## =========pkl转json================
# contents = read_pkl_file('dicts_list_1887.pkl')
# print(contents)
# with open('data_1887.json', 'w') as json_file:
# json.dump(contents, json_file)