Skip to content

Add end-to-end polygon (Mask R-CNN) workflow#1399

Open
bw4sz wants to merge 2 commits into
weecology:mainfrom
bw4sz:cursor/polygon-maskrcnn-workflow
Open

Add end-to-end polygon (Mask R-CNN) workflow#1399
bw4sz wants to merge 2 commits into
weecology:mainfrom
bw4sz:cursor/polygon-maskrcnn-workflow

Conversation

@bw4sz

@bw4sz bw4sz commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Implement instance segmentation paralleling the box and point workflows:

  • Add Mask R-CNN model (task="polygon"), encapsulating the torchvision background-class convention by shifting labels in forward()
  • Refactor PolygonDataset to mirror BoxDataset (csv_file, 3-tuple, joint image/box/mask augmentation)
  • Support polygon prediction formatting and mask-based geometry detection
  • Wire segmentation mAP and polygon recall/precision into validation
  • Enable polygon mosaicking in predict_tile via reduce_polygons
  • Add tests for the dataset, model, formatting, training and prediction

Description

Related Issue(s)

AI-Assisted Development

  • I used AI tools (e.g., GitHub Copilot, ChatGPT, etc.) in developing this PR
  • I understand all the code I'm submitting
  • I have reviewed and validated all AI-generated code

AI tools used (if applicable):

bw4sz and others added 2 commits June 9, 2026 10:34
Implement instance segmentation paralleling the box and point workflows:
- Add Mask R-CNN model (task="polygon"), encapsulating the torchvision
  background-class convention by shifting labels in forward()
- Refactor PolygonDataset to mirror BoxDataset (csv_file, 3-tuple,
  joint image/box/mask augmentation)
- Support polygon prediction formatting and mask-based geometry detection
- Wire segmentation mAP and polygon recall/precision into validation
- Enable polygon mosaicking in predict_tile via reduce_polygons
- Add tests for the dataset, model, formatting, training and prediction

Co-authored-by: Cursor <[email protected]>
@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 77.43363% with 51 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.71%. Comparing base (d2851ec) to head (aa05206).
⚠️ Report is 8 commits behind head on main.

Files with missing lines Patch % Lines
src/deepforest/models/maskrcnn.py 58.57% 29 Missing ⚠️
src/deepforest/datasets/training.py 80.00% 16 Missing ⚠️
src/deepforest/predict.py 88.23% 2 Missing ⚠️
src/deepforest/utilities.py 93.93% 2 Missing ⚠️
src/deepforest/main.py 94.44% 1 Missing ⚠️
src/deepforest/metrics.py 83.33% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1399      +/-   ##
==========================================
- Coverage   86.61%   85.71%   -0.90%     
==========================================
  Files          26       28       +2     
  Lines        3736     3970     +234     
==========================================
+ Hits         3236     3403     +167     
- Misses        500      567      +67     
Flag Coverage Δ
unittests 85.71% <77.43%> (-0.90%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jveitchmichaelis jveitchmichaelis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@bw4sz as far as your concerns about this, my opinion is the general feel of this PR is good. It cribs the right bits from other sections of the code. Can you feed the review notes back into Cursor?

Comment thread src/deepforest/main.py

# Compute precision, recall and empty frame metrics.
if self.model.task == "box" or self.model.task == "point":
if self.model.task in ("box", "point", "polygon"):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Redundant? At least for now we can compute PR for any task so we can always add this metric.

"""Determine the geometry type of the batched result."""
# Assumes that all geometries are the same in a batch
if "boxes" in batched_result.keys():
# Assumes that all geometries are the same in a batch. Mask R-CNN

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I would remove the reference to Mask R-CNN here and say "Polygon model results that contain both ... "

label_dict: dict = None,
**kwargs,
):
backbone = torchvision.models.detection.maskrcnn_resnet50_fpn(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

There is also V2. https://docs.pytorch.org/vision/main/models/mask_rcnn.html

Improved Mask R-CNN model with a ResNet-50-FPN backbone from the Benchmarking Detection Transfer Learning with Vision Transformers paper.

Comment thread tests/test_maskrcnn.py
predictions = model(x)

assert len(predictions) == 2
assert sorted(predictions[0].keys()) == ["boxes", "labels", "masks", "scores"]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should also check the shape of the masks.

Comment thread tests/test_maskrcnn.py
assert targets[0]["labels"].tolist() == [0]


def test_check_model():

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Redundant with test_predict_outputs_masks?

area = torch.as_tensor(targets["area"])
image_id = targets["image_id"]

# Filter out-of-bounds boxes and sync with transformed

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Keep this comment?

Comment thread src/deepforest/main.py
synced_metrics[key] = torch.tensor(value, device=self.device)
else:
synced_metrics[key] = value
elif self.model.task == "polygon":

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not obvious why this should be separate logic to boxes?

Comment thread src/deepforest/main.py
results.update(self.trainer.logged_metrics)
results["predictions"] = self.predictions
if self.model.task == "box" or self.model.task == "point":
if self.model.task in ("box", "point", "polygon"):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Drop the condition here as this is valid for all model tasks

Comment thread src/deepforest/predict.py
return predictions.iloc[np.flatnonzero(kept)].reset_index(drop=True)


def reduce_polygons(predictions: pd.DataFrame, iou_threshold: float) -> pd.DataFrame:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Does this need to be a different function? Polygons aren't used at all here, only box bounds. If the result is that the dataframe/preds are filtered by index then it shouldn't matter if we ran reduce_boxes.

Might need to refactor with an output_columns argument?

Comment thread src/deepforest/datasets/training.py
@bw4sz

bw4sz commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator Author

Sorry, I actually didn't mean to trigger this into main yet. Thanks for looking at it. I thought I pushed to my fork. Let's hold this open and I will clean it up on monday.

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