From 789329494398d776d993a6b3a1dc4e21c8e1ec5c Mon Sep 17 00:00:00 2001 From: Justin Date: Mon, 17 May 2021 21:16:51 -0600 Subject: [PATCH] Tests and minor fixes v2.26 - Setting region on nameless person will now prompt a dialog box to prevent overwriting names - Tests written for Regions and renamed test_tracker to test_Multitracker - Fixed an issue with predictor being tracked with a location of -1 x and assuming a reset position, but failing to actually reset caused values to be passed as None and resulted in crash --- src/filters.py | 4 +- src/multitracker.py | 29 +++--- src/{test_tracker.py => test_Multitracker.py} | 2 +- src/test_Regions.py | 89 +++++++++++++++++++ 4 files changed, 110 insertions(+), 14 deletions(-) rename src/{test_tracker.py => test_Multitracker.py} (99%) create mode 100644 src/test_Regions.py diff --git a/src/filters.py b/src/filters.py index b892c0e..9b9ea06 100644 --- a/src/filters.py +++ b/src/filters.py @@ -11,7 +11,7 @@ def __init__(self, white=False): def reset(self, white=False): - self.previous_location = np.array((-1,-1)) + self.previous_location = np.array((float('inf'),float('inf'))) self.k_filter = KalmanFilter(dim_x=4, dim_z=4) @@ -55,7 +55,7 @@ def reset(self, white=False): def predict(self, location=None): # Indicates user set a new location or starting a new tracker - if self.previous_location[0] == -1: + if self.previous_location[0] == float('inf'): self.previous_location = np.array(location) diff --git a/src/multitracker.py b/src/multitracker.py index 4a522a0..aaffefb 100644 --- a/src/multitracker.py +++ b/src/multitracker.py @@ -33,7 +33,7 @@ CPU_COUNT = multiprocessing.cpu_count() #start tracking version at 1.0 -PEOPLETRACKER_VERSION = 2.25 +PEOPLETRACKER_VERSION = 2.26 # For extracting video metadata # import mutagen @@ -657,21 +657,28 @@ def display_radius(self, frame): def test_radius(self, test_point): """ - Tests weather a point value exists within a radius + Tests weather a point value exists within an eclipse + p <= 1 exists in or on eclipse - Equation: Given (x-h)^2/a^2 + (y-k)^2/b^2 <= 1 - Given a test_point (x,y), ellipse_center at (h,k), + Equation: Given p = (x-h)^2/a^2 + (y-k)^2/b^2 + Where test_point is (x,y) and ellipse_center is (h,k), radius_width, radius_height as a,b respectivly + + Returns list(regions), p """ #overlapping areas may result in multiple True tests within_points = [] test_x = test_point[0] test_y = test_point[1] - + p = float('inf') for key, region in self.radius_regions.items(): x, y, w, h = region[0], region[1], region[2], region[3] + #Invalid inputs are areas with zero or less, return no region and invalid p value + if w <= 0 or h <= 0: + return [], float("inf") + #handle if devisor == 0 denom_x = math.pow((w/2), 2) denom_y = math.pow((h/2), 2) @@ -687,12 +694,11 @@ def test_radius(self, test_point): p = ((math.pow((test_x - ellipse_center[0]), 2) / denom_x) + (math.pow((test_y - ellipse_center[1]), 2) / denom_y)) except ZeroDivisionError as zerodiverr: - print(zerodiverr) - p = -1 + p = float("inf") # Does not count inside the eclipse if p <= 1: #point exists in or on eclipse within_points.append(key) - return within_points + return within_points, p def handle_inputs(): pass @@ -1280,6 +1286,9 @@ def export_meta(vid_dir): center_y = top_left_y + (height/2) # cv2.circle(frame, (box[0],box[1]), 10, (0,0,255)) + if tracker.is_region() is True and tracker.get_name().strip() == "": + input_dialog.tab_list[tracker_num].getText(input_name="Region Name:",line=input_dialog.tab_list[tracker_num].name_line) + if tracker.is_region() is True and tracker.get_name() != "": regions.set_moving_radius(name = tracker.get_name(), @@ -1346,7 +1355,7 @@ def export_meta(vid_dir): # bottom = (int(center_x), int(center_y - height/2)) # cv2.circle(frame, top, 3, (0,255,255),-1) # cv2.circle(frame, bottom, 3, (0,255,255),-1) - in_region = regions.test_radius((center_x, center_y)) + in_region, p = regions.test_radius((center_x, center_y)) if input_dialog.play_state == True and input_dialog.tab_list[tracker_num].read_only is False: #record all the data collected from that frame @@ -1458,7 +1467,6 @@ def export_meta(vid_dir): # print(frame_number) frame_number = input_dialog.get_scrollbar_value() # regions.del_moving_radius(tracker.get_name()) - # print(selected_tracker, tracker_num) if frame_number in tracker.data_dict: # print("Exists") @@ -1466,7 +1474,6 @@ def export_meta(vid_dir): # point, regions, dimensions, other_room, total_people center, _, dim, other_room, total_people, is_chair = tracker.data_dict[frame_number] # print(frame_number, center) - if tracker.is_region() is True and tracker.get_name() != "": point = (int(center[0] - dim[0]), int(center[1] - dim[1])) diff --git a/src/test_tracker.py b/src/test_Multitracker.py similarity index 99% rename from src/test_tracker.py rename to src/test_Multitracker.py index 0b010d2..1d55502 100644 --- a/src/test_tracker.py +++ b/src/test_Multitracker.py @@ -1,4 +1,4 @@ -from multitracker import MultiTracker +from multitracker import MultiTracker, Regions from qt_dialog import person_tab from PyQt5 import QtWidgets import sys diff --git a/src/test_Regions.py b/src/test_Regions.py new file mode 100644 index 0000000..261594d --- /dev/null +++ b/src/test_Regions.py @@ -0,0 +1,89 @@ +from multitracker import Regions +from qt_dialog import person_tab +from PyQt5 import QtWidgets +import sys +import unittest +import logging + +class TestRegions(unittest.TestCase): + def __init__(self, *args, **kwargs): + super(TestRegions, self).__init__(*args, **kwargs) + self.longMessage = True + + def new_region(self): + #Requires app before regions can be declared + app = QtWidgets.QApplication(sys.argv) + region = Regions() + self.assertNotEqual(region, None, "Should not be None") + return region + + def test_set_moving_radius(self): + regions = self.new_region() + + #Test Null Entry or Invalid + regions.set_moving_radius(name="Joe", point=(0,0), dimensions=(0,0)) + regions.set_moving_radius(name="Joe", point=(0,0), dimensions=(-1,-1)) + regions.set_moving_radius(name="Joe", point=(0,0), dimensions=(10,10)) + + + def del_moving_radius(self): + regions = self.new_region() + + # Test Removal of name + regions.set_moving_radius(name="Test", point=(0,0), dimensions=(0,0)) + regions.del_moving_radius(name="Test") + self.assertEqual(regions.radius_regions, dict()) + + # Test does not remove subset + regions.set_moving_radius(name="Test", point=(0,0), dimensions=(0,0)) + regions.del_moving_radius(name="Tes") + self.assertEqual(regions.radius_regions.keys(), dict("Test").keys()) + + # Test does not remove superset + regions.set_moving_radius(name="Test", point=(0,0), dimensions=(0,0)) + regions.del_moving_radius(name="Tests") + self.assertEqual(regions.radius_regions.keys(), dict("Test").keys()) + + + def test_test_radius(self): + """ + if p <= 1: #point exists in or on ellipse + Otherwise the point exists outside of the ellipse + + Note: Eclipse Center = (PointX + 1/2 W, PointY + H/2) because (x,y) describe top left corner of a bounding box, and (x + width, y + height) describe the bottom right + """ + regions = self.new_region() + + # Test on Empty + regions.set_moving_radius(name="Test", point=(0,0), dimensions=(0,0)) + + # Zero Area cube has no center, therefore should not be in eclipse + self.assertEqual(regions.test_radius((0,0))[0], []) + self.assertGreaterEqual(regions.test_radius((0,0))[1], 1) + + # Point outside of zero area eclispe should not be in or on the eclipse + self.assertEqual(regions.test_radius((10,10))[0], []) + self.assertGreaterEqual(regions.test_radius((10,10))[1], 1) + + # Test Invalid + regions.set_moving_radius(name="Test", point=(-1,-1), dimensions=(-1,-1)) + + self.assertEqual(regions.test_radius((0,0))[0], []) + self.assertGreaterEqual(regions.test_radius((0,0))[1], 1) + + self.assertEqual(regions.test_radius((-10,-10))[0], []) + self.assertGreaterEqual(regions.test_radius((-10,-10))[1], 1) + + # Test Valid + regions.set_moving_radius(name="Test", point=(100,100), dimensions=(5,10)) + self.assertGreaterEqual(regions.test_radius((0,0))[1], 1) + self.assertGreaterEqual(regions.test_radius((100,100))[1], 1) # The top left of a rectangle which describes an eclipse is not included in ellipse + + self.assertLessEqual(regions.test_radius((102.5,100))[1], 1) # Tangent Edge should exist within ellipse (top) + self.assertLessEqual(regions.test_radius((102.5,110))[1], 1) # Tangent Edge should exist within ellipse (bottom) + self.assertLessEqual(regions.test_radius((100,105))[1], 1) # Tangent Edge should exist within ellipse (left) + self.assertLessEqual(regions.test_radius((105,105))[1], 1) # Tangent Edge should exist within ellipse (right) + # self.assertEqual(regions.test_radius((,-10)), -1) + +if __name__ == '__main__': + unittest.main()