增加了单帧入侵判断及yoloV10

This commit is contained in:
18262620154
2025-04-11 17:02:39 +08:00
parent 798c596acc
commit e044c85a04
197 changed files with 1863 additions and 997 deletions

Binary file not shown.

View File

@ -123,25 +123,28 @@ def devide_motion_state(tboxes, width):
'''
periods = []
if len(tboxes) < width:
return periods
fboxes, frameTstamp = array2frame(tboxes)
fnum = len(frameTstamp)
if fnum < width: return periods
state = np.zeros((fnum, 2), dtype=np.int64)
frameState = np.concatenate((frameTstamp, state), axis = 1).astype(np.int64)
handState = np.concatenate((frameTstamp, state), axis = 1).astype(np.int64)
if fnum < width:
return frameState, handState
mtrackFid = {}
handFid = {}
'''frameState 标记由图像判断的购物车状态0: 静止1: 运动'''
for idx in range(width, fnum+1):
idx0 = idx-width
# if idx == 40:
# print("123")
lboxes = np.concatenate(fboxes[idx0:idx], axis = 0)
md = MoveDetect(lboxes)
md.classify()

420
realtime/intrude_detect.py Normal file
View File

@ -0,0 +1,420 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Apr 8 10:07:17 2025
@author: wqg
"""
import csv
import os
import platform
import sys
import pickle
import cv2
import numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
import matplotlib.pyplot as plt
from typing import List, Tuple
from scipy.spatial.distance import cdist
from scipy.spatial import ConvexHull
from shapely.geometry import Point, Polygon
##################################################### for method: run_yrt()
FILE = Path(__file__).resolve()
ROOT = FILE.parents[1]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from track_reid import yolov10_resnet_tracker
from event_time_specify import devide_motion_state
def cross(o: Tuple[float, float], a: Tuple[float, float], b: Tuple[float, float]) -> float:
""" 计算向量 OA × OB 的叉积 """
return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0])
def compute_convex_hull(points: List[Tuple[float, float]]) -> List[Tuple[float, float]]:
""" 使用 Andrew's Monotone Chain 算法求二维点集的凸包 """
points = sorted(set(points)) # 排序并去重
if len(points) <= 1:
return points
lower = []
for p in points:
while len(lower) >= 2 and cross(lower[-2], lower[-1], p) <= 0:
lower.pop()
lower.append(p)
upper = []
for p in reversed(points):
while len(upper) >= 2 and cross(upper[-2], upper[-1], p) <= 0:
upper.pop()
upper.append(p)
# 去掉重复的连接点
return lower[:-1] + upper[:-1]
def is_point_in_convex_hull(point: Tuple[float, float], hull: List[Tuple[float, float]]) -> bool:
""" 判断一个点是否在凸包(含边界)内 """
n = len(hull)
if n < 3:
# 对于点或线段,直接判断是否共线或在线段上
if n == 1:
return point == hull[0]
if n == 2:
a, b = hull
return abs(cross(a, b, point)) < 1e-10 and min(a[0], b[0]) <= point[0] <= max(a[0], b[0]) and min(a[1], b[1]) <= point[1] <= max(a[1], b[1])
return False
for i in range(n):
a = hull[i]
b = hull[(i + 1) % n]
if cross(a, b, point) < -1e-10: # 必须全部在左边或边上
return False
return True
def plot_convex_hull(points: List[Tuple[float, float]], hull: List[Tuple[float, float]], test_points: List[Tuple[float, float]] = None):
x_all, y_all = zip(*points)
fig, ax = plt.subplots()
ax.set_xlim(0, 1024)
ax.set_ylim(1280, 0)
ax.plot(x_all, y_all, 'o', label='Points')
# 凸包闭环线
hull_loop = hull + [hull[0]]
hx, hy = zip(*hull_loop)
ax.plot(hx, hy, 'r-', linewidth=2, label='Convex Hull')
# 如果有测试点
if test_points:
for pt in test_points:
color = 'green' if is_point_in_convex_hull(pt, hull) else 'black'
ax.plot(pt[0], pt[1], 's', color=color, markersize=8)
ax.text(pt[0] + 0.05, pt[1], f'{pt}', fontsize=9)
ax.legend()
ax.grid(True)
plt.title("Convex Hull Visualization")
plt.show()
def convex_scipy():
points = np.array([
[0, 0],
[2, 0],
[1, 1],
[2, 2],
[0, 2],
[1, 0.5]])
hull = ConvexHull(points)
# 凸包顶点的索引
print("凸包顶点索引:{}".format(hull.vertices))
print("凸包顶点坐标:")
for i in hull.vertices:
print(points[i])
# 将凸包坐标构造成 Polygon
hull_points = points[hull.vertices]
polygon = Polygon(hull_points)
# 判断一个点是否在凸包内
p = Point(1, 1) # 示例点
print("是否在凸包内:", polygon.contains(p)) # True or False
def test_convex():
# 测试数据
sample_points = [(0, 0), (1, 1), (2, 2), (2, 0), (0, 2), (1, 0.5)]
convex_hull = compute_convex_hull(sample_points)
# 测试点在凸包内
test_point_inside = (1, 1)
test_point_outside = (3, 3)
test_point_on_edge = (1, 0)
inside = is_point_in_convex_hull(test_point_inside, convex_hull)
outside = is_point_in_convex_hull(test_point_outside, convex_hull)
on_edge = is_point_in_convex_hull(test_point_on_edge, convex_hull)
convex_hull, inside, outside, on_edge
# 展示图像
plot_convex_hull(sample_points, convex_hull, [test_point_inside, test_point_outside, test_point_on_edge])
def array2frame(tboxes):
"tboxes: [x1, y1, x2, y2, track_id, score, cls, frame_index, box_index]"
idx = np.where(tboxes[:, 6] != 0)[0]
bboxes = tboxes[idx, :]
frameID = np.sort(np.unique(bboxes[:, 7].astype(int)))
fboxes = []
for fid in frameID:
idx = np.where(bboxes[:, 7] == fid)[0]
box = bboxes[idx, :]
fboxes.append(box)
return fboxes
def convex_based(tboxes, width, TH=40):
fboxes = array2frame(tboxes)
fnum = len(fboxes)
fids = np.array([i+1 for i in range(fnum)])[:, np.newaxis]
state = np.zeros((fnum, 1), dtype=np.int64)
frameState = np.concatenate((fids, state), axis = 1).astype(np.int64)
if fnum < width:
return frameState
for idx1 in range(width, fnum+1):
idx0 = idx1 - width
idx = idx1 - width//2 - 1
iboxes = fboxes[:idx]
cboxes = fboxes[idx][:, 0:4]
cur_xy = np.zeros((len(cboxes), 2))
cur_xy[:, 0] = (fboxes[idx][:, 0]+fboxes[idx][:, 2])/2
cur_xy[:, 1] = (fboxes[idx][:, 1]+fboxes[idx][:, 3])/2
for i in range(width//2):
x1, y1, x2, y2 = iboxes[i][:, 0], iboxes[i][:, 1], iboxes[i][:, 2], iboxes[i][:, 3]
boxes = np.array([(x1, y1), (x1, y2), (x2, y1), (x2, y2)]).transpose(0, 2, 1).reshape(-1, 2)
box1 = [(x, y) for x, y in boxes]
convex_hull = compute_convex_hull(box1)
for pt in cur_xy:
inside = is_point_in_convex_hull(pt, convex_hull)
if not inside:
break
if not inside:
break
# Based on the distance between the four corners of the current frame boxes
# and adjacent frame boxes
iboxes = fboxes[idx0:idx] + fboxes[idx+1:idx1]
cboxes = fboxes[idx][:, 0:4]
cx1, cy1, cx2, cy2 = cboxes[:, 0], cboxes[:, 1], cboxes[:, 2], cboxes[:, 3]
cxy = np.array([(cx1, cy1), (cx1, cy2), (cx2, cy1), (cx2, cy2)]).transpose(0, 2, 1).reshape(-1, 2)
iiboxes = np.concatenate(iboxes, axis=0)
ix1, iy1, ix2, iy2 = iiboxes[:, 0], iiboxes[:, 1], iiboxes[:, 2], iiboxes[:, 3]
ixy = np.array([(ix1, iy1), (ix1, iy2), (ix2, iy1), (ix2, iy2)]).transpose(0, 2, 1).reshape(-1, 2)
Dist = cdist(cxy, ixy).round(2)
max_dist = np.max(np.min(Dist, axis=1))
if max_dist > TH and not inside:
frameState[idx, 1] = 1
# plot_convex_hull(boxes, convex_hull, [pt])
frameState[idx, 1] = 1
return frameState
def single_point(tboxes, width, TH=60):
"""width: window width, >=2"""
fboxes = array2frame(tboxes)
fnum = len(fboxes)
fids = np.array([i+1 for i in range(fnum)])[:, np.newaxis]
state = np.zeros((fnum, 1), dtype=np.int64)
frameState = np.concatenate((fids, state), axis = 1).astype(np.int64)
if fnum < width:
return frameState
for idx1 in range(width, fnum+1):
idx0 = idx1 - width
idx = idx1 - width//2 - 1
iboxe1 = fboxes[idx0:idx]
iboxe2 = fboxes[idx+1:idx1]
iboxes = fboxes[idx0:idx] + fboxes[idx+1:idx1]
cboxes = fboxes[idx][:, 0:4]
cur_xy = np.zeros((len(cboxes), 2))
cur_xy[:, 0] = (fboxes[idx][:, 0]+fboxes[idx][:, 2])/2
cur_xy[:, 1] = (fboxes[idx][:, 1]+fboxes[idx][:, 3])/2
Dist = np.empty((len(cboxes), 0))
for i in range(width-1):
boxes = iboxes[i][:, 0:4]
box_xy = np.zeros((len(boxes), 2))
box_xy[:, 0] = (boxes[:, 0]+boxes[:, 2])/2
box_xy[:, 1] = (boxes[:, 1]+boxes[:, 3])/2
dist2 = cdist(cur_xy, box_xy).round(2)
Dist = np.concatenate((Dist, dist2), axis=1)
max_dist = np.max(np.min(Dist, axis=1))
if max_dist > TH:
frameState[idx, 1] = 1
return frameState
def intrude():
pkpath = Path("/home/wqg/dataset/small-goods/pkfiles")
savepath = Path("/home/wqg/dataset/small-goods/illustration_convex")
if not savepath.exists():
savepath.mkdir(parents=True, exist_ok=True)
err_trail, err_single, err_all = [], [], []
num = 0
for pth in pkpath.iterdir():
# item = r"69042386_20250407-145737_front_returnGood_b82d28427666_15_17700000001.pickle"
# pth = pkpath/item
with open(str(pth), 'rb') as f:
yrt = pickle.load(f)
evtname = pth.stem
bboxes = []
trackerboxes = np.empty((0, 10), dtype=np.float64)
for frameDict in yrt:
boxes = frameDict["bboxes"]
tboxes = frameDict["tboxes"]
tboxes = np.concatenate((tboxes, tboxes[:,7][:, None]), axis=1)
bboxes.append(boxes)
trackerboxes = np.concatenate((trackerboxes, np.array(tboxes)), axis=0)
'''single-points based for intrusion detection'''
# wd =5
# fstate1 = single_point(trackerboxes, wd)
'''convex-based '''
width = 5
fstate = convex_based(trackerboxes, width, TH=60)
# fstate = np.zeros(fstate1.shape)
# fstate[:, 0] = fstate1[:, 0]
# fstate[:, 1] = fstate1[:, 1] * fstate2[:, 1]
'''trajectory based for intrusion detection
period: 0 1 2 3
fid timestamp(fid) 基于滑动窗的tid扩展 滑动窗覆盖的运动区间
'''
win_width = 12
period, handState = devide_motion_state(trackerboxes, win_width)
num += 1
if np.all(period[:,2:4]==0):
err_trail.append(evtname)
if np.all(fstate[:,1]==0):
err_single.append(evtname)
if np.all(period[:,2:4]==0) and np.all(fstate[:,1]==0):
err_all.append(evtname)
fig, (ax1, ax2) = plt.subplots(2, 1)
ax1.plot(period[:, 1], period[:, 2], 'bo-', linewidth=1, markersize=4)
ax1.plot(period[:, 1], period[:, 3], 'rx-', linewidth=1, markersize=8)
ax2.plot(fstate[:, 0], fstate[:, 1], 'rx-', linewidth=1, markersize=8)
plt.savefig(os.path.join(str(savepath), f"{evtname}.png"))
plt.close()
# if num==1:
# break
rate_trail = 1 - len(err_trail)/num
rate_single = 1 - len(err_single)/num
rate_all = 1 - len(err_all)/num
print(f"rate_trail: {rate_trail}")
print(f"rate_single: {rate_single}")
print(f"rate_all: {rate_all}")
txtpath = savepath.parents[0] / "error.txt"
with open(str(txtpath), "w") as f:
f.write(f"rate_trail: {rate_trail}" + "\n")
f.write(f"rate_single: {rate_single}" + "\n")
f.write(f"rate_all: {rate_all}" + "\n")
f.write("\n" + "err_trail" + "\n")
for line in err_trail:
f.write(line + "\n")
f.write("\n" + "err_single" + "\n")
for line in err_single:
f.write(line + "\n")
f.write("\n" + "err_all" + "\n")
for line in err_all:
f.write(line + "\n")
print("Done!")
def run_yrt():
datapath = Path("/home/wqg/dataset/small-goods/videos/")
savepath = Path("/home/wqg/dataset/small-goods/result/")
pkpath = Path("/home/wqg/dataset/small-goods/pkfiles/")
if not savepath.exists():
savepath.mkdir(parents=True, exist_ok=True)
if not pkpath.exists():
pkpath.mkdir(parents=True, exist_ok=True)
optdict = {}
optdict["weights"] = ROOT / 'ckpts/best_v10s_width0375_1205.pt'
optdict["is_save_img"] = False
optdict["is_save_video"] = True
k = 0
for pth in datapath.iterdir():
item = "69042386_20250407-145819_back_returnGood_b82d28427666_15_17700000001.mp4"
pth = pth.parents[0] /item
optdict["source"] = pth
optdict["save_dir"] = savepath
# try:
yrtOut = yolov10_resnet_tracker(**optdict)
pkpath_ = pkpath / f"{Path(pth).stem}.pickle"
with open(str(pkpath_), 'wb') as f:
pickle.dump(yrtOut, f)
k += 1
if k==1:
break
# except Exception as e:
# print("abc")
if __name__ == '__main__':
# run_yrt()
intrude()
# test_convex()

View File

@ -19,7 +19,18 @@ from collections import OrderedDict
from event_time_specify import devide_motion_state #, state_measure
import sys
sys.path.append(r"D:\DetectTracking")
FILE = Path(__file__).resolve()
ROOT = FILE.parents[1] # YOLOv5 root directory
if str(ROOT) not in sys.path:
sys.path.append(str(ROOT)) # add ROOT to PATH
from imgs_inference import run_yolo
from tracking.utils.read_data import read_weight_sensor