Skip to content

Commit

Permalink
Fix a couple of performance issues in peak_local_max (improve perfo…
Browse files Browse the repository at this point in the history
…rmance of blob detectors and `corner_peaks`) (#782)

It seems that we can get a large speedup in calls to `peak_local_max` when the default `min_distance=1` is specified. A bottleneck in that function can be the call to `ensure_spacing` which falls back to the CPU, but we don't need to call that function at all unless `min_distance>1` (no coordinates can be excluded if min_distance=1, so it is pointless to call it).

I proposed the same changes upstream in scikit-image/scikit-image#7548. See additional comments and measurements made there.

There should be no change in behavior with this MR, it is purely a performance improvement.

Authors:
  - Gregory Lee (https://github.com/grlee77)

Approvers:
  - Gigon Bae (https://github.com/gigony)

URL: #782
  • Loading branch information
grlee77 authored Sep 24, 2024
1 parent 8461465 commit cc42019
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 5 deletions.
2 changes: 1 addition & 1 deletion python/cucim/src/cucim/skimage/_shared/coord.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def _ensure_spacing(coord, spacing, p_norm, max_out):
# keep current point and the points at exactly spacing from it
candidates.remove(idx)
dist = distance.cdist(
[coord[idx]], coord[candidates], distance.minkowski, p=p_norm
[coord[idx]], coord[candidates], "minkowski", p=p_norm
).reshape(-1)
candidates = [c for c, d in zip(candidates, dist) if d < spacing]

Expand Down
9 changes: 5 additions & 4 deletions python/cucim/src/cucim/skimage/feature/peak.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ def _get_high_intensity_peaks(image, mask, num_peaks, min_distance, p_norm):
else:
max_out = None

coord = ensure_spacing(
coord, spacing=min_distance, p_norm=p_norm, max_out=max_out
)
if min_distance > 1:
coord = ensure_spacing(
coord, spacing=min_distance, p_norm=p_norm, max_out=max_out
)

if len(coord) > num_peaks:
coord = coord[:num_peaks]
Expand All @@ -53,7 +54,7 @@ def _get_peak_mask(image, footprint, threshold, mask=None):
out = image == image_max

# no peak for a trivial image
image_is_trivial = np.all(out) if mask is None else np.all(out[mask])
image_is_trivial = cp.all(out) if mask is None else cp.all(out[mask])
if image_is_trivial: # synchronize
out[:] = False
if mask is not None:
Expand Down

0 comments on commit cc42019

Please sign in to comment.