Reconstructs ellipses for multiple individuals based on their body part coordinates across multiple frames. Each ellipse is fitted to the coordinates using an `EllipseFitter`. Parameters ---------- data : pandas.DataFrame A multi-level DataFrame containing body part coor
(data, sd)
| 737 | |
| 738 | |
| 739 | def reconstruct_all_ellipses(data, sd): |
| 740 | """Reconstructs ellipses for multiple individuals based on their body part |
| 741 | coordinates across multiple frames. Each ellipse is fitted to the coordinates using |
| 742 | an `EllipseFitter`. |
| 743 | |
| 744 | Parameters |
| 745 | ---------- |
| 746 | data : pandas.DataFrame |
| 747 | A multi-level DataFrame containing body part coordinates and likelihood values. |
| 748 | The index represents frames, and the columns follow a multi-level structure: |
| 749 | - Level 0: Scorer |
| 750 | - Level 1: Individuals |
| 751 | - Level 2: Body parts |
| 752 | - Level 3: Coordinates ("x" and "y") and "likelihood". |
| 753 | sd : float |
| 754 | The standard deviation used by the `EllipseFitter` for fitting ellipses. |
| 755 | |
| 756 | Returns |
| 757 | ------- |
| 758 | numpy.ndarray |
| 759 | A 3D array of shape (A, F, 5), where: |
| 760 | - A is the number of individuals (excluding "single" if present). |
| 761 | - F is the number of frames. |
| 762 | - Each row contains ellipse parameters [cx, cy, width, height, angle]. |
| 763 | |
| 764 | Notes |
| 765 | ----- |
| 766 | - The method drops the "likelihood" column from the input DataFrame as it is not |
| 767 | relevant for ellipse fitting. |
| 768 | - If the "single" individual is present, it is excluded from the reconstruction process. |
| 769 | - The `EllipseFitter` is used to fit ellipses to the body part coordinates for each |
| 770 | individual in each frame. |
| 771 | - NaN values are assigned when no valid ellipse can be fitted. |
| 772 | """ |
| 773 | xy = data.droplevel("scorer", axis=1).drop("likelihood", axis=1, level=-1) |
| 774 | if "single" in xy: |
| 775 | xy.drop("single", axis=1, level="individuals", inplace=True) |
| 776 | animals = xy.columns.get_level_values("individuals").unique() |
| 777 | nrows = xy.shape[0] |
| 778 | ellipses = np.full((len(animals), nrows, 5), np.nan) |
| 779 | fitter = EllipseFitter(sd) |
| 780 | for n, animal in enumerate(animals): |
| 781 | data = xy.xs(animal, axis=1, level="individuals").values.reshape((nrows, -1, 2)) |
| 782 | for i, coords in enumerate(tqdm(data)): |
| 783 | el = fitter.fit(coords.astype(np.float64)) |
| 784 | if el is not None: |
| 785 | ellipses[n, i] = el.parameters |
| 786 | return ellipses |
| 787 | |
| 788 | |
| 789 | def _track_individuals(individuals, min_hits=1, max_age=5, similarity_threshold=0.6, track_method="ellipse"): |
nothing calls this directly
no test coverage detected