From 106c281870aaa85583740f981986715a60a59d89 Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Tue, 20 Jun 2023 18:25:08 +0200 Subject: Renaming size into points_number. Adding bounds and size method. Moving AOIFrame class at the end of the file. --- src/argaze/AreaOfInterest/AOIFeatures.py | 210 +++++++++++++++++-------------- 1 file changed, 113 insertions(+), 97 deletions(-) diff --git a/src/argaze/AreaOfInterest/AOIFeatures.py b/src/argaze/AreaOfInterest/AOIFeatures.py index 4a109a8..548382c 100644 --- a/src/argaze/AreaOfInterest/AOIFeatures.py +++ b/src/argaze/AreaOfInterest/AOIFeatures.py @@ -46,7 +46,7 @@ class AreaOfInterest(numpy.ndarray): return self.shape[1] @property - def size(self) -> int: + def points_number(self) -> int: """Number of points defining the area.""" return self.shape[0] @@ -58,12 +58,29 @@ class AreaOfInterest(numpy.ndarray): return self.shape[0] == 0 @property + def bounds(self) -> numpy.array: + """Get area's bounds.""" + + min_bounds = numpy.min(self, axis=0) + max_bounds = numpy.max(self, axis=0) + + return numpy.array([min_bounds, max_bounds]) + + @property def center(self) -> numpy.array: """Center of mass.""" return self.mean(axis=0) @property + def size(self) -> numpy.array: + """Get scene size.""" + + min_bounds, max_bounds = self.bounds + + return max_bounds - min_bounds + + @property def area(self) -> float: """Area of the polygon defined by aoi's points.""" @@ -75,14 +92,14 @@ class AreaOfInterest(numpy.ndarray): !!! warning Available for 2D AOI only.""" - assert(self.size > 1) + assert(self.points_number > 1) assert(self.dimension == 2) min_x, min_y = numpy.min(self, axis=0) max_x, max_y = numpy.max(self, axis=0) return numpy.array([(min_x, min_y), (max_x, min_y), (max_x, max_y), (min_x, max_y)]) - + def clockwise(self) -> AreaOfInterestType: """Get area points in clockwise order. !!! warning @@ -203,100 +220,6 @@ class AreaOfInterest(numpy.ndarray): center_pixel = numpy.rint(self.center).astype(int) cv2.circle(frame, center_pixel, 1, color, -1) -AOIFrameType = TypeVar('AOIFrame', bound="AOIFrame") -# Type definition for type annotation convenience - -class AOIFrame(): - """Define frame to draw into 2D AOI.""" - - def __init__(self, aoi: AreaOfInterestType, size: tuple): - """ - !!! warning - Available for 2D AOI only.""" - - assert(aoi.dimension == 2) - - self.__rX, self.__rY = size - - # Init coordinates - self.__Sx = numpy.linspace(0., self.__rX/self.__rY, self.__rX) - self.__Sy = numpy.linspace(0., 1., self.__rY) - - # Init heatmap - self.heatmap_init() - - def point_spread(self, point: tuple, sigma: float): - """Draw gaussian point spread into frame.""" - - div = -2 * sigma**2 - - x = point[0] / self.__rY # we use rY not rX !!! - y = point[1] / self.__rY - - dX2 = (self.__Sx - x)**2 - dY2 = (self.__Sy - y)**2 - - v_dX, v_dY = numpy.array(numpy.meshgrid(dX2, dY2)).reshape(2, -1) - - return numpy.exp((v_dX + v_dY) / div).reshape(self.__rY, self.__rX) - - def heatmap_init(self, buffer_size: int = 0): - """Initialize heatmap matrix.""" - - self.__point_spread_sum = numpy.zeros((self.__rY, self.__rX)) - self.__point_spread_buffer = [] - self.__point_spread_buffer_size = buffer_size - - def heatmap_update(self, point: tuple, sigma: float): - """Update heatmap matrix. - - !!! danger - Call heatmap_init() method before any update.""" - - point_spread = self.point_spread(point, sigma) - - # Sum point spread - self.__point_spread_sum += point_spread - - # If point spread buffering enabled - if self.__point_spread_buffer_size > 0: - - self.__point_spread_buffer.append(point_spread) - - # Remove oldest point spread buffer frame - if len(self.__point_spread_buffer) > self.__point_spread_buffer_size: - - self.__point_spread_sum -= self.__point_spread_buffer.pop(0) - - # Edit heatmap - heatmap_gray = (255 * self.__point_spread_sum / numpy.max(self.__point_spread_sum)).astype(numpy.uint8) - self.__heatmap_matrix = cv2.applyColorMap(heatmap_gray, cv2.COLORMAP_JET) - - @property - def heatmap_buffer(self) -> int: - """Get size of heatmap buffer.""" - - return self.__point_spread_buffer_size - - @heatmap_buffer.setter - def heatmap_buffer(self, size: int): - """Set size of heatmap buffer (0 means no buffering).""" - - self.__point_spread_buffer = [] - self.__point_spread_buffer_size = size - - @property - def heatmap(self): - """Get heatmap matrix.""" - - try: - - return self.__heatmap_matrix - - except AttributeError: - - return numpy.zeros((self.__rY, self.__rX, 3)).astype(numpy.uint8) - AOISceneType = TypeVar('AOIScene', bound="AOIScene") # Type definition for type annotation convenience @@ -446,3 +369,96 @@ class TimeStampedAOIScenes(DataStructures.TimeStampedBuffer): super().__setitem__(ts, scene) +AOIFrameType = TypeVar('AOIFrame', bound="AOIFrame") +# Type definition for type annotation convenience + +class AOIFrame(): + """Define frame to draw into 2D AOI.""" + + def __init__(self, aoi: AreaOfInterestType, size: tuple): + """ + !!! warning + Available for 2D AOI only.""" + + assert(aoi.dimension == 2) + + self.__rX, self.__rY = size + + # Init coordinates + self.__Sx = numpy.linspace(0., self.__rX/self.__rY, self.__rX) + self.__Sy = numpy.linspace(0., 1., self.__rY) + + # Init heatmap + self.heatmap_init() + + def point_spread(self, point: tuple, sigma: float): + """Draw gaussian point spread into frame.""" + + div = -2 * sigma**2 + + x = point[0] / self.__rY # we use rY not rX !!! + y = point[1] / self.__rY + + dX2 = (self.__Sx - x)**2 + dY2 = (self.__Sy - y)**2 + + v_dX, v_dY = numpy.array(numpy.meshgrid(dX2, dY2)).reshape(2, -1) + + return numpy.exp((v_dX + v_dY) / div).reshape(self.__rY, self.__rX) + + def heatmap_init(self, buffer_size: int = 0): + """Initialize heatmap matrix.""" + + self.__point_spread_sum = numpy.zeros((self.__rY, self.__rX)) + self.__point_spread_buffer = [] + self.__point_spread_buffer_size = buffer_size + + def heatmap_update(self, point: tuple, sigma: float): + """Update heatmap matrix. + + !!! danger + Call heatmap_init() method before any update.""" + + point_spread = self.point_spread(point, sigma) + + # Sum point spread + self.__point_spread_sum += point_spread + + # If point spread buffering enabled + if self.__point_spread_buffer_size > 0: + + self.__point_spread_buffer.append(point_spread) + + # Remove oldest point spread buffer frame + if len(self.__point_spread_buffer) > self.__point_spread_buffer_size: + + self.__point_spread_sum -= self.__point_spread_buffer.pop(0) + + # Edit heatmap + heatmap_gray = (255 * self.__point_spread_sum / numpy.max(self.__point_spread_sum)).astype(numpy.uint8) + self.__heatmap_matrix = cv2.applyColorMap(heatmap_gray, cv2.COLORMAP_JET) + + @property + def heatmap_buffer(self) -> int: + """Get size of heatmap buffer.""" + + return self.__point_spread_buffer_size + + @heatmap_buffer.setter + def heatmap_buffer(self, size: int): + """Set size of heatmap buffer (0 means no buffering).""" + + self.__point_spread_buffer = [] + self.__point_spread_buffer_size = size + + @property + def heatmap(self): + """Get heatmap matrix.""" + + try: + + return self.__heatmap_matrix + + except AttributeError: + + return numpy.zeros((self.__rY, self.__rX, 3)).astype(numpy.uint8) -- cgit v1.1