Skip to content

Spatial Metrics (CSV) Export#332

Merged
Jordan-Pierce merged 9 commits intomainfrom
dev
Jan 22, 2026
Merged

Spatial Metrics (CSV) Export#332
Jordan-Pierce merged 9 commits intomainfrom
dev

Conversation

@Jordan-Pierce
Copy link
Owner

This pull request introduces several enhancements and fixes across annotation morphology metrics, polygon operations, transformer model selection, and IO exports. The main changes expand the set of computed morphology metrics for annotations, improve polygon merging robustness, add new transformer models (including conditional support for DINOv3), and introduce a new export option for spatial metrics.

Morphology Metrics Enhancements:

  • Expanded the set of computed morphology metrics in QtAnnotation.py to include orientation, bounding box width/height, elongation, eccentricity, rectangularity, and compactness. These are now calculated and stored for all applicable annotation types. [1] [2] [3] [4]
  • Updated QtPolygonAnnotation.py and QtRectangleAnnotation.py to provide these new raw metrics for use in the base morphology calculation, ensuring rectangles and polygons both report the expanded set of metrics. [1] [2] [3] [4]

Polygon Annotation Robustness:

  • Improved the polygon annotation merging logic to automatically fix invalid geometries using buffering, both before and after the union operation, reducing the risk of topology errors in merged results.

Transformer Model Selection:

  • Added support for additional transformer models (Swin Transformer, ViT) and conditionally included DINOv3 models if a HuggingFace token is available in the environment. This makes advanced models available only when access is permitted. [1] [2] [3]

Spatial Metrics Export:

  • Registered a new export option, ExportSpatialMetrics, in the IO module to enable exporting of spatial metrics. [1] [2]

Other Improvements:

  • Added get_min_z and get_max_z methods to QtAnnotation.py for retrieving minimum and maximum z-values within an annotation, supporting conversion to real-world units.
  • Cleaned up the output of to_dict and to_coralnet methods in QtAnnotation.py by removing redundant area and perimeter fields, relying on morphology for these values. [1] [2]

Jordan-Pierce and others added 3 commits January 20, 2026 14:55
…lations

- Implemented `get_morphology` method in `RectangleAnnotation` to calculate and return various shape metrics.
- Enhanced `PolygonAnnotation` to include orientation and bounding box dimensions in its morphology metrics.
- Introduced `ExportSpatialMetrics` dialog for exporting spatial metrics of annotations to CSV, allowing users to select images, labels, annotation types, and metrics.
- Updated `ConfidenceWindow` to display additional morphology metrics including orientation, compactness, elongation, rectangularity, and eccentricity.
- Modified `MainWindow` to integrate the new spatial metrics export functionality into the UI.
- Ensured compatibility with existing annotation types and metrics, providing a comprehensive export feature for spatial analysis.
@Jordan-Pierce Jordan-Pierce self-assigned this Jan 21, 2026
@Jordan-Pierce Jordan-Pierce added the enhancement New feature or request label Jan 21, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @Jordan-Pierce, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the application's annotation analysis and data export capabilities. It introduces a richer set of morphology metrics for various annotation types, improving the descriptive power of annotations. Furthermore, it bolsters the robustness of polygon operations and expands the range of available transformer models for advanced image processing. The most notable addition is a new, dedicated CSV export feature for spatial metrics, allowing users to extract detailed quantitative data about their annotations with flexible filtering options.

Highlights

  • Expanded Morphology Metrics: New metrics like orientation, bounding box width/height, elongation, eccentricity, rectangularity, and compactness are now calculated and stored for annotations. QtPolygonAnnotation and QtRectangleAnnotation have been updated to provide these raw metrics, and tooltips in QtConfidenceWindow now display them.
  • Enhanced Polygon Merging Robustness: The polygon merging logic has been improved to automatically fix invalid geometries using buffering, both before and after union operations, significantly reducing the risk of topology errors in merged results.
  • Conditional Transformer Model Support: Support for additional transformer models (Swin Transformer, ViT) has been added. DINOv3 models are now conditionally included, appearing only if a HuggingFace token is available in the environment, ensuring access is permitted.
  • New Spatial Metrics Export Feature: A dedicated 'Export Spatial Metrics' option has been introduced in the IO module. This new feature allows users to export a comprehensive set of spatial metrics for annotations to CSV, complete with filtering capabilities by image, label, and annotation type.
  • 3D Z-Value Retrieval: New methods get_min_z and get_max_z were added to QtAnnotation.py for retrieving minimum and maximum z-values within an annotation, supporting conversion to real-world units.
  • Refined Annotation Data Export: Redundant area and perimeter fields have been removed from the to_dict and to_coralnet methods in QtAnnotation.py, streamlining data output by relying on the dedicated morphology calculations.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new spatial metrics export feature and enhances morphology calculations. The changes are well-structured, especially the new ExportSpatialMetrics dialog. I've found a few critical issues in the new export logic related to unit conversions for volume and surface area calculations that will lead to incorrect results. I've also identified an incorrect calculation for pixel-based metrics. Additionally, there's an opportunity to refactor some new methods in QtAnnotation.py to improve maintainability by reducing code duplication.

# 3D Metrics
elif metric == 'volume':
if z_channel is not None and has_scale:
volume = annotation.get_scaled_volume(z_channel, scale_x, scale_y, z_unit)
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

There's a unit mismatch when calling get_scaled_volume. This method expects the scale factors (scale_x, scale_y) to be in meters per pixel, as per its docstring. However, the code passes annotation.scale_x and annotation.scale_y directly, which are in scale_units per pixel (e.g., cm/pixel). This will lead to incorrect volume calculations if the scale units are not meters.

You should convert scale_x and scale_y to meters/pixel before passing them to this function. You've already calculated to_meters_factor which can be used for this conversion.

Suggested change
volume = annotation.get_scaled_volume(z_channel, scale_x, scale_y, z_unit)
volume = annotation.get_scaled_volume(z_channel, scale_x * to_meters_factor, scale_y * to_meters_factor, z_unit)

pixel_value = volume / (scale_x * scale_y * (to_meters_factor ** 2))
elif metric == 'surface_area':
if z_channel is not None and has_scale:
surf_area = annotation.get_scaled_surface_area(z_channel, scale_x, scale_y, z_unit)
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

Similar to the volume calculation, there's a unit mismatch when calling get_scaled_surface_area. This method expects scale factors in meters per pixel, but is being passed values in scale_units per pixel. This will result in incorrect surface area values. Please convert the scales to meters/pixel before the call.

Suggested change
surf_area = annotation.get_scaled_surface_area(z_channel, scale_x, scale_y, z_unit)
surf_area = annotation.get_scaled_surface_area(z_channel, scale_x * to_meters_factor, scale_y * to_meters_factor, z_unit)

# Volume is already in the correct units
meter_value = volume
# Calculate pixel equivalent (approximation)
pixel_value = volume / (scale_x * scale_y * (to_meters_factor ** 2))
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The calculation for the "pixel equivalent" of volume is dimensionally incorrect. The expression volume / (scale_x * scale_y * (to_meters_factor ** 2)) results in units of m * px^2, not a pixel-based volume. A more direct pixel-based volume would be the sum of z-values in pixels over the annotation area. You can get the pixel z-values from annotation._get_raster_slice_and_mask(z_channel) and sum them.

The same issue exists for surface_area on line 650.

@Jordan-Pierce Jordan-Pierce merged commit 1b91e2b into main Jan 22, 2026
2 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant