movement icon indicating copy to clipboard operation
movement copied to clipboard

Adding the option for front-back instead of left-right points for forward vector calculation.

Open vigji opened this issue 6 months ago • 8 comments

Is your feature request related to a problem? Please describe. I would like to use a movement function like compute_forward_vector_angle to compute forward_vector starting from rear and front points instead of left and right (in my case, from the bottom I have reliable neck and nose positions but no left and right ear positions).

Maybe I'm missing something stupid? But all functions in orientation seem to refer to left and right keypoints, no?

Describe the solution you'd like compute_forward_vector(..) to accept back and front points instead of left and right

Describe alternatives you've considered This is simple to compute outside movement of course, but would be nice to do it within as well for consistency with other variables computation.

vigji avatar Jun 18 '25 10:06 vigji

Hey @vigji, we are aware of this limitation and have been thinking on how to handle this, so your opinion is more than welcome.

First, a workaround to your current situation:

You could compute to the back-to-front vector similarly to how we derive the head-to-snout vector in this example:

rear_keypoint = ds.position.sel(keypoints="rear")
front_keypoint = ds.position.sel(keypoints="front")

rear_to_front_vec = front_keypoint - rear_keypoint

One you have the desired vector, you can then call the compute_signed_angle_2d utility to get the angle relative to chosen reference direction.

Alternatively you can use the cart2pol utility to convert the vector in polar coordinates, giving you both the magnitude and the angle.

I suspect you already knew of these workarounds, and besides they are probably too complex for most users.

I guess what your question is really getting at is providing front + back keypoint options directly in compute_forward_vector and compute_forward_vector_angle. I think this would be a nice improvement/generalisation, but I'm kinda struggling with coming up with the best function signature for that. We would need to either:

  • expose arguments for all left/right/front/rear keypoints and require the user to only supply left-right or front rear
  • expose one argument for a pair of keypoints, and another argument for "mode" (left-right or front-back)
  • other options I haven't thought of.

I'm interested to hear how you'd approach this.

niksirbi avatar Jun 18 '25 10:06 niksirbi

Indeed that works! But still, one has to face some quirks of the geometry involved (eg: at the beginning I was assuming the two vectors to pass were the "position vectors" and it would have computed the angle between them; or also some subtleties of dealing with xarrays). So definitively not beginner-friendly!

I am personally biased toward the option of exposing both left/right or front/rear and just check that one and only on of the pairs is present. I cannot see many drawbacks apart from the ugliness of the alternative mandartoriety of one of the pairs, is there something more deep that I am missing?

vigji avatar Jun 18 '25 11:06 vigji

I am personally biased toward the option of exposing both left/right or front/rear and just check that one and only on of the pairs is present. I cannot see many drawbacks apart from the ugliness of the alternative mandartoriety of one of the pairs, is there something more deep that I am missing?

I don't think you are missing anything, it's just that we'll have to increase the number of arguments we expose and the code for handling all the cases, but I think in this case the payoff is worth it. I'll put this issue on the agenda for next community call.

niksirbi avatar Jun 18 '25 14:06 niksirbi

Hi @vigji, thanks for raising this point! It was bugging me for a while too 😅

We discussed it in the last community call (notes here) and thought of a simpler interface:

  • renaming compute_forward_vector to compute_perpendicular_vector, to make it more explicit that we compute the (2D) perpendicular vector to the vector that goes from the left to the right keypoint.
  • adding a new compute_vector_from_to function, that takes a from keypoint and a target (to) keypoint to compute the vector by subtracting the position vectors.
  • scrap compute_forward_vector_angle and instead have compute_vector_angle, that takes an input vector (rather than a pair of keypoints) and (optionally) a reference vector (by default the x-axis of the image coordinate system). In principle it would be for 2D data only, but we can generalise it.

What do you think?

Some pending bits would be:

  • the corresponding example would need to be updated accordingly
  • should we keep "head vector" convenience wrappers?
    • we think so, but unsure of the shape of this. Maybe in two steps? i.e. users would usecompute_head_vector first (using from/to or right/left keypoints), and then compute_vector_angle to get the head angle.

sfmig avatar Jun 30 '25 14:06 sfmig

Also, we welcome any suggestions for better names for any of these functions. We want to take this chance to re-design this module's API intro something more intuitive.

niksirbi avatar Jun 30 '25 15:06 niksirbi

Great about the consideration for the issue! The proposed solution sounds very reasonable to me.

I actually have a proposal for compute_vector_angle (or a different function, in case you do not want to overload it): for me it would be great to have the option of a reference with a time axis, in case you compute orientation to something that's moving around (in my very concrete scenario a cricket :))

vigji avatar Jun 30 '25 16:06 vigji

I actually have a proposal for compute_vector_angle (or a different function, in case you do not want to overload it): for me it would be great to have the option of a reference with a time axis, in case you compute orientation to something that's moving around (in my very concrete scenario a cricket :))

That's already supported, albeit not well documented! The existing compute_forward_vector_angle function can also accept a reference_vector that is another xr.DataArray with time axis (essentialy another time-varying vector), in which case it should return an xr.DataArray of angles over time. This "super-power" is built into the underlying compute_signed_angle_2D utility, because we were already thinking about moving reference frames when we implemented that.

We will make sure that compute_vector_angle can also handle both static and moving reference frames, and is properly documented as such.

niksirbi avatar Jun 30 '25 17:06 niksirbi

To manage expectations, this re-design of movement/kinematics/orientation.py is unlikely to happen before September, given the time we've already committed to other features this summer. Unless of course you want to give it a go yourself, in which case we'd be happy to provide feedback/guidance.

niksirbi avatar Jun 30 '25 17:06 niksirbi