99
1010from utils .analysis import angle_between_vectors , calculate_distance , EllipseROI , RectangleROI
1111from utils .configloader import RESOLUTION
12-
12+ from collections import deque
13+ import numpy as np
1314"""Single posture triggers"""
1415
1516class HeaddirectionROITrigger :
@@ -333,15 +334,20 @@ def check_skeleton(self, skeleton: dict):
333334
334335class FreezeTrigger :
335336 """
336- Trigger to check if animal is in freezing state
337+ Trigger to check if animal is moving below a certain speed
337338 """
338- def __init__ (self , threshold : int , debug : bool = False ):
339+ def __init__ (self , threshold : int , bodypart : str , timewindow_len : int = 2 , debug : bool = False ):
339340 """
340341 Initializing trigger with given threshold
341342 :param threshold: int in pixel how much of a movement does not count
342- For example threshold of 5 would mean that all movements less then 5 pixels would be ignored
343+ :param bodypart: str of body part in skeleton used for speed calculation
344+ For example threshold of 5 would mean that all movements more then 5 pixels in the last timewindow length frames
345+ would be ignored
343346 """
347+ self ._bodypart = bodypart
344348 self ._threshold = threshold
349+ self ._timewindow_len = timewindow_len
350+ self ._timewindow = deque (maxlen = timewindow_len )
345351 self ._skeleton = None
346352 self ._debug = debug # not used in this trigger
347353
@@ -354,45 +360,49 @@ def check_skeleton(self, skeleton: dict):
354360 """
355361 # choosing a point to draw near the skeleton
356362 org_point = skeleton [list (skeleton .keys ())[0 ]]
357- joint_moved = []
363+ joint_moved = 0
364+
358365 if self ._skeleton is None :
359366 result = False
360- text = 'Not freezing '
367+ text = '... '
361368 self ._skeleton = skeleton
362369 else :
363- for joint in skeleton :
364- joint_travel = calculate_distance (skeleton [joint ], self ._skeleton [joint ])
365- joint_moved .append (abs (joint_travel ) <= self ._threshold )
366- if all (joint_moved ):
370+ joint_travel = calculate_distance (skeleton [self ._bodypart ], self ._skeleton [self ._bodypart ])
371+ self ._timewindow .append (joint_travel )
372+ if len (self ._timewindow ) == self ._timewindow_len :
373+ joint_moved = np .sum (self ._timewindow )
374+
375+ if abs (joint_moved ) <= self ._threshold :
367376 result = True
368377 text = 'Freezing'
369378 else :
370379 result = False
371- text = 'Not freezing'
372- self ._skeleton = skeleton
373-
380+ text = 'Not Freezing'
381+ self ._skeleton = skeleton
374382 color = (0 , 255 , 0 ) if result else (0 , 0 , 255 )
375383 response_body = {'plot' : {'text' : dict (text = text ,
376384 org = org_point ,
377385 color = color )}}
378386 response = (result , response_body )
379- return response
380387
388+ return response
381389
382390class SpeedTrigger :
383391 """
384392 Trigger to check if animal is moving above a certain speed
385393 """
386- def __init__ (self , threshold : int , bodypart : str = 'any' , debug : bool = False ):
394+ def __init__ (self , threshold : int , bodypart : str , timewindow_len : int = 2 , debug : bool = False ):
387395 """
388396 Initializing trigger with given threshold
389397 :param threshold: int in pixel how much of a movement does not count
390- :param bodypart: str or list of str, bodypart or list of bodyparts in skeleton to use for trigger,
391- if "any" will check if any bodypart reaches treshold; default "any"
392- For example threshold of 5 would mean that all movements less then 5 pixels would be ignored
398+ :param bodypart: str of body part in skeleton used for speed calculation
399+ For example threshold of 5 would mean that all movements less then 5 pixels in the last timewindow length frames
400+ would be ignored
393401 """
394402 self ._bodypart = bodypart
395403 self ._threshold = threshold
404+ self ._timewindow_len = timewindow_len
405+ self ._timewindow = deque (maxlen = timewindow_len )
396406 self ._skeleton = None
397407 self ._debug = debug # not used in this trigger
398408
@@ -405,36 +415,29 @@ def check_skeleton(self, skeleton: dict):
405415 """
406416 # choosing a point to draw near the skeleton
407417 org_point = skeleton [list (skeleton .keys ())[0 ]]
408- joint_moved = []
418+ joint_moved = 0
419+
409420 if self ._skeleton is None :
410421 result = False
411- text = 'First frame '
422+ text = '... '
412423 self ._skeleton = skeleton
413424 else :
414- if self ._bodypart is "any" :
415- for joint in skeleton :
416- joint_travel = calculate_distance (skeleton [joint ], self ._skeleton [joint ])
417- joint_moved .append (abs (joint_travel ) >= self ._threshold )
418-
419- elif isinstance (self ._bodypart , list ):
420- for joint in self ._bodypart :
421- joint_travel = calculate_distance (skeleton [joint ], self ._skeleton [joint ])
422- joint_moved .append (abs (joint_travel ) >= self ._threshold )
423- else :
424- joint_travel = calculate_distance (skeleton [self ._bodypart ], self ._skeleton [self ._bodypart ])
425- joint_moved .append (abs (joint_travel ) >= self ._threshold )
425+ joint_travel = calculate_distance (skeleton [self ._bodypart ], self ._skeleton [self ._bodypart ])
426+ self ._timewindow .append (joint_travel )
427+ if len (self ._timewindow ) == self ._timewindow_len :
428+ joint_moved = np .sum (self ._timewindow )
426429
427- if all (joint_moved ):
430+ if abs (joint_moved ) >= self . _threshold :
428431 result = True
429432 text = 'Running'
430433 else :
431434 result = False
432- text = ''
433- self ._skeleton = skeleton
434-
435+ text = 'Not Running'
436+ self ._skeleton = skeleton
435437 color = (0 , 255 , 0 ) if result else (0 , 0 , 255 )
436438 response_body = {'plot' : {'text' : dict (text = text ,
437439 org = org_point ,
438440 color = color )}}
439441 response = (result , response_body )
442+
440443 return response
0 commit comments