Skip to content

Functions to QC histopathology images#1036

Open
timtreis wants to merge 3 commits intomainfrom
bugfix/issue1034-function-to-qc-he-images
Open

Functions to QC histopathology images#1036
timtreis wants to merge 3 commits intomainfrom
bugfix/issue1034-function-to-qc-he-images

Conversation

@timtreis
Copy link
Member

IMPORTANT: Please search among the Pull requests before creating one.

Description

How has this been tested?

Closes

@timtreis timtreis linked an issue Sep 14, 2025 that may be closed by this pull request
@timtreis timtreis changed the title MVP for image QC Functions to QC histopathology images Sep 14, 2025
@codecov
Copy link

codecov bot commented Oct 29, 2025

Codecov Report

❌ Patch coverage is 67.59777% with 174 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.62%. Comparing base (59afd9e) to head (5ae7f70).

Files with missing lines Patch % Lines
src/squidpy/experimental/im/_sharpness_metrics.py 25.35% 52 Missing and 1 partial ⚠️
src/squidpy/experimental/im/_qc_image.py 80.22% 20 Missing and 15 partials ⚠️
src/squidpy/experimental/pl/_qc_image.py 60.22% 23 Missing and 12 partials ⚠️
src/squidpy/experimental/im/_utils.py 71.84% 21 Missing and 8 partials ⚠️
src/squidpy/experimental/im/_qc_metrics.py 76.40% 20 Missing and 1 partial ⚠️
src/squidpy/experimental/im/_make_tiles.py 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1036      +/-   ##
==========================================
- Coverage   73.10%   72.62%   -0.49%     
==========================================
  Files          38       42       +4     
  Lines        6473     6914     +441     
  Branches     1144     1198      +54     
==========================================
+ Hits         4732     5021     +289     
- Misses       1265     1386     +121     
- Partials      476      507      +31     
Files with missing lines Coverage Δ
src/squidpy/experimental/im/_make_tiles.py 67.94% <88.88%> (-1.73%) ⬇️
src/squidpy/experimental/im/_qc_metrics.py 76.40% <76.40%> (ø)
src/squidpy/experimental/im/_utils.py 61.33% <71.84%> (+23.03%) ⬆️
src/squidpy/experimental/im/_qc_image.py 80.22% <80.22%> (ø)
src/squidpy/experimental/pl/_qc_image.py 60.22% <60.22%> (ø)
src/squidpy/experimental/im/_sharpness_metrics.py 25.35% <25.35%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.



# --- Registry ---

Copy link
Member

Choose a reason for hiding this comment

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

like the idea with the metric registry puts structure into complicated input types. Should consider adopting something like this more generally. Also do you know how well this works with spatialdata images and if they use something similar?

Copy link
Member Author

Choose a reason for hiding this comment

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

like the idea with the metric registry puts structure into complicated input types.

agree!

Also do you know how well this works with spatialdata images and if they use something similar?

Wdym?

Copy link
Member

Choose a reason for hiding this comment

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

Wdym?

like in general I wonder if there is something already similar to this in spatialdata codebase. Not the registry itself but the InputKind.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ahh, not that I'm aware of 🤔 We're channel agnostic. In sdata-plot I try to infer this from the channel names but formally it doesn't exist

Copy link
Member

@selmanozleyen selmanozleyen left a comment

Choose a reason for hiding this comment

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

Things to do:

  • Sync with main (some files are old)
  • Vectorize for loops I mentioned
  • Use scikit-image when we can

@timtreis timtreis force-pushed the bugfix/issue1034-function-to-qc-he-images branch from e4890cc to 5952a86 Compare February 26, 2026 15:43
Replaces the earlier qc_sharpness prototype with a general-purpose
qc_image function that computes tile-based QC metrics on spatial images.

Compute (sq.experimental.im.qc_image):
- Tile-based metrics: sharpness (tenengrad, var_of_laplacian), intensity
  (brightness, entropy), staining (hematoxylin/eosin via HED deconvolution),
  and artifact detection (fold fraction, tissue fraction)
- QCMetric enum and registry mapping each metric to its input kind and
  callable
- Percentile-rank unfocus scoring within tissue tiles for outlier detection
- Preview overlay showing flagged tiles on the image
- Shared utilities in _utils.py: vectorized TileGrid (numpy + shapely.box),
  mask helpers, and shapes persistence (also used by make_tiles)

Plot (sq.experimental.pl.qc_image):
- Multi-panel summary: spatial view, KDE distribution (tissue vs background),
  and descriptive statistics per metric

Metrics use scikit-image filters (sobel_h/v, laplace) instead of hand-rolled
convolutions, and thread-safe HED caching avoids redundant deconvolution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@timtreis timtreis force-pushed the bugfix/issue1034-function-to-qc-he-images branch from 5952a86 to a5e4dfd Compare February 26, 2026 15:45


# --- Intensity metrics (grayscale input) ---

Copy link
Member

Choose a reason for hiding this comment

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

Maybe you aren't done yet but while I have it in mind I want to say I'd put intensity metrics in another file like done in sharpness metrics and have the registry in shorter file.

Also functions called outside a module should not start with _. squidpy.experimental.im._sharpness_metrics
is already private so _tenengrad_mean can be tenengrad_mean. Thats why in your IDE it might show _tenengrad_mean as unused function because the assumption is _tenengrad_mean is only meant to be used in the function it is defined.

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.

Function to QC H&E images

2 participants