initial project version!

This commit is contained in:
王庆刚
2024-05-20 20:01:06 +08:00
commit d6f3693d3f
483 changed files with 60345 additions and 0 deletions

View File

@ -0,0 +1,329 @@
# -*- coding: utf-8 -*-
"""
Created on Mon Mar 4 18:28:47 2024
@author: ym
"""
import cv2
import numpy as np
from scipy.spatial.distance import cdist
from sklearn.decomposition import PCA
from .dotracks import MoveState, Track
class backTrack(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, imgshape=(1024, 1280)):
super().__init__(boxes, imgshape)
'''该函数依赖项: self.cornpoints'''
self.isCornpoint = self.isimgborder()
'''该函数依赖项: self.isCornpoint不能在父类中初始化'''
self.trajfeature()
'''静止点帧索引'''
self.static_index = self.compute_static_fids()
'''运动点帧索引(运动帧两端的静止帧索引)'''
self.moving_index = self.compute_dynamic_fids()
self.static_dynamic_fids = self.compute_static_dynamic_fids()
'''该函数依赖项: self.cornpoints定义 4 个商品位置变量:
self.Cent_isIncart, self.LB_isIncart, self.RB_isIncart
self.posState = self.Cent_isIncart+self.LB_isIncart+self.RB_isIncart'''
self.PositionState()
'''self.feature_ious = (incart_iou, outcart_iou, cartboarder_iou, maxbox_iou, minbox_iou)
self.incartrates = incartrates'''
self.compute_ious_feat()
# self.PCA()
def isimgborder(self, BoundPixel=10, BoundThresh=0.3):
x1, y1 = self.cornpoints[:,2], self.cornpoints[:,3],
x2, y2 = self.cornpoints[:,8], self.cornpoints[:,9]
cont1 = sum(abs(x1)<BoundPixel) / self.frnum > BoundThresh
cont2 = sum(abs(y1)<BoundPixel) / self.frnum > BoundThresh
cont3 = sum(abs(x2-self.imgshape[0])<BoundPixel) / self.frnum > BoundThresh
cont4 = sum(abs(y2-self.imgshape[1])<BoundPixel) / self.frnum > BoundThresh
cont = cont1 or cont2 or cont3 or cont4
isCornpoint = False
if cont:
isCornpoint = True
return isCornpoint
def PositionState(self, camerType="back"):
'''
camerType: back, 后置摄像头
front, 前置摄像头
'''
if camerType=="front":
incart = cv2.imread("./shopcart/cart_tempt/incart.png", cv2.IMREAD_GRAYSCALE)
else:
incart = cv2.imread("./shopcart/cart_tempt/incart_ftmp.png", cv2.IMREAD_GRAYSCALE)
xc, yc = self.cornpoints[:,0].clip(0,self.imgshape[0]-1).astype(np.int64), self.cornpoints[:,1].clip(0,self.imgshape[1]-1).astype(np.int64)
x1, y1 = self.cornpoints[:,6].clip(0,self.imgshape[0]-1).astype(np.int64), self.cornpoints[:,7].clip(0,self.imgshape[1]-1).astype(np.int64)
x2, y2 = self.cornpoints[:,8].clip(0,self.imgshape[0]-1).astype(np.int64), self.cornpoints[:,9].clip(0,self.imgshape[1]-1).astype(np.int64)
# print(self.tid)
Cent_inCartnum = np.count_nonzero(incart[(yc, xc)])
LB_inCartnum = np.count_nonzero(incart[(y1, x1)])
RB_inCartnum = np.count_nonzero(incart[(y2, x2)])
self.Cent_isIncart = False
self.LB_isIncart = False
self.RB_isIncart = False
if Cent_inCartnum: self.Cent_isIncart = True
if LB_inCartnum: self.LB_isIncart = True
if RB_inCartnum: self.RB_isIncart = True
self.posState = self.Cent_isIncart+self.LB_isIncart+self.RB_isIncart
def PCA(self):
self.pca = PCA()
X = self.cornpoints[:, 0:2]
self.pca.fit(X)
def compute_ious_feat(self):
'''输出:
self.feature_ious = (incart_iou, outcart_iou, cartboarder_iou, maxbox_iou, minbox_iou)
self.incartrates = incartrates
其中:
boxes流track中所有boxes形成的轨迹图可分为三部分incart, outcart, cartboarder
incart_iou, outcart_iou, cartboarder_iou各部分和 boxes流的 iou。
incart_iou = 0track在购物车外
outcart_iou = 0track在购物车内也可能是通过左下角、右下角置入购物车
maxbox_iou, minbox_ioutrack中最大、最小 box 和boxes流的iou二者差值越小越接近 1表明track的运动型越小。
incartrates: 各box和incart的iou时序由小变大反应的是置入过程由大变小反应的是取出过程
'''
incart = cv2.imread("./shopcart/cart_tempt/incart.png", cv2.IMREAD_GRAYSCALE)
outcart = cv2.imread("./shopcart/cart_tempt/outcart.png", cv2.IMREAD_GRAYSCALE)
cartboarder = cv2.imread("./shopcart/cart_tempt/cartboarder.png", cv2.IMREAD_GRAYSCALE)
incartrates = []
temp = np.zeros(incart.shape, np.uint8)
maxarea, minarea = 0, self.imgshape[0]*self.imgshape[1]
for i in range(self.frnum):
# x, y, w, h = self.boxes[i, 0:4]
x = (self.boxes[i, 2] + self.boxes[i, 0]) / 2
w = (self.boxes[i, 2] - self.boxes[i, 0]) / 2
y = (self.boxes[i, 3] + self.boxes[i, 1]) / 2
h = (self.boxes[i, 3] - self.boxes[i, 1]) / 2
if w*h > maxarea: maxarea = w*h
if w*h < minarea: minarea = w*h
cv2.rectangle(temp, (int(x-w/2), int(y-h/2)), (int(x+w/2), int(y+h/2)), 255, cv2.FILLED)
temp1 = np.zeros(incart.shape, np.uint8)
cv2.rectangle(temp1, (int(x-w/2), int(y-h/2)), (int(x+w/2), int(y+h/2)), 255, cv2.FILLED)
temp2 = cv2.bitwise_and(incart, temp1)
inrate = cv2.countNonZero(temp1)/(w*h)
incartrates.append(inrate)
isincart = cv2.bitwise_and(incart, temp)
isoutcart = cv2.bitwise_and(outcart, temp)
iscartboarder = cv2.bitwise_and(cartboarder, temp)
num_temp = cv2.countNonZero(temp)
num_incart = cv2.countNonZero(isincart)
num_outcart = cv2.countNonZero(isoutcart)
num_cartboarder = cv2.countNonZero(iscartboarder)
incart_iou = num_incart/num_temp
outcart_iou = num_outcart/num_temp
cartboarder_iou = num_cartboarder/num_temp
maxbox_iou = maxarea/num_temp
minbox_iou = minarea/num_temp
self.feature_ious = (incart_iou, outcart_iou, cartboarder_iou, maxbox_iou, minbox_iou)
self.incartrates = incartrates
def compute_static_fids(self, thresh1 = 12, thresh2 = 3):
'''
计算 track 的轨迹中相对处于静止状态的轨迹点的start_frame_id, end_frame_id
thresh1: 相邻两帧目标中心点是否静止的的阈值,以像素为单位,
thresh2: 连续捕捉到目标处于静止状态的帧数,当 thresh2 = 3时,至少连续 4个点,
产生3个相邻点差值均小于 thresh1 时,判定为连续静止.
处理过程中利用了插值技术因此start、end并非 self.boxes 中对应的帧索引
'''
BoundPixel = 8
x1, y1 = self.cornpoints[:,2], self.cornpoints[:,3],
x2, y2 = self.cornpoints[:,8], self.cornpoints[:,9]
cont1 = sum(abs(x1)<BoundPixel) > 3
# cont2 = sum(abs(y1)<BoundPixel) > 3
cont3 = sum(abs(x2-self.imgshape[0])<BoundPixel) > 3
# cont4 = sum(abs(y2-self.imgshape[1])<BoundPixel) > 3
cont = not(cont1 or cont3)
## ============== 下一步,启用中心点,选择具有最小运动幅度的角点作为参考点
static_index = []
if self.frnum>=2 and cont:
x1 = self.boxes[1:,7]
x2 = [i for i in range(int(min(x1)), int(max(x1)+1))]
dist_adjc = np.interp(x2, x1, self.trajmin)
# dist_adjc = self.trajmin
static_thresh = (dist_adjc < thresh1)[:, None].astype(np.uint8)
static_cnts, _ = cv2.findContours(static_thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
for cnt in static_cnts:
_, start, _, num = cv2.boundingRect(cnt)
end = start + num
if num < thresh2:
continue
static_index.append((start, end))
static_index = np.array(static_index)
if static_index.size:
indx = np.argsort(static_index[:, 0])
static_index = static_index[indx]
return static_index
def compute_dynamic_fids(self, thresh1 = 12, thresh2 = 3):
'''
计算 track 的轨迹中运动轨迹点的start_frame_id, end_frame_id
thresh1: 相邻两帧目标中心点是否运动的阈值,以像素为单位,
thresh2: 连续捕捉到目标连续运动的帧数
目标:
1. 计算轨迹方向
2. 计算和手部运动的关联性
'''
moving_index = []
if self.frnum>=2:
x1 = self.boxes[1:,7]
x2 = [i for i in range(int(min(x1)), int(max(x1)+1))]
dist_adjc = np.interp(x2, x1, self.trajmin)
moving_thresh = (dist_adjc >= thresh1)[:, None].astype(np.uint8)
moving_cnts, _ = cv2.findContours(moving_thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
for cnt in moving_cnts:
_, start, _, num = cv2.boundingRect(cnt)
if num < thresh2:
continue
end = start + num
moving_index.append((start, end))
# =============================================================================
# '''========= 输出帧id不太合适 ========='''
# moving_fids = []
# for i in range(len(moving_index)):
# i1, i2 = moving_index[i]
# fid1, fid2 = boxes[i1, 7], boxes[i2, 7]
# moving_fids.append([fid1, fid2])
# moving_fids = np.array(moving_fids)
# =============================================================================
moving_index = np.array(moving_index)
if moving_index.size:
indx = np.argsort(moving_index[:, 0])
moving_index = moving_index[indx]
return moving_index
def compute_static_dynamic_fids(self):
static_dynamic_fids = []
for traj in self.trajectory:
static, dynamic = self.compute_static_fids(traj)
static_dynamic_fids.append((static, dynamic))
return static_dynamic_fids
def is_static(self):
'''静态情况 1: 目标关键点最小相对运动轨迹 < 0.2, 指标值偏大
feature = [trajlen_min, trajlen_max,
trajdist_min, trajdist_max,
trajlen_rate, trajdist_rate]
'''
condt1 = self.feature[5] < 0.2 or self.feature[3] < 120
'''静态情况 2: 目标初始状态为静止,适当放宽关键点最小相对运动轨迹 < 0.5'''
condt2 = self.static_index.size > 0 \
and self.static_index[0, 0] <= 2 \
and self.feature[5] < 0.5
'''静态情况 3: 目标初始状态和最终状态均为静止'''
condt3 = self.static_index.shape[0] >= 2 \
and self.static_index[0, 0] <= 2 \
and self.static_index[-1, 1] >= self.frnum-3 \
condt = condt1 or condt2 or condt3
return condt
# =============================================================================
# track1 = [t for t in tracks if t.feature[5] < 0.2
# or t.feature[3] < 120
# ]
#
# track2 = [t for t in tracks if t.static_index.size > 0
# and t.static_index[0, 0] <= 2
# and t.feature[5] < 0.5]
#
# track3 = [t for t in tracks if t.static_index.shape[0] >= 2
# and t.static_index[0, 0] <= 2
# and t.static_index[-1, 1] >= t.frnum-3]
#
# track12 = self.join_tracks(track1, track2)
#
# '''提取静止状态的 track'''
# static_tracks = self.join_tracks(track12, track3)
# self.Static.extend(static_tracks)
#
# =============================================================================
def is_OutTrack(self):
if self.posState <= 1:
isout = True
else:
isout = False
return isout
def compute_distance(self):
pass
def move_start_fid(self):
pass
def move_end_fid(self):
pass