Proposed changes to Markups to support unplaced points

I’d like to help implement some updates to support the use of unplaced fiducials, as discussed in this thread. From that discussion and our user needs, I made a detailed list of improvements and would appreciate feedback or advice. @lassoan your input would be especially helpful.

@ezgimercan @muratmaga

Views

  • Hide display of unplaced fiducials
  • Hide position of unplaced fiducial in Markups control point table

Markups Module

  • Add buttons for unplace all/unplace selected to the menu bar above the control points table, similar to delete all/delete selected (see screenshot)

  • Add column in the control points table for placement status. This could be modeled after the Segment editor status column, which shows an open circle for segments not started and a check mark for complete (see screenshot below). Toggling the icon to checkmark would initiate landmark placement mode to place this point. Toggling again to the open circle would set position to (0,0,0) and set “unplaced” flag.

  • Update “Add new markup at origin” button to add new unplaced markup. This button currently is not working for me with the intended function.

Save/Load

  • Update FCSV writer to save the position status flag

  • Update FCSV reader to read and set position status flag, set visibility

2 Likes

Awesome @smrolfe, thank you.

Would it be possible to address the confusion about selected vs highlighted fiducials as well? I am not entirely sure why we have two different modes of choosing LMs? (e.g., copy and paste seems to function only with highlight but not with select).

All sounds good.

Yes, the button is currently broken (does not do anything) - it should be fixed.

In addition to what is described above:

  • markup placement behavior should be changed so that if there are undefined control points then first they would be placed instead of adding new points.
  • markups table should be a reusable widget: you can either use qSlicerSimpleMarkupsWidget as a starting point or the segment list widget. Segment list widget already has status and filtering features (right-click to enable it) which will be very useful when you handle more than 10 control points.

“Selected” state of a control point is a property of the node (shared between all markups tables), which determines the color of the control point and is used by various modules (e.g., landmark registration only takes into account selected control points; vessel network extractor uses unselected points as source points, selected points as target points).

Highlight in the table is just temporary selection in one particular table so that you can operate on multiple points at once.

How would you change the GUI to make this more clear?

I am not sure yet.

But right now, for SLicerMorph we need a mechanism that visually provides a clue of highlighted control points in the viewers (or vice versa, like picking a control point in the 3D viewer, should highlight in the table view). From our workshops we are seeing new users right also expecting that behavior.

From your description, ‘selected’ state seems like a fairly marginal use. In fact it sounds like both use cases can be covered by creating mutually exclusive fiducial nodes for selected and unselected subsets.

Easy toggling each control point is an important feature. You may need it at some point, too. Anyway, there is no conflict of interest here: Slicer core can be generic and you can use only the features that you need right now.

To make things very convenient, you probably want to add a custom landmark placement module to SlicerMorph. A very small, simple Python-scripted module would suffice, which would contain a few high-level widgets, which would be set up to work exactly as your users like it, hide things that you don’t need, and add convenience features, such as loading point set templates, maybe some quick import/export features, etc.

This exists already: right-lick on the control point and choose “Toggle select point”.

If you need more temporary highlighting then “active” control point mechanism may be usable (this is in addition to selected/non-selected and defined/undefined state; it is just a display state). A control point (or curve) is highlighted when you hover over it or moving it. Highlighting is already propagated to all viewers and it could be quite easily displayed in the control point list, too. A limitation is that there is always only one active control point per context (i.e., one for the desktop mouse, and one for each virtual reality controller).

To have multiple selections and somewhat temporary selection state, the new control point table widget could offer a “direct select” mode. In this mode, the selection checkboxes could be hidden and row selection in the table widget could be synchronized with the control point’s selection state. You could enable this mode in your custom module (and maybe we could expose it in Markups module, too; similarly to how “Click to jump slices” mode can be enabled with a checkbox).

If you plan to make profound changes to Markups, I would suggest adding more simple events like :

PointPrependEvent (added before the first, becoming first)
PointAppendEvent (added after the last, becoming last)
PointPositionChangedEvent (when changed in the list of control points)

Might be of interest.

Regards.

Thanks Andras. I have just one concern with the markup placement behavior:

Occasionally a user needs to skip a landmark (e.g. missing data, abnormality). If a landmark was skipped, it would not be possible to add new landmarks if the logic forced placement of all unplaced points first. I think you could make a case for keeping the current placement behavior and using the control point table to initiate placement.

One workaround might be to have a three toggle options in the status column (placed, not placed, skipped) that would let the placement logic skip over select unplaced points.

1 Like

I think having the selection toggle/checkboxes in the table along with cut/paste/delete tools that only work for highlighted points can be confusing. It would be nice to be able to select points with any method and use these tools. Unless I’m missing something, the only way to do this would be to highlight the selected points in the table individually.

Maybe a button to highlight all selected points could help?

This would not be a workaround but an elegant solution to add a state to indicate that a point should not be attempted to be placed. “Skipped” as state name is not bad, but maybe “missing” could be better, or maybe “unavailable” or “ignore”.

Yes, of course if a user does not need the additional flexibility and a simple transient selection state is sufficient then anything beyond that is “confusing”. The key is to find a way to “make simple things simple and complex things possible”. One option that I described above is to add a new operating mode to the control point table: “direct select mode”. In this mode, checkbox column would be hidden. Selecting/unselecting rows in the table would automatically select/unselect the control points.

I can see how a highlight selected/unselected points could be useful, especially when there are many points.

However, a more powerful and more sustainable solution would be to allow filtering based on selected state of the control point (in addition to search by text and filter by control point state undefined/unavailable/defined). Then you could easily create a custom list by search&filtering and perform operations on all the points in the result set. For example, delete all could delete all control points that are displayed with the current search&filter settings.

1 Like

That’s a great idea! And could easily be wrapped into the other updates to the table.

First of all, so excited that Markups module is getting some much needed attention. Thanks, @smrolfe!

  1. Skipping one or more landmarks is a very common case when using template lists. Annotating landmarks in order is also very common and automatically moving to the next “unselected/unmarked” landmark on the list would be very helpful. But I also observed that sometimes it is easier to landmark points out of order. I think having an option to annotate a landmark point out of order would be good - without flagging points in between as “skipped/missing”. I’ve used other programs that does this by highlighting the point on the list: when the cursor is changed to “annotation” mode, if the user highlights another point on the list, that point is captured on the image. And then it can move to the next undefined point or go back to the first undefined point.

  2. I might have missed this point in the discussion but from what I understand, before all points in a list are either placed or skipped, changing the cursor mode to landmark/annotate would not add a new point, right? So, there should be a way to skip all points (for example by highlighting all and changing the flag).

  3. Moving/reannotating or undefining (skipping) an already placed landmark. Undefining could be done by simply changing the flag. For moving or re-annotation (re-placing), it could be done by either changing the flag, or if there is a way to annotate a point by highlighting it (see 1 above), it could be done that way. And there is also the original way of moving landmarks on the views when not in fiducial placement mode.

I really like the idea of searching/filtering by name and state. Especially when working with large landmark templates, searching by name would be very useful. Not only delete but “lock”, “select”, “flag (finished/skipped/undefined)” actions can be applied to these filtered points.

2 Likes

Yes, it would work like this in Slicer, too. You can click “place” button of in the table in any row to place that point. After that, if “persistent” mode is enabled then we would automatically offer placement of the next undefined point in the list.

We need to improve the toolbar as well, because currently it is not clear which point of which markups node would be placed when the user clicks the place button in the toolbar.

We could do the same as in the segment list for segment status: you can select multiple rows and then change their state using right-click menu.

Move: you can drag-and-drop any point.
Re-place: you will be able to do it by clicking on the “Place” button in the corresponding row in the table.
Undefine: you will be able to right-click in the table or in a view and setting state to undefined or delete.

Agreed. This has been proven to work very well for segment lists already: it is really easy to handle large atlases that contains hundreds of segments.

@smrolfe Since it seems that we will need most of the features of the segments table view, I would recommend to create a new qSlicerMarkupsControlPointsTableView class (and corresponding model and proxy model classes) based on qMRMLSegmentsTableView (and related classes).

2 Likes

Sounds great. I’m scheduling time next week to tackle this.