From 5b64484c7dc1af992bf201bda8ee05087c35a874 Mon Sep 17 00:00:00 2001 From: Tristan Pepin <122389133+tristanpepinartefact@users.noreply.github.com> Date: Thu, 23 Nov 2023 14:29:16 +0100 Subject: [PATCH] Tp/add mkdocs (#19) --- docs/code.md | 1 - docs/custom_cost_selection.md | 148 ++++++++++++++++++++++ docs/index.md | 2 +- docs/quickstart_dev.md | 57 +++++++++ docs/quickstart_user.md | 117 +++++++++++++++++ docs/reference/cost_functions.md | 15 +++ docs/reference/matcher.md | 3 + docs/reference/reid_processor.md | 3 + docs/reference/selection_functions.md | 17 +++ docs/reference/tracked_object.md | 3 + docs/reference/tracked_object_filter.md | 3 + docs/reference/tracked_object_metadata.md | 3 + mkdocs.yaml | 31 ----- mkdocs.yml | 46 +++++++ pyproject.toml | 2 +- trackreid/matcher.py | 17 +-- trackreid/reid_processor.py | 33 ++--- trackreid/tracked_object.py | 14 +- trackreid/tracked_object_filter.py | 8 +- trackreid/tracked_object_metadata.py | 49 +++---- 20 files changed, 458 insertions(+), 114 deletions(-) delete mode 100644 docs/code.md create mode 100644 docs/custom_cost_selection.md create mode 100644 docs/quickstart_dev.md create mode 100644 docs/quickstart_user.md create mode 100644 docs/reference/cost_functions.md create mode 100644 docs/reference/matcher.md create mode 100644 docs/reference/reid_processor.md create mode 100644 docs/reference/selection_functions.md create mode 100644 docs/reference/tracked_object.md create mode 100644 docs/reference/tracked_object_filter.md create mode 100644 docs/reference/tracked_object_metadata.md delete mode 100644 mkdocs.yaml create mode 100644 mkdocs.yml diff --git a/docs/code.md b/docs/code.md deleted file mode 100644 index aa45473..0000000 --- a/docs/code.md +++ /dev/null @@ -1 +0,0 @@ -# Code diff --git a/docs/custom_cost_selection.md b/docs/custom_cost_selection.md new file mode 100644 index 0000000..71bb9c1 --- /dev/null +++ b/docs/custom_cost_selection.md @@ -0,0 +1,148 @@ +# Designing custom cost and selection functions + +## Custom cost function + +In our codebase, a cost function is utilized to quantify the dissimilarity between two objects, specifically instances of [TrackedObjects](reference/tracked_object.md). The cost function plays a pivotal role in the matching process within the [Matcher class](reference/matcher.md), where it computes a cost matrix. Each element in this matrix represents the cost of assigning a candidate to a switcher. For a deeper understanding of cost functions, please refer to the [related documentation](reference/cost_functions.md). + +When initializing the [ReidProcessor](reference/reid_processor.md), you have the option to provide a custom cost function. The requirements for designing one are as follows: + +- The cost function must accept 2 [TrackedObjects](reference/tracked_object.md) instances: a candidate (a new object that appears and can potentially be matched), and a switcher (an object that has been lost and can potentially be re-matched). +- All the [metadata](reference/tracked_object_metadata.md) of each [TrackedObject](reference/tracked_object.md) can be utilized to compute a cost. +- If additional metadata is required, you should modify the [metadata](reference/tracked_object_metadata.md) class accordingly. Please refer to the [developer quickstart documentation](quickstart_dev.md) if needed. + +Here is an example of an Intersection over Union (IoU) distance function that you can use: + +```python +def bounding_box_iou_distance(candidate: TrackedObject, switcher: TrackedObject) -> float: + """ + Calculates the Intersection over Union (IoU) between the bounding boxes of two TrackedObjects. + This measure is used as a measure of similarity between the two objects, with a higher IoU + indicating a higher likelihood of the objects being the same. + + Args: + candidate (TrackedObject): The first TrackedObject. + switcher (TrackedObject): The second TrackedObject. + + Returns: + float: The IoU between the bounding boxes of the two TrackedObjects. + """ + # Get the bounding boxes from the Metadata of each TrackedObject + bbox1 = candidate.metadata.bbox + bbox2 = switcher.metadata.bbox + + # Calculate the intersection of the bounding boxes + x1 = max(bbox1[0], bbox2[0]) + y1 = max(bbox1[1], bbox2[1]) + x2 = min(bbox1[2], bbox2[2]) + y2 = min(bbox1[3], bbox2[3]) + + # If the bounding boxes do not overlap, return 0 + if x2 < x1 or y2 < y1: + return 0.0 + + # Calculate the area of the intersection + intersection_area = (x2 - x1) * (y2 - y1) + + # Calculate the area of each bounding box + bbox1_area = (bbox1[2] - bbox1[0]) * (bbox1[3] - bbox1[1]) + bbox2_area = (bbox2[2] - bbox2[0]) * (bbox2[3] - bbox2[1]) + + # Calculate the IoU + iou = intersection_area / float(bbox1_area + bbox2_area - intersection_area) + + return 1 - iou + +``` + +Next, pass this function during the initialization of your [ReidProcessor](reference/reid_processor.md): + +```python +reid_processor = ReidProcessor(cost_function_threshold=0.3, + cost_function = bounding_box_iou_distance, + filter_confidence_threshold=..., + filter_time_threshold=..., + max_attempt_to_match=..., + max_frames_to_rematch=..., + save_to_txt=True, + file_path="your_file.txt") +``` + +In this case, candidates and switchers with bounding boxes will be matched if their IoU is below 0.7. Among possible matches, the two bounding boxes with the lowest cost (i.e., larger IoU) will be matched. You can use all the available metadata. For instance, here is an example of a cost function based on the difference in confidence: + +```python +def confidence_difference(candidate: TrackedObject, switcher: TrackedObject) -> float: + """ + Calculates the absolute difference between the confidence values of two TrackedObjects. + This measure is used as a measure of dissimilarity between the two objects, with a smaller difference + indicating a higher likelihood of the objects being the same. + + Args: + candidate (TrackedObject): The first TrackedObject. + switcher (TrackedObject): The second TrackedObject. + + Returns: + float: The absolute difference between the confidence values of the two TrackedObjects. + """ + # Get the confidence values from the Metadata of each TrackedObject + confidence1 = candidate.metadata.confidence + confidence2 = switcher.metadata.confidence + + # Calculate the absolute difference between the confidence values + difference = abs(confidence1 - confidence2) + + return difference + +``` + +Then, pass this function during the initialization of your [ReidProcessor](reference/reid_processor.md): + +```python +reid_processor = ReidProcessor(cost_function_threshold=0.1, + cost_function = confidence_difference, + filter_confidence_threshold=..., + filter_time_threshold=..., + max_attempt_to_match=..., + max_frames_to_rematch=..., + save_to_txt=True, + file_path="your_file.txt") +``` + +In this case, candidates and switchers will be matched if their confidence is similar, with a threshold acceptance of 0.1. Among possible matches, the two objects with the lowest cost (i.e., lower confidence difference) will be matched. + +## Custom Selection function + +In the codebase, a selection function is used to determine whether two objects, specifically [TrackedObjects](reference/tracked_object.md) instances, should be considered for matching. The selection function is a key part of the matching process in the [Matcher class](reference/matcher.md). For a deeper understanding of selection functions, please refer to the [related documentation](reference/selection_functions.md). + +Here is an example of a selection function per zone that you can use: + +```python + +# Define the area of interest, [x_min, y_min, x_max, y_max] +AREA_OF_INTEREST = [0, 0, 500, 500] + +def select_by_area(candidate: TrackedObject, switcher: TrackedObject) -> int: + + # Check if both objects are inside the area of interest + if (candidate.bbox[0] > AREA_OF_INTEREST[0] and candidate.bbox[1] > AREA_OF_INTEREST[1] and + candidate.bbox[0] + candidate.bbox[2] < AREA_OF_INTEREST[2] and candidate.bbox[1] + candidate.bbox[3] < AREA_OF_INTEREST[3] and + switcher.bbox[0] > AREA_OF_INTEREST[0] and switcher.bbox[1] > AREA_OF_INTEREST[1] and + switcher.bbox[0] + switcher.bbox[2] < AREA_OF_INTEREST[2] and switcher.bbox[1] + switcher.bbox[3] < AREA_OF_INTEREST[3]): + return 1 + else: + return 0 + +``` + +Then, pass this function during the initialization of your [ReidProcessor](reference/reid_processor.md): + +```python +reid_processor = ReidProcessor(selection_function = select_by_area, + filter_confidence_threshold=..., + filter_time_threshold=..., + max_attempt_to_match=..., + max_frames_to_rematch=..., + save_to_txt=True, + file_path="your_file.txt") +``` + +In this case, candidates and switchers will be considerated for matching if they belong to the same zone. You can of course combine selection functions, for instance to selection only switchers and candidates that belong to the same area and belong to the same category. diff --git a/docs/index.md b/docs/index.md index 8013429..df25491 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,3 +1,3 @@ -# Welcome to the documentation! +# Welcome to the documentation For more information, make sure to check the [Material for MkDocs documentation](https://squidfunk.github.io/mkdocs-material/getting-started/) diff --git a/docs/quickstart_dev.md b/docs/quickstart_dev.md new file mode 100644 index 0000000..7a0f99e --- /dev/null +++ b/docs/quickstart_dev.md @@ -0,0 +1,57 @@ +# Quickstart developers + +## Installation + +First, clone the repository to your local machine: + +```bash +git clone https://github.com/artefactory-fr/track-reid.git +``` + +Then, navigate to the project directory: + +```bash +cd track-reid +``` + +To install the necessary dependencies, we use Poetry. If you don't have Poetry installed, you can download it using the following command: + +```bash +curl -sSL https://install.python-poetry.org | python3 - +``` + +Now, you can install the dependencies: + +```bash +make install +``` + +This will create a virtual environment and install the necessary dependencies. +To activate the virtual environment in your terminal, you can use the following command: + +```bash +poetry shell +``` + +You can also update the requirements using the following command: + +```bash +make update-requirements +``` + +Then, you are ready to go ! +For more detailed information, please refer to the `Makefile`. + +## Tests + +In this project, we have designed both integration tests and unit tests. These tests are located in the `tests` directory of the project. + +Integration tests are designed to test the interaction between different parts of the system, ensuring that they work together as expected. Those tests can be found in the `tests/integration_tests` directory of the project. + +Unit tests, on the other hand, are designed to test individual components of the system in isolation. We provided a bench of unit tests to test key functions of the project, those can be found in `tests/unit_tests`. + +To run all tests, you can use the following command: + +```bash +make run_tests +``` diff --git a/docs/quickstart_user.md b/docs/quickstart_user.md new file mode 100644 index 0000000..d5262cb --- /dev/null +++ b/docs/quickstart_user.md @@ -0,0 +1,117 @@ +# Using the ReidProcessor + +The `ReidProcessor` is the entry point of the `track-reid` library. It is used to process and reconcile tracking data, ensuring consistent and accurate tracking of objects over time. Here's a step-by-step guide on how to use it: + +## Step 1: Understand the Usage + +The reidentification process is applied to tracking results, which are derived from the application of a tracking algorithm on detection results for successive frames of a video. This reidentification process is applied iteratively on each tracking result, updating its internal states during the process. + +The `ReidProcessor` needs to be updated with the tracking results for each frame of your +sequence or video. This is done by calling the `update` method that takes 2 arguments: + +- `frame_id`: an integer specifying the current frame of the video +- `tracker_output`: a numpy array containing the tracking results for the current frame + +## Step 2: Understand the Data Format Requirements + +The `ReidProcessor` update function requires a numpy array of tracking results for the current frame as input. This data must meet specific criteria regarding data type and structure. + +All input data must be numeric, either integers or floats. +Here's an example of the expected input data format based on the schema: + +| bbox (0-3) | object_id (4) | category (5) | confidence (6) | +|-----------------|---------------|--------------|----------------| +| 50, 60, 120, 80 | 1 | 1 | 0.91 | +| 50, 60, 120, 80 | 2 | 0 | 0.54 | + +Each row corresponds to a tracked object. + +- The first four columns denote the **bounding box coordinates** in the format (x, y, width, height), +where x and y are the top left coordinates of the bounding box. These coordinates can be either normalized or in pixel units. +These values remain unchanged during the reidentification process. +- The fifth column is the **object ID** assigned by the tracker, which may be adjusted during the reidentification process. +- The sixth column indicates the **category** of the detected object, which may also be adjusted during the reidentification process. +- The seventh column is the confidence score of the detection, which is not modified by the reidentification process. + +For additional information, you can utilize `ReidProcessor.print_input_data_requirements()`. + +Here's a reformatted example of how the output data should appear, based on the schema: + +| frame_id (0) | object_id (1) | category (2) | bbox (3-6) | confidence (7) | mean_confidence (8) | tracker_id (9) | +|--------------|---------------|--------------|-----------------|----------------|---------------------|----------------| +| 1 | 1 | 1 | 50, 60, 120, 80 | 0.91 | 0.85 | 1 | +| 2 | 2 | 0 | 50, 60, 120, 80 | 0.54 | 0.60 | 2 | + +- The first column represents the **frame identifier**, indicating the frame for which the result is applicable. +- The second column is the **object ID** assigned by the reidentification process. +- The third column is the **category** of the detected object, which may be adjusted during the reidentification process. +- The next four columns represent the **bounding box coordinates**, which remain unchanged from the input data. +- The seventh column is the **confidence** of the object, which also remains unchanged from the input data. +- The eighth column indicates the **average confidence** of the detected object over its lifetime, from the beginning of the tracking to the current frame. +- The final column is the **object ID assigned by the tracking algorithm**, before the reidentification process. + +You can use `ReidProcessor.print_output_data_format_information()` for more insight. + +## Step 3: Understand Necessary Modules + +To make ReidProcessor work, several modules are necessary: + +- `TrackedObject`: This class represents a tracked object. It is used within the Matcher and ReidProcessor classes. +- `TrackedObjectMetadata`: This class is attached to a tracked object and represents informations and properties about the object. +- `TrackedObjectFilter`: This class is used to filter tracked objects based on certain criteria. It is used within the ReidProcessor class. +- `Matcher`: This class is used to match tracked objects based on a cost function and a selection function. It is initialized within the ReidProcessor class. + +The cost and selection functions are key components of the ReidProcessor, as they will drive the matching process between lost objects and new objects during the video. Those two functions are fully customizable and can be passed as arguments of the ReidProcessor at initialization. They both take 2 `TrackedObjects` as inputs, and perform computation based on their metadatas. + +- **cost function**: This function calculates the cost of matching two objects. It takes two TrackedObject instances as input and returns a numerical value representing the cost of matching these two objects. A lower cost indicates a higher likelihood of a match. The default cost function is `bounding_box_distance`. + +- **selection_function**: This function determines whether two objects should be considered for matching. It takes two TrackedObject instances as input and returns a binary value (0 or 1). A return value of 1 indicates that the pair should be considered for matching, while a return value of 0 indicates that the pair should not be considered. The default selection function is `select_by_category`. + +In summary, prior to the matching process, filtering on which objects should be considerated is applied thought the `TrackedObjectFilter`. All objects are represented by the `TrackedObject` class, with its attached metadata represented by `TrackedObjectMetadata`. The `ReidProcessor` then uses the `Matcher` class with a cost function and selection function to match objects. + +## Step 4: Initialize ReidProcessor + +If you do not want to provide custom cost and selection function, here is an example of ReidProcessor initialization: + +```python +reid_processor = ReidProcessor(filter_confidence_threshold=0.1, + filter_time_threshold=5, + cost_function_threshold=5000, + max_attempt_to_match=5, + max_frames_to_rematch=500, + save_to_txt=True, + file_path="your_file.txt") +``` + +Here is a brief explanation of each argument in the ReidProcessor function, and how you can monitor the `Matcher` and the `TrackedObjectFilter` behaviours: + +- `filter_confidence_threshold`: Float value that sets the **minimum average confidence level** for a tracked object to be considered valid. Tracked objects with average confidence levels below this threshold will be ignored. + +- `filter_time_threshold`: Integer that sets the **minimum number of frames** a tracked object must be seen with the same id to be considered valid. Tracked objects seen less frames that this threshold will be ignored. + +- `cost_function_threshold`: This is a float value that sets the **maximum cost for a match** between a detection and a track. If the cost of matching a detection to a track exceeds this threshold, the match will not be made. Set to None for no limitation. + +- `max_attempt_to_match`: This is an integer that sets the **maximum number of attempts to match a tracked object never seen before** to a lost tracked object. If this tracked object never seen before can't be matched within this number of attempts, it will be considered a new stable tracked object. + +- `max_frames_to_rematch`: This is an integer that sets the **maximum number of frames to try to rematch a tracked object that has been lost**. If a lost object can't be rematch within this number of frames, it will be considered as lost forever. + +- `save_to_txt`: This is a boolean value that determines whether the tracking results should be saved to a text file. If set to True, the results will be saved to a text file. + +- `file_path`: This is a string that specifies the path to the text file where the tracking results will be saved. This argument is only relevant if save_to_txt is set to True. + +For more information on how to design custom cost and selection functions, refer to [this guide](custom_cost_selection.md). + +## Step 5: Run reidentifiaction process + +Lets say you have a `dataset` iterable object, composed for each iteartion of a frame id and its associated tracking results. You can call the `ReidProcessor` update class using the following: + +```python +for frame_id, tracker_output in dataset: + corrected_results = reid_processor.update(frame_id = frame_id, tracker_output=tracker_output) +``` + +At the end of the for loop, information about the correction can be retrieved using the `ReidProcessor` properties. For instance, the list of tracked object can be accessed using: + +```python +reid_processor.seen_objects() +``` diff --git a/docs/reference/cost_functions.md b/docs/reference/cost_functions.md new file mode 100644 index 0000000..3a0a1c9 --- /dev/null +++ b/docs/reference/cost_functions.md @@ -0,0 +1,15 @@ +# Cost functions + +In the codebase, a cost function is used to measure the dissimilarity between two objects, specifically [TrackedObjects](tracked_object.md) instances. The cost function is a crucial part of the matching process in the [Matcher class](matcher.md). It calculates a cost matrix, where each element represents the cost of assigning a candidate to a switcher. + +The cost function affects the behavior of the matching process in the following ways: + +1. **Determining Matches**: The cost function is used to determine the best matches between candidates and switchers. The lower the cost, the higher the likelihood that two objects are the same. + +2. **Influencing Match Quality**: The choice of cost function can greatly influence the quality of the matches. For example, a cost function that calculates the Euclidean distance between the centers of bounding boxes might be more suitable for tracking objects in a video, while a cost function that calculates the absolute difference between confidence values might be more suitable for matching objects based on their detection confidence. + +3. **Setting Match Thresholds**: The cost function also plays a role in setting thresholds for matches. In the [Matcher class](matcher.md), if the cost exceeds a certain threshold, the match is discarded. + +You can provide a custom cost function to the reidentification process. For more information, please refer to [this documentation](../custom_cost_selection.md). + +:::trackreid.cost_functions diff --git a/docs/reference/matcher.md b/docs/reference/matcher.md new file mode 100644 index 0000000..396ffbf --- /dev/null +++ b/docs/reference/matcher.md @@ -0,0 +1,3 @@ +# Matcher + +:::trackreid.matcher diff --git a/docs/reference/reid_processor.md b/docs/reference/reid_processor.md new file mode 100644 index 0000000..c72dbdc --- /dev/null +++ b/docs/reference/reid_processor.md @@ -0,0 +1,3 @@ +# Reid processor + +:::trackreid.reid_processor diff --git a/docs/reference/selection_functions.md b/docs/reference/selection_functions.md new file mode 100644 index 0000000..6b4f998 --- /dev/null +++ b/docs/reference/selection_functions.md @@ -0,0 +1,17 @@ +# Selection Functions + +In the codebase, a selection function is used to determine whether two objects, specifically [TrackedObjects](tracked_object.md) instances, should be considered for matching. The selection function is a key part of the matching process in the [Matcher class](matcher.md). + +The selection function influences the behavior of the matching process in the following ways: + +1. **Filtering Candidates**: The selection function is used to filter out pairs of objects that should not be considered for matching. This can help reduce the computational complexity of the matching process by reducing the size of the cost matrix. + +2. **Customizing Matching Criteria**: The selection function allows you to customize the criteria for considering a pair of objects for matching. For example, you might want to only consider pairs of objects that belong to the same category, or pairs of objects that belong to the same area / zone. + +3. **Improving Match Quality**: By carefully choosing or designing a selection function, you can improve the quality of the matches. For example, a selection function that only considers pairs of objects with similar appearance features might lead to more accurate matches. + +The selection function should return a boolean value. A return value of `True` or `1` indicates that the pair of objects should be considered for matching, while a return value of `False` or `0` indicates that the pair should not be considered. + +You can provide a custom selection function to the reidentification process. For more information, please refer to [this documentation](../custom_cost_selection.md). + +:::trackreid.selection_functions diff --git a/docs/reference/tracked_object.md b/docs/reference/tracked_object.md new file mode 100644 index 0000000..d74024a --- /dev/null +++ b/docs/reference/tracked_object.md @@ -0,0 +1,3 @@ +# TrackedObject + +:::trackreid.tracked_object diff --git a/docs/reference/tracked_object_filter.md b/docs/reference/tracked_object_filter.md new file mode 100644 index 0000000..757ebe7 --- /dev/null +++ b/docs/reference/tracked_object_filter.md @@ -0,0 +1,3 @@ +# TrackedObjectFilter + +:::trackreid.tracked_object_filter diff --git a/docs/reference/tracked_object_metadata.md b/docs/reference/tracked_object_metadata.md new file mode 100644 index 0000000..b03870c --- /dev/null +++ b/docs/reference/tracked_object_metadata.md @@ -0,0 +1,3 @@ +# TrackedObjectMetadata + +:::trackreid.tracked_object_metadata diff --git a/mkdocs.yaml b/mkdocs.yaml deleted file mode 100644 index 449fd64..0000000 --- a/mkdocs.yaml +++ /dev/null @@ -1,31 +0,0 @@ -site_name: track-reid - -theme: - name: "material" - palette: - - media: "(prefers-color-scheme: dark)" - scheme: default - primary: teal - accent: amber - toggle: - icon: material/moon-waning-crescent - name: Switch to dark mode - - media: "(prefers-color-scheme: light)" - scheme: slate - primary: teal - accent: amber - toggle: - icon: material/white-balance-sunny - name: Switch to light mode - features: - - search.suggest - - search.highlight - - content.tabs.link - -plugins: - - mkdocstrings - - search - -nav: - - Home: index.md - - Source code: code.md diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..edc0dd2 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,46 @@ +site_name: track-reid + +theme: + name: "material" + palette: + - media: "(prefers-color-scheme: dark)" + scheme: default + primary: indigo + accent: pink + toggle: + icon: material/moon-waning-crescent + name: Switch to dark mode + - media: "(prefers-color-scheme: light)" + scheme: slate + primary: indigo + accent: pink + toggle: + icon: material/white-balance-sunny + name: Switch to light mode + features: + - search.suggest + - search.highlight + - content.tabs.link + +plugins: + - mkdocstrings + - search + +markdown_extensions: + - codehilite: + use_pygments: true + pygments_style: monokai + +nav: + - Home: index.md + - Quickstart users: quickstart_user.md + - Quickstart developers: quickstart_dev.md + - Custom cost and selection functions: custom_cost_selection.md + - Code Reference: + - ReidProcessor: reference/reid_processor.md + - TrackedObjectFilter: reference/tracked_object_filter.md + - Matcher: reference/matcher.md + - TrackedObjectMetadata: reference/tracked_object_metadata.md + - TrackedObject: reference/tracked_object.md + - Cost functions: reference/cost_functions.md + - Selection functions: reference/selection_functions.md diff --git a/pyproject.toml b/pyproject.toml index 122887e..1d64bc7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ pytest = "7.3.2" ipykernel = "6.24.0" mkdocs = "1.4.3" mkdocs-material = "9.1.15" -mkdocstrings-python = "1.1.2" +mkdocstrings = {extras = ["python-legacy"], version = "^0.24.0"} bandit = "1.7.5" nbstripout = "0.6.1" diff --git a/trackreid/matcher.py b/trackreid/matcher.py index 9148c2e..c57a9d9 100644 --- a/trackreid/matcher.py +++ b/trackreid/matcher.py @@ -18,22 +18,13 @@ def __init__( Initializes the Matcher object with the provided cost function, selection function, and cost function threshold. Args: - cost_function (Callable): A function that calculates the cost of matching two objects. This function should - take two TrackedObject instances as input and return a numerical value representing the cost of matching - these two objects. A lower cost indicates a higher likelihood of a match. - - selection_function (Callable): A function that determines whether two objects should be considered for - matching. This function should take two TrackedObject instances as input and return a binary value (0 or 1). - A return value of 1 indicates that the pair should be considered for matching, while a return value of 0 - indicates that the pair should not be considered. - - cost_function_threshold (Optional[Union[int, float]]): An optional threshold value for the cost function. - If provided, any pair of objects with a matching cost greater than this threshold will not be considered for - matching. If not provided, all selected pairs will be considered regardless of their matching cost. + cost_function (Callable): A function that calculates the cost of matching two objects. This function should take two TrackedObject instances as input and return a numerical value representing the cost of matching these two objects. A lower cost indicates a higher likelihood of a match. + selection_function (Callable): A function that determines whether two objects should be considered for matching. This function should take two TrackedObject instances as input and return a binary value (0 or 1). A return value of 1 indicates that the pair should be considered for matching, while a return value of 0 indicates that the pair should not be considered. + cost_function_threshold (Optional[Union[int, float]]): An optional threshold value for the cost function. If provided, any pair of objects with a matching cost greater than this threshold will not be considered for matching. If not provided, all selected pairs will be considered regardless of their matching cost. Returns: None - """ + """ # noqa: E501 self.cost_function = cost_function self.selection_function = selection_function self.cost_function_threshold = cost_function_threshold diff --git a/trackreid/reid_processor.py b/trackreid/reid_processor.py index 8fde685..027f07e 100644 --- a/trackreid/reid_processor.py +++ b/trackreid/reid_processor.py @@ -51,40 +51,23 @@ class ReidProcessor: Args: - filter_confidence_threshold (float): Confidence threshold for the filter. The filter will only consider - tracked objects that have a mean confidence score during the all transaction above this threshold. + filter_confidence_threshold (float): Confidence threshold for the filter. The filter will only consider tracked objects that have a mean confidence score during the all transaction above this threshold. - filter_time_threshold (int): Time threshold for the filter. The filter will only consider tracked objects - that have been seen for a number of frames above this threshold. + filter_time_threshold (int): Time threshold for the filter. The filter will only consider tracked objects that have been seen for a number of frames above this threshold. - max_frames_to_rematch (int): Maximum number of frames to rematch. If a switcher is lost for a number of - frames greater than this value, it will be flagged as lost forever. + max_frames_to_rematch (int): Maximum number of frames to rematch. If a switcher is lost for a number of frames greater than this value, it will be flagged as lost forever. - max_attempt_to_match (int): Maximum number of attempts to match a candidate. If a candidate has not been - rematched despite a number of attempts equal to this value, it will be flagged as a stable object. + max_attempt_to_match (int): Maximum number of attempts to match a candidate. If a candidate has not been rematched despite a number of attempts equal to this value, it will be flagged as a stable object. - selection_function (Callable): A function that determines whether two objects should be considered for - matching. The selection function should take two TrackedObject instances as input and return a binary value - (0 or 1). A return value of 1 indicates that the pair should be considered for matching, while a return - value of 0 indicates that the pair should not be considered. - Defaults to select_by_category. + selection_function (Callable): A function that determines whether two objects should be considered for matching. The selection function should take two TrackedObject instances as input and return a binary value (0 or 1). A return value of 1 indicates that the pair should be considered for matching, while a return value of 0 indicates that the pair should not be considered. - cost_function (Callable): A function that calculates the cost of matching two objects. The cost function - should take two TrackedObject instances as input and return a numerical value representing the cost of - matching these two objects. A lower cost indicates a higher likelihood of a match. - Defaults to bounding_box_distance. + cost_function (Callable): A function that calculates the cost of matching two objects. The cost function should take two TrackedObject instances as input and return a numerical value representing the cost of matching these two objects. A lower cost indicates a higher likelihood of a match. - cost_function_threshold (Optional[Union[int, float]]): An maximal threshold value for the cost function. - If provided, any pair of objects with a matching cost greater than this threshold will not be considered - for matching. If not provided, all selected pairs will be considered regardless of their matching cost. - Defaults to None. + cost_function_threshold (Optional[Union[int, float]]): An maximal threshold value for the cost function. If provided, any pair of objects with a matching cost greater than this threshold will not be considered for matching. If not provided, all selected pairs will be considered regardless of their matching cost.\n - save_to_txt (bool): A flag indicating whether to save the results to a text file. If set to True, the - results will be saved to a text file specified by the file_path parameter. - Default to False. + save_to_txt (bool): A flag indicating whether to save the results to a text file. If set to True, the results will be saved to a text file specified by the file_path parameter. file_path (str): The path to the text file where the results will be saved if save_to_txt is set to True. - Defaults to tracks.txt """ # noqa: E501 def __init__( diff --git a/trackreid/tracked_object.py b/trackreid/tracked_object.py index bd42a19..1bc84b0 100644 --- a/trackreid/tracked_object.py +++ b/trackreid/tracked_object.py @@ -44,14 +44,12 @@ class TrackedObject: Args: object_ids (Union[Union[float, int], sllist]): The unique identifiers for the object. state (int): The current state of the object. - metadata (Union[np.ndarray, TrackedObjectMetaData]): The metadata for the object. It can be either a - TrackedObjectMetaData object, or a data line, i.e. output of detection model. If metadata is initialized - with a TrackedObjectMetaData object, a frame_id must be given. + metadata (Union[np.ndarray, TrackedObjectMetaData]): The metadata for the object. It can be either a TrackedObjectMetaData object, or a data line, i.e. output of detection model. If metadata is initialized with a TrackedObjectMetaData object, a frame_id must be given. frame_id (Optional[int], optional): The frame ID where the object was first seen. Defaults to None. Raises: NameError: If the type of object_ids or metadata is unrecognized. - """ + """ # noqa: E501 def __init__( self, @@ -192,12 +190,10 @@ def update_metadata(self, data_line: np.ndarray, frame_id: int): the tracked object. Args: - data_line (np.ndarray): The detection data for a single frame. It contains information such as the - class name, bounding box coordinates, and confidence level of the detection. + data_line (np.ndarray): The detection data for a single frame. It contains information such as the class name, bounding box coordinates, and confidence level of the detection. - frame_id (int): The frame id where the object was detected. This is used to update the last frame id of - the tracked object. - """ + frame_id (int): The frame id where the object was detected. This is used to update the last frame id of the tracked object. + """ # noqa: E501 self.metadata.update(data_line=data_line, frame_id=frame_id) def __eq__(self, other): diff --git a/trackreid/tracked_object_filter.py b/trackreid/tracked_object_filter.py index c4a56fa..cf9b016 100644 --- a/trackreid/tracked_object_filter.py +++ b/trackreid/tracked_object_filter.py @@ -8,11 +8,9 @@ class TrackedObjectFilter: confidence and the number of frames they have been observed in. Args: - confidence_threshold (float): The minimum mean confidence level required for a tracked - object to be considered valid. - frames_seen_threshold (int): The minimum number of frames a tracked object - must be observed in to be considered valid. - """ + confidence_threshold (float): The minimum mean confidence level required for a tracked object to be considered valid. + frames_seen_threshold (int): The minimum number of frames a tracked object must be observed in to be considered valid. + """ # noqa: E501 def __init__(self, confidence_threshold: float, frames_seen_threshold: int): self.confidence_threshold = confidence_threshold diff --git a/trackreid/tracked_object_metadata.py b/trackreid/tracked_object_metadata.py index ea04bfc..874ec4b 100644 --- a/trackreid/tracked_object_metadata.py +++ b/trackreid/tracked_object_metadata.py @@ -31,28 +31,20 @@ def update(self, data_line: np.ndarray, frame_id: int): Updates the metadata of a tracked object based on new detection data. This method is used to update the metadata of a tracked object whenever new detection data is available. - It updates the last frame id, class counts, bounding box, confidence, confidence sum, and observations. + It updates the last frame id, class counts, bounding box, confidence, confidence sum, and observations: + - last_frame_id: Updated to the frame id where the object was detected + - class_counts: Incremented by 1 for the detected class + - bbox: Updated to the bounding box coordinates from the detection data + - confidence: Updated to the confidence level from the detection data + - confidence_sum: Incremented by the confidence level from the detection data + - observations: Incremented by 1 Args: - data_line (np.ndarra): The detection data for a single frame. It contains information such as the - class name, bounding box coordinates, and confidence level of the detection. + data_line (np.ndarra): The detection data for a single frame. It contains information such as the class name, bounding box coordinates, and confidence level of the detection. - frame_id (int): The frame id where the object was detected. This is used to update the last frame id of - the tracked object. + frame_id (int): The frame id where the object was detected. This is used to update the last frame id of the tracked object. - Updates: - last_frame_id: The last frame id is updated to the frame id where the object was detected. - - class_counts: The class counts are updated by incrementing the count of the detected class by 1. - - bbox: The bounding box is updated to the bounding box coordinates from the detection data. - - confidence: The confidence is updated to the confidence level from the detection data. - - confidence_sum: The confidence sum is updated by adding the confidence level from the detection data. - - observations: The total number of observations is incremented by 1. - """ + """ # noqa: E501 self.last_frame_id = frame_id class_name = int(data_line[input_data_positions.category]) @@ -66,22 +58,23 @@ class name, bounding box coordinates, and confidence level of the detection. def merge(self, other_object): """ Merges the metadata of another TrackedObjectMetaData instance into the current one. + Updates the current instance with the data from the other TrackedObjectMetaData instance. + + The following properties are updated: + - observations: Incremented by the observations of the other object. + - confidence_sum: Incremented by the confidence sum of the other object. + - confidence: Set to the confidence of the other object. + - bbox: Set to the bounding box of the other object. + - last_frame_id: Set to the last frame id of the other object. + - class_counts: For each class, the count is incremented by the count of the other object. Args: - other_object (TrackedObjectMetaData): The other TrackedObjectMetaData instance whose metadata - is to be merged with the current instance. + other_object (TrackedObjectMetaData): The other TrackedObjectMetaData instance whose metadata is to be merged with the current instance. Raises: TypeError: If the other_object is not an instance of TrackedObjectMetaData. - Updates: - observations: The total number of observations is updated by adding the observations of the other object. - confidence_sum: The total confidence sum is updated by adding the confidence sum of the other object. - confidence: The confidence is updated to the confidence of the other object. - bbox: The bounding box is updated to the bounding box of the other object. - last_frame_id: The last frame id is updated to the last frame id of the other object. - class_counts: The class counts are updated by adding the class counts of the other object for each class. - """ + """ # noqa: E501 if not isinstance(other_object, type(self)): raise TypeError("Can only merge with another TrackedObjectMetaData.")