Skip to content

bounding box annotation for bronchoscopy videos - #21

Merged
ehof merged 6 commits into
synced-with-serverfrom
20-bounding-box-annotation-for-bronchoscopy-videos
Jun 26, 2026
Merged

bounding box annotation for bronchoscopy videos#21
ehof merged 6 commits into
synced-with-serverfrom
20-bounding-box-annotation-for-bronchoscopy-videos

Conversation

@ehof

@ehof ehof commented May 6, 2026

Copy link
Copy Markdown
Collaborator

The new functionality can be tested on a dataset from a CustusX patient with a bronchoscopy video acquired.

  1. Make a subsequence_classification task and do some annotations (to check that they are read into step 2).
  2. Make a bronchoscopy_bounding_box task.
    a) Check that the annotations from step 1 are read in and displayed (e.g. "Current branch: 1,1,2").
    b) Check that you are able to draw bounding boxes with different names and with random colours.
    c) Copy to next frame is working.
    d) Check that the annotation file is created with one line per box per frame.

Erlend Fagertun Hofstad added 2 commits May 5, 2026 13:29
…ee-text labeled bounding boxes, per-box color coding, color-preserving copy-to-next-frame, multi-frame save, duplicate-label prevention, CSV exporter, and edit-annotations support. #20
…unding box annotation view: Shows the current branch label (from a linked subsequence_classification task) below the canvas, updating as the slider is moved. Displays N/A for frames without a label. #20
@ehof
ehof requested a review from jpdefrutos May 6, 2026 10:30
Comment thread bronchoscopy_bounding_box/migrations/0001_initial.py Outdated
Comment thread bronchoscopy_boundingbox/models.py Outdated
width = models.PositiveIntegerField()
height = models.PositiveIntegerField()
label = models.CharField(max_length=255, blank=True)
color = models.CharField(max_length=7) # hex color, e.g. '#e6194b'

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I undestand that to not clutter the Labels table with user-inputed box names, you want to save the label and colour on the BronchoscopyBoundingBox. Yet, have you considered the alternative proposed by Karen to add new labels on-the-fly? It could enable recycling of already inputed labels in previous annotation tasks.

On a side note, but still related to my previouos comment, the labels selected when creating the task are not available for the user.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this would function the same way as for subsequence_classification, where new labels are added if not seen before. However, I do not see how this would make an impact anyway. A more robust solution could be to add a check for valid labels. E.g. only integers <5, separated by ",".

@jpdefrutos jpdefrutos May 21, 2026

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the PR with the automatic new-label creation functionality I mentioned: #18

Comment thread bronchoscopy_bounding_box/models.py Outdated
Comment thread bronchoscopy_bounding_box/urls.py Outdated
Comment thread bronchoscopy_boundingbox/views.py Outdated
y=int(box['y']),
width=int(box['width']),
height=int(box['height']),
label=box.get('label', ''),

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to my previous comment on empty label texts

g_BBx = pos.x;
g_BBy = pos.y;
var inside = isInsideBox(pos.x, pos.y);
if (inside.isInside) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the "Box label" text box with the selected box label. It is reasonable to expect the user to be able to change the label of the last selected box.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have only one label text field. The value entered will be the code to the next drawn box, it will not update the name of an existing box. It the code is incorrect, the box needs the be deleted and redrawn after entering the correct label. We could add a new functionality to update the name of existing boxes, but that would require a few additions to the GUI.

@jpdefrutos

jpdefrutos commented May 13, 2026

Copy link
Copy Markdown
Owner

I forgot to add that the behaviour of the application is as expected, according to the test instructions. Good job!

…oscopy_bounding_box → bronchoscopy_boundingbox and (2) enforce non-empty box label.

1:Renames the app directory, static/template subdirectories, JS file, and
  exporter file, updating all references in settings, urls, views, apps.py,
  and the exporter import. URL namespace updated to match.

2:Adds frontend validation blocking box drawing when the label field is
  empty (red outline feedback for 1 s). Also sets blank=False on the model
  label field to enforce the constraint at the database level.

@jpdefrutos jpdefrutos left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commit fixes the naming of the application and the empty label field issue.

We discussed about using the automatic label creation proposed in #18

I will leave this PR open waiting for what do you prefer to do next. Either merge these changes, or change the design of the bounding box for bronchoscopy application :)

  Replace the cycling fixed-palette approach with a hash-based color
  generation scheme aligned with PR #18 (feature/textbox-colored-labels):

  - Add stringToColor() using the polynomial hash + golden angle (137.508°)
    mapping to HSL hue, so similar labels get visually distinct colors
  - Add hslToHex() helper to produce well-saturated, consistent colors
  - Cache label→color in g_labelColorMap so the same label always gets
    the same color within and across sessions
  - Auto-create missing Label entries in the shared Label model (with RGB
    color) and link them to the task on save, if not already present
  - Drop BronchoscopyBoundingBox.color — color is now derived from the
    label name rather than stored per box
@ehof

ehof commented May 21, 2026

Copy link
Copy Markdown
Collaborator Author

I removed the color from BronchoscopyBoundingBox, and rather use the color from existing Label entries. Using a similar approach to generate deterministic colours for labels as is done in feature/textbox-colored-labels (PR#18), however two improvements were needed. First, the color generator did make similar colors for similar labels, resulting in two bounding-boxes in the same frame having very similar colors. This was fixed by scattering neighbours in the polynomial hash. Second, trying to avoid light red colours, similar to the background.

The same color generation strategy should also be used in feature/textbox-colored-labels.

Erlend Fagertun Hofstad added 2 commits May 27, 2026 11:52
  These color utilities were only available in bronchoscopy_boundingbox.
  Moving them to annotationweb.js (loaded globally via base.html) makes
  them accessible to all annotation types without any template changes.
  save_boxes() crashed with a KeyError when a key frame had no boxes
  drawn on it: g_boxes only contains frames with boxes, but annotations
  iterates all key frames. Fix by skipping frames absent from boxes_data.

  Also wrap the entire view in transaction.atomic() so a failure cannot
  leave the DB in a partially-saved state.
@ehof
ehof merged commit 1fd8152 into synced-with-server Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants