270 lines
8.9 KiB
Python
270 lines
8.9 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
Created on Mon Mar 4 18:33:01 2024
|
||
|
||
@author: ym
|
||
"""
|
||
import numpy as np
|
||
from sklearn.cluster import KMeans
|
||
from .dotracks import MoveState, Track
|
||
|
||
|
||
class frontTrack(Track):
|
||
# boxes: [x1, y1, x2, y2, track_id, score, cls, frame_index, box_index]
|
||
# 0, 1, 2, 3, 4, 5, 6, 7, 8
|
||
def __init__(self, boxes, features, imgshape=(1024, 1280)):
|
||
|
||
super().__init__(boxes, features, imgshape)
|
||
|
||
'''5个关键点(中心点、左上点、右上点、左下点、右下点 )轨迹特征'''
|
||
# self.compute_cornpts_feats()
|
||
|
||
|
||
self.CART_HIGH_THRESH1 = imgshape[1]/2.98
|
||
|
||
|
||
# if self.tid==10:
|
||
# print(f"ID: {self.tid}")
|
||
|
||
'''y1、y2静止状态区间,值是 boxes 中对 axis=0 的索引,不是帧索引'''
|
||
det_y1 = np.diff(boxes[:, 1], axis=0)
|
||
det_y2 = np.diff(boxes[:, 3], axis=0)
|
||
self.static_y1, self.dynamic_y1 = self.pt_state_fids(det_y1)
|
||
self.static_y2, self.dynamic_y2 = self.pt_state_fids(det_y2)
|
||
|
||
self.isCornpoint = self.is_left_or_right_cornpoint()
|
||
self.isBotmpoint = self.is_bottom_cornpoint()
|
||
|
||
'''该函数依赖项: self.isCornpoint,不能在父类中初始化'''
|
||
self.trajfeature()
|
||
|
||
self.PositionState(camerType="front")
|
||
|
||
'''手部状态分析'''
|
||
self.HAND_STATIC_THRESH = 100
|
||
self.CART_POSIT_0 = 430
|
||
self.CART_POSIT_1 = 620
|
||
|
||
|
||
|
||
|
||
def is_left_or_right_cornpoint(self):
|
||
''' 基于 all(boxes),
|
||
boxes左下角点和图像左下角点重叠 或
|
||
boxes右下角点和图像左下角点重叠
|
||
'''
|
||
x1, y1 = self.boxes[:, 0], self.boxes[:, 1]
|
||
x2, y2 = self.boxes[:, 2], self.boxes[:, 3]
|
||
|
||
# Left-Bottom cornpoint
|
||
condt1 = all(x1 < 5) and all(y2 > self.imgshape[1]-5)
|
||
|
||
# Right-Bottom cornpoint
|
||
condt2 = all(x2 > self.imgshape[0]-5) and all(y2 > self.imgshape[1]-5)
|
||
|
||
condt = condt1 or condt2
|
||
|
||
return condt
|
||
|
||
def is_edge_cornpoint(self):
|
||
'''基于 all(boxes),boxes是否和图像左右边缘重叠'''
|
||
x1, x2 = self.boxes[:, 0], self.boxes[:, 2]
|
||
condt = all(x1 < 3) or all(x2 > self.imgshape[0]-3)
|
||
|
||
return condt
|
||
|
||
def is_bottom_cornpoint(self):
|
||
'''基于 all(boxes),boxes是否和图像下边缘重叠'''
|
||
condt = all(self.boxes[:, 3] > self.imgshape[1]-20)
|
||
|
||
return condt
|
||
|
||
# def is_OutTrack(self):
|
||
# isout = False
|
||
# if self.posState <= 1:
|
||
# isout = True
|
||
# return isout
|
||
|
||
|
||
# =============================================================================
|
||
# def compute_static_fids(self, det_y, STATIC_THRESH = 8):
|
||
# '''
|
||
# 前摄时,y一般选择为 box 的 y1 坐标,且需限定商品在购物车内。
|
||
# inputs:
|
||
# y:1D array,
|
||
# parameters:
|
||
# STATIC_THRESH:轨迹处于静止状态的阈值。
|
||
# outputs:
|
||
# 输出为差分值小于 STATIC_THRESH 的y中元素的(start, end)索引
|
||
# ranges = [(x1, y1),
|
||
# (x1, y1),
|
||
# ...]
|
||
# '''
|
||
# # print(f"The ID is: {self.tid}")
|
||
#
|
||
# # det_y = np.diff(y, axis=0)
|
||
# ranges, rangex = [], []
|
||
#
|
||
# static_indices = np.where(np.abs(det_y) < STATIC_THRESH)[0]
|
||
#
|
||
# if len(static_indices) == 0:
|
||
# rangex.append((0, len(det_y)))
|
||
# return ranges, rangex
|
||
#
|
||
# start_index = static_indices[0]
|
||
#
|
||
# for i in range(1, len(static_indices)):
|
||
# if static_indices[i] != static_indices[i-1] + 1:
|
||
# ranges.append((start_index, static_indices[i-1] + 1))
|
||
# start_index = static_indices[i]
|
||
# ranges.append((start_index, static_indices[-1] + 1))
|
||
#
|
||
# if len(ranges) == 0:
|
||
# rangex.append((0, len(det_y)))
|
||
# return ranges, rangex
|
||
#
|
||
# idx1, idx2 = ranges[0][0], ranges[-1][1]
|
||
#
|
||
# if idx1 != 0:
|
||
# rangex.append((0, idx1))
|
||
#
|
||
# # 轨迹的最后阶段是运动状态
|
||
# for k in range(1, len(ranges)):
|
||
# index1 = ranges[k-1][1]
|
||
# index2 = ranges[k][0]
|
||
# rangex.append((index1, index2))
|
||
#
|
||
# if idx2 != len(det_y):
|
||
# rangex.append((idx2, len(det_y)))
|
||
#
|
||
# return ranges, rangex
|
||
#
|
||
# =============================================================================
|
||
|
||
|
||
|
||
def is_static(self):
|
||
assert self.frnum > 1, "boxes number must greater than 1"
|
||
# print(f"The ID is: {self.tid}")
|
||
|
||
# 手部和小孩目标不考虑
|
||
if self.cls == 0 or self.cls == 9:
|
||
return False
|
||
|
||
# boxes 全部 y2=1280
|
||
if self.isBotmpoint:
|
||
return True
|
||
|
||
boxes = self.boxes
|
||
y0 = (boxes[:, 1]+boxes[:, 3])/2
|
||
|
||
## 纵轴矢量和
|
||
sum_y0 = y0[-1] - y0[0]
|
||
sum_y1 = boxes[-1, 1]-boxes[0, 1]
|
||
sum_y2 = boxes[-1, 3]-boxes[0, 3]
|
||
|
||
# 一些需要考虑的特殊情况
|
||
isbottom = max(boxes[:, 3]) > 1280-3
|
||
istop = min(boxes[:, 1]) < 3
|
||
isincart = min(y0) > self.CART_HIGH_THRESH1
|
||
uncert = abs(sum_y1)<100 and abs(sum_y2)<100
|
||
|
||
'''初始条件:商品中心点始终在购物车内、'''
|
||
condt0 = max((boxes[:, 1]+boxes[:, 3])/2) > self.CART_HIGH_THRESH1
|
||
|
||
'''条件1:轨迹运动纵向和(y1 或 y2)描述商品轨迹长度,存在情况:
|
||
(1). 检测框可能与图像上下边缘重合,
|
||
(2). 上边或下边存在跳动
|
||
'''
|
||
if isbottom and istop:
|
||
condt1 = abs(sum_y0) < 300
|
||
elif isbottom: # y2在底部,用y1表征运动
|
||
condt1 = sum_y1 > -120 and abs(sum_y0)<80 # 有底部点,方向向上阈值小于100
|
||
elif istop: # y1在顶部,用y2表征运动
|
||
condt1 = abs(sum_y2) < 100
|
||
else:
|
||
condt1 = (abs(sum_y1) < 30 or abs(sum_y2)<30)
|
||
|
||
'''条件2:轨迹的开始和结束阶段均处于静止状态, 利用静止状态区间判断,用 y1
|
||
a. 商品在购物车内,
|
||
b. 检测框的起始阶段和结束阶段均为静止状态
|
||
c. 静止帧长度 > 3'''
|
||
|
||
condt2 = False
|
||
if len(self.static_y1)>=2:
|
||
condt_s0 = self.static_y1[0][0]==0 and self.static_y1[0][1] - self.static_y1[0][0] >= 3
|
||
condt_s1 = self.static_y1[-1][1]==self.frnum-1 and self.static_y1[-1][1] - self.static_y1[-1][0] >= 3
|
||
condt2 = condt_s0 and condt_s1 and isincart
|
||
|
||
|
||
condt = condt0 and (condt1 or condt2)
|
||
|
||
return condt
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
def is_upward(self):
|
||
'''判断商品是否取出,'''
|
||
print(f"The ID is: {self.tid}")
|
||
|
||
def is_free_move(self):
|
||
if self.frnum == 1:
|
||
return True
|
||
# print(f"The ID is: {self.tid}")
|
||
|
||
|
||
y0 = (self.boxes[:, 1] + self.boxes[:, 3]) / 2
|
||
det_y0 = np.diff(y0, axis=0)
|
||
sum_y0 = y0[-1] - y0[0]
|
||
|
||
'''情况1:中心点向下 '''
|
||
## 初始条件:商品第一次检测到在购物车内
|
||
condt0 = y0[0] > self.CART_HIGH_THRESH1
|
||
|
||
condt_a = False
|
||
## 条件1:商品初始为静止状态,静止条件应严格一些
|
||
condt11, condt12 = False, False
|
||
if len(self.static_y1)>0:
|
||
condt11 = self.static_y1[0][0]==0 and self.static_y1[0][1] - self.static_y1[0][0] >= 5
|
||
if len(self.static_y2)>0:
|
||
condt12 = self.static_y2[0][0]==0 and self.static_y2[0][1] - self.static_y2[0][0] >= 5
|
||
|
||
# 条件2:商品中心发生向下移动
|
||
condt2 = y0[-1] > y0[0]
|
||
|
||
# 综合判断a
|
||
condt_a = condt0 and (condt11 or condt12) and condt2
|
||
|
||
'''情况2:中心点向上 '''
|
||
## 商品中心点向上移动,但没有关联的Hand轨迹,也不是左右边界点
|
||
condt_b = condt0 and len(self.Hands)==0 and y0[-1] < y0[0] and (not self.is_edge_cornpoint())
|
||
|
||
|
||
'''情况3: 商品在购物车内,但运动方向无序'''
|
||
## 中心点在购物车内,纵向轨迹和小于轨迹差中绝对值最大的两个值的和,说明运动没有主方向
|
||
condt_c = False
|
||
if self.frnum > 3:
|
||
condt_c = all(y0>self.CART_HIGH_THRESH1) and \
|
||
(abs(sum_y0) < sum(np.sort(np.abs(det_y0))[::-1][:2])-1)
|
||
|
||
condt = (condt_a or condt_b or condt_c) and self.cls!=0
|
||
|
||
return condt
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|