from dataclasses import dataclass, field from numbers import Number from typing import Optional, Dict, Deque from collections import deque import numpy as np from dataclasses_json import dataclass_json, config import utils @dataclass_json @dataclass class Point: x:float y:float def __iter__(self): # 使对象可迭代,可直接转为元组 yield self.x yield self.y @dataclass class RectangleArea: x: int y: int w: int h: int @classmethod def from_dict(cls, data: dict): return cls( x=data['x'], y=data['y'], w=data['w'], h = data['h']) @dataclass class Threshold: binary: int gauss: int @dataclass_json @dataclass class TargetInfo: # 标靶方形区域 rectangle_area:RectangleArea threshold:Threshold # 标靶物理半径 radius:float=0.0 id:int =-1 desc:str="" base:bool=False def __init__(self,id,desc,rectangle_area:RectangleArea,radius,threshold:Threshold,base:bool,**kwargs): self.id = id self.desc = desc self.rectangle_area=rectangle_area self.radius=radius self.threshold=threshold self.base=base @classmethod def from_dict(cls,data: dict): return cls(data['id'],data['rectangle_area'],data['radius']) @dataclass_json @dataclass class HandlerInfo: # 初始话 is_init=True radius_pix:float= 1.0 pix_length:float=0.0 # 标靶中心 center_point_queue:Deque[Point] = field(default_factory=lambda: deque(maxlen=10)) center_point: Optional[Point]= field(default=None, metadata=config(exclude=lambda x: x is None)) center_init : Optional[Point]= field(default=None, metadata=config(exclude=lambda x: x is None)) # 标靶位移(像素) displacement_pix: Optional[Point]= field(default=None, metadata=config(exclude=lambda x: x is None)) displacement_phy: Optional[Point]= field(default=None, metadata=config(exclude=lambda x: x is None)) def calculate_mean(self)-> Point: """计算队列中所有数据的均值""" if self.center_point_queue: length=len(self.center_point_queue) mean_x = sum(p.x for p in self.center_point_queue) / length mean_y = sum(p.y for p in self.center_point_queue) / length return Point(mean_x, mean_y) else: return None def enqueue_center_point(self, data) -> Point: """入队操作""" self.center_point_queue.append(data) return self.calculate_mean() @dataclass_json @dataclass class CircleTarget: # 标靶方形区域 info:TargetInfo # 标靶透视矩阵 perspective: np.ndarray = field( metadata=config( encoder=utils.encode_perspective, decoder=utils.decode_perspective ) ) handler_info: Optional[HandlerInfo]=None # def __init__(self,info:TargetInfo,center_point,center_init,displacement_pix,displacement_phy): # self.info=info # self.center_point=center_point # self.center_init=center_init # self. displacement_pix=displacement_pix # self.displacement_phy=displacement_phy @classmethod def init_by_info(cls,t:TargetInfo): return CircleTarget(t,None,None,None,None) def circle_displacement_pix(self): previous = self.handler_info.center_init if previous != (): self.handler_info.displacement_pix = Point(self.handler_info.center_point.x - previous.x, self.handler_info.center_point.y - previous.y) return self def circle_displacement_phy(self): if self.info.radius != 0 and self.handler_info.displacement_pix is not None: # 单位像素->距离 self.handler_info.pix_length = self.info.radius / self.handler_info.radius_pix offset_x = round(float(self.handler_info.displacement_pix.x * self.handler_info.pix_length), 5) offset_y = round(float(self.handler_info.displacement_pix.y * self.handler_info.pix_length), 5) self.handler_info.displacement_phy = Point(offset_x, offset_y) return self