@@ -50,6 +50,7 @@ def __init__(self,
5050 self .logger = logging .getLogger (__name__ )
5151 self .params = StaticVideoTrackerParameter ()
5252 self .first_frame = first_frame
53+ self .frame_heigt , self .frame_width = first_frame .shape [:2 ]
5354 self .limit_searchspace = limit_searchspace
5455 self .first_tracking_bbox = tracking_bbox
5556 self .supervised_tracking_area = supervised_tracking_area
@@ -69,6 +70,7 @@ def __init__(self,
6970 self .lats_detected_tracking_box = tracking_bbox
7071 self .last_valid_tracking_box = tracking_bbox
7172 self .supervised_tracking_is_exit_condition = supervised_tracking_is_exit_condition
73+ self .last_box_was_in_tracking_area = True
7274
7375
7476 @dataclass
@@ -227,6 +229,129 @@ def create_tracking_box(box: tuple):
227229 return (box [0 ], box [1 ], box [2 ], box [3 ], center [0 ], center [1 ])
228230
229231
232+ def move_box_by (self , box : tuple , x0 : int , y0 : int ) -> tuple :
233+ """ Move box by given (x, y)
234+
235+ Args:
236+ box: the tracking box
237+ x0: shift value in x direction
238+ y0: shift value in y direction
239+ """
240+ return (
241+ min (( self .frame_width , max ((0 , box [0 ] + x0 )) )),
242+ min (( self .frame_heigt , max ((0 , box [1 ] + y0 )) )),
243+ box [2 ],
244+ box [3 ],
245+ min (( self .frame_width , max ((0 , box [4 ] + x0 )) )),
246+ min (( self .frame_heigt , max ((0 , box [5 ] + y0 )) ))
247+ )
248+
249+
250+ def move_box_to (self , box : tuple , cx : int , cy : int ) -> tuple :
251+ """ Move box to given (x, y) center coordinates
252+
253+ Args:
254+ box: the tracking box
255+ x0: shift value in x direction
256+ y0: shift value in y direction
257+ """
258+ return self .move_box_by (box , cx - box [4 ], cy - box [5 ])
259+
260+
261+ @staticmethod
262+ def get_line_intersection (line1 , line2 ):
263+ """ Compute the intersection point of two lines
264+
265+ Args:
266+ line1 (list): [[x1,y1], [x2,y2]]
267+ line2 (list): [[x1,y1], [x2,y2]]
268+
269+ Returns:
270+ tuple: (x, y)
271+ """
272+ xdiff = (line1 [0 ][0 ] - line1 [1 ][0 ], line2 [0 ][0 ] - line2 [1 ][0 ])
273+ ydiff = (line1 [0 ][1 ] - line1 [1 ][1 ], line2 [0 ][1 ] - line2 [1 ][1 ])
274+
275+ def det (a , b ):
276+ return a [0 ] * b [1 ] - a [1 ] * b [0 ]
277+
278+ div = det (xdiff , ydiff )
279+ if div == 0 :
280+ return None
281+
282+ d = (det (* line1 ), det (* line2 ))
283+ x = det (d , xdiff ) / div
284+ y = det (d , ydiff ) / div
285+ return (round (x ), round (y ))
286+
287+
288+ def get_border_box (self , last_valid_box , invalid_box ) -> tuple :
289+ """ Calculate the intersection with the tracking area to predict a box exacly
290+ at the border of the tracking area.
291+
292+ Args:
293+ last_valid_box (tuple): last valid tracking box
294+ invert_box (tuple): box that is outside the tracking area
295+
296+ Returns:
297+ tuple: border box
298+ """
299+ if invalid_box is None :
300+ return last_valid_box
301+
302+ if self .supervised_tracking_area is None :
303+ return last_valid_box
304+
305+ x0 = self .supervised_tracking_area [0 ]
306+ y0 = self .supervised_tracking_area [1 ]
307+ x1 = self .supervised_tracking_area [0 ] + self .supervised_tracking_area [2 ]
308+ y1 = self .supervised_tracking_area [1 ] + self .supervised_tracking_area [3 ]
309+
310+ # left top point
311+ if invalid_box [4 ] < x0 and invalid_box [5 ] < y0 :
312+ return self .move_box_to (invalid_box , x0 , y0 )
313+
314+ # left bottom point
315+ if invalid_box [4 ] < x0 and invalid_box [5 ] > y1 :
316+ return self .move_box_to (invalid_box , x0 , y1 )
317+
318+ # left bottom point
319+ if invalid_box [4 ] > x1 and invalid_box [5 ] > y1 :
320+ return self .move_box_to (invalid_box , x1 , y1 )
321+
322+ # right top point
323+ if invalid_box [4 ] > x1 and invalid_box [5 ] < y0 :
324+ return self .move_box_to (invalid_box , x1 , y0 )
325+
326+ line1 = [ [invalid_box [4 ], invalid_box [5 ]], [last_valid_box [4 ], last_valid_box [5 ]] ]
327+
328+ # left
329+ if invalid_box [4 ] <= x0 :
330+ intersection = self .get_line_intersection (line1 , [ [x0 , y0 ], [x0 , y1 ] ])
331+ if intersection :
332+ return self .move_box_to (invalid_box , intersection [0 ], intersection [1 ])
333+
334+ # bottom
335+ if invalid_box [5 ] >= y1 :
336+ intersection = self .get_line_intersection (line1 , [ [x0 , y1 ], [x1 , y1 ] ])
337+ if intersection :
338+ return self .move_box_to (invalid_box , intersection [0 ], intersection [1 ])
339+
340+ # right
341+ if invalid_box [4 ] >= x1 :
342+ intersection = self .get_line_intersection (line1 , [ [x1 , y1 ], [x1 , y0 ] ])
343+ if intersection :
344+ return self .move_box_to (invalid_box , intersection [0 ], intersection [1 ])
345+
346+ # top
347+ if invalid_box [5 ] <= y0 :
348+ intersection = self .get_line_intersection (line1 , [ [x1 , y0 ], [x0 , y0 ] ])
349+ if intersection :
350+ return self .move_box_to (invalid_box , intersection [0 ], intersection [1 ])
351+
352+ return last_valid_box
353+
354+
230355 def run (self ) -> None :
231356 """ The Video Tracker Thread Function """
232357 self .__setup_tracker ()
@@ -276,14 +401,19 @@ def run(self) -> None:
276401 if self .params .tracking_plausibility_check :
277402 if not self .__is_plausible (bbox ):
278403 status = StaticVideoTracker .Status .IMPLAUSIBLE
279- elif not StaticVideoTracker .is_bbox_in_tracking_area (bbox , self .supervised_tracking_area ):
404+ elif StaticVideoTracker .is_bbox_in_tracking_area (bbox , self .supervised_tracking_area ):
405+ self .last_box_was_in_tracking_area = True
406+ else :
280407 if self .supervised_tracking_is_exit_condition :
281408 status = StaticVideoTracker .Status .FEATURE_OUTSIDE
282409 else :
283- bbox = self .last_valid_tracking_box
284- elif self .supervised_tracking_area is not None and not self .supervised_tracking_is_exit_condition :
285- # TODO: When we insert the tracking area again make sure the point is below/above the last valid box
286- pass
410+ if self .last_box_was_in_tracking_area :
411+ self .last_box_was_in_tracking_area = False
412+ self .last_valid_tracking_box = self .get_border_box (self .last_valid_tracking_box , bbox )
413+ self .logger .info ("Determine Border Intersection with box: %s" , str (self .last_valid_tracking_box ))
414+ bbox = self .last_valid_tracking_box
415+ else :
416+ bbox = self .last_valid_tracking_box
287417
288418
289419 self .queue_out .put ((status , bbox ))
0 commit comments