From fdfed71bb2fb044c46dfbed0ece6f11e89663e49 Mon Sep 17 00:00:00 2001 From: Christian Tischer Date: Wed, 30 Oct 2024 09:23:38 +0100 Subject: [PATCH] Further improve annotation overlay performance --- .../bdv/overlay/AnnotatedRegionsOverlay.java | 6 +- .../lib/bdv/overlay/ImageNameOverlay.java | 71 +++++++++---------- .../mobie/lib/bdv/overlay/OverlayHelper.java | 24 +++++-- .../mobie/lib/bdv/overlay/OverlayItem.java | 3 + 4 files changed, 57 insertions(+), 47 deletions(-) diff --git a/src/main/java/org/embl/mobie/lib/bdv/overlay/AnnotatedRegionsOverlay.java b/src/main/java/org/embl/mobie/lib/bdv/overlay/AnnotatedRegionsOverlay.java index e9dd712b..42f72526 100644 --- a/src/main/java/org/embl/mobie/lib/bdv/overlay/AnnotatedRegionsOverlay.java +++ b/src/main/java/org/embl/mobie/lib/bdv/overlay/AnnotatedRegionsOverlay.java @@ -99,7 +99,7 @@ protected synchronized void draw( Graphics2D g ) start = System.currentTimeMillis(); for ( OverlayItem overlayItem : overlayItems ) { - OverlayHelper.drawTextWithBackground( g, overlayItem ); + OverlayHelper.drawTextWithBackground( g, overlayItem, false ); } // System.out.println( "drawn " + overlayItems.size() + " overlay items in [ms] " + ( System.currentTimeMillis() - start ) ); } @@ -118,14 +118,14 @@ private void updateOverlayItems( Graphics2D g ) final RealMaskRealInterval mask = annotatedRegion.getMask(); FinalRealInterval bounds = viewerTransform.estimateBounds( mask ); - OverlayItem overlayItem = OverlayHelper.itemFromBounds( + OverlayItem newItem = OverlayHelper.itemFromBounds( g, bounds, annotatedRegion.getValue( annotationColumn ).toString(), font ); - overlayItems.add( overlayItem ); + overlayItems.add( newItem ); } } } diff --git a/src/main/java/org/embl/mobie/lib/bdv/overlay/ImageNameOverlay.java b/src/main/java/org/embl/mobie/lib/bdv/overlay/ImageNameOverlay.java index 24adc644..76c3bbe3 100644 --- a/src/main/java/org/embl/mobie/lib/bdv/overlay/ImageNameOverlay.java +++ b/src/main/java/org/embl/mobie/lib/bdv/overlay/ImageNameOverlay.java @@ -28,11 +28,7 @@ */ package org.embl.mobie.lib.bdv.overlay; -import bdv.util.BdvFunctions; -import bdv.util.BdvHandle; -import bdv.util.BdvOptions; -import bdv.util.BdvOverlay; -import bdv.util.BdvOverlaySource; +import bdv.util.*; import bdv.viewer.SourceAndConverter; import bdv.viewer.TransformListener; import bdv.viewer.ViewerState; @@ -52,9 +48,7 @@ import java.awt.*; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; public class ImageNameOverlay extends BdvOverlay implements TransformListener< AffineTransform3D > { @@ -136,10 +130,9 @@ private void updateOverlayItems( Graphics2D g ) if ( image instanceof RegionAnnotationImage ) { - continue; + // Do nothing } - - if ( image instanceof StitchedImage ) + else if ( image instanceof StitchedImage ) { final List< ? extends Image< ? > > tileImages = ( ( StitchedImage< ?, ? > ) image ).getTileImages(); @@ -149,35 +142,43 @@ private void updateOverlayItems( Graphics2D g ) final FinalRealInterval intersect = Intervals.intersect( viewerInterval, imageMask ); if ( ! Intervals.isEmpty( intersect ) ) { - overlayItems.add( - OverlayHelper.itemFromBounds( - g, - viewerTransform.estimateBounds( imageMask ), - image.getName(), - font ) - ); + createAndAddNewOverlayItem( g, viewerTransform, imageMask, image ); } } - continue; } + else + { + final RealMaskRealInterval imageMask = image.getMask(); + final FinalRealInterval intersect = Intervals.intersect( viewerInterval, imageMask ); + if ( !Intervals.isEmpty( intersect ) ) + { + createAndAddNewOverlayItem( g, viewerTransform, imageMask, image ); + } + } + } + } - final RealMaskRealInterval imageMask = image.getMask(); - final FinalRealInterval intersect = Intervals.intersect( viewerInterval, imageMask ); - if ( ! Intervals.isEmpty( intersect ) ) + private void createAndAddNewOverlayItem( Graphics2D g, AffineTransform3D viewerTransform, RealMaskRealInterval imageMask, Image< ? > image ) + { + OverlayItem newItem = OverlayHelper.itemFromBounds( + g, + viewerTransform.estimateBounds( imageMask ), + image.getName(), + font ); + + boolean addItem = true; + for ( OverlayItem item : overlayItems ) + { + // TODO: This could be changed such that small overlaps are tolerated + if ( ! Intervals.isEmpty( Intervals.intersect( item.interval, newItem.interval ) ) ) { - // TODO: This will be slow if there are many - // Consider simplification, e.g. do not paint the black background - // But rather exclude over-painting by checking overlap with already existing - // overlay Items - overlayItems.add( - OverlayHelper.itemFromBounds( - g, - viewerTransform.estimateBounds( imageMask ), - image.getName(), - font ) - ); + addItem = false; + break; } } + + if ( addItem ) + overlayItems.add( newItem ); } @Override @@ -191,11 +192,7 @@ protected synchronized void draw( Graphics2D g ) for ( OverlayItem overlayItem : overlayItems ) { - // TODO: This will be slow if there are many - // Consider simplification, e.g. do not paint the black background - // But rather exclude over-painting by checking overlap with already existing - // overlay Items - OverlayHelper.drawTextWithBackground( g, overlayItem ); + OverlayHelper.drawTextWithBackground( g, overlayItem, false ); } } diff --git a/src/main/java/org/embl/mobie/lib/bdv/overlay/OverlayHelper.java b/src/main/java/org/embl/mobie/lib/bdv/overlay/OverlayHelper.java index 0f82bf51..013171b5 100644 --- a/src/main/java/org/embl/mobie/lib/bdv/overlay/OverlayHelper.java +++ b/src/main/java/org/embl/mobie/lib/bdv/overlay/OverlayHelper.java @@ -1,21 +1,25 @@ package org.embl.mobie.lib.bdv.overlay; +import net.imglib2.FinalInterval; import net.imglib2.FinalRealInterval; import java.awt.*; public class OverlayHelper { - public static void drawTextWithBackground( Graphics2D g, OverlayItem item ) + public static void drawTextWithBackground( Graphics2D g, OverlayItem item, final boolean drawBackground ) { // draw background (this helps with https://github.com/mobie/mobie-viewer-fiji/issues/1013) // but this is slow, if there are many annotations - g.setColor( Color.BLACK ); - g.fillRect( - item.x, - item.y - item.height + g.getFontMetrics().getDescent(), - item.width, - item.height ); + if ( drawBackground ) + { + g.setColor( Color.BLACK ); + g.fillRect( + ( int ) item.interval.min( 0 ), + ( int ) item.interval.min( 1 ), + ( int ) item.interval.dimension( 0 ), + ( int ) item.interval.dimension( 1 ) ); + } // draw text g.setColor( Color.WHITE ); @@ -45,6 +49,12 @@ public static OverlayItem itemFromBounds( item.height = g.getFontMetrics().getHeight(); item.x = (int) ( center - item.width / 2.0 ); item.y = (int) ( bounds.realMax( 1 ) + 1.1F * finalFont.getSize() ); + item.interval = FinalInterval.createMinSize( + item.x, + item.y - item.height + g.getFontMetrics().getDescent(), + item.width, + item.height ); + return item; } diff --git a/src/main/java/org/embl/mobie/lib/bdv/overlay/OverlayItem.java b/src/main/java/org/embl/mobie/lib/bdv/overlay/OverlayItem.java index 64d7d561..c9f348b9 100644 --- a/src/main/java/org/embl/mobie/lib/bdv/overlay/OverlayItem.java +++ b/src/main/java/org/embl/mobie/lib/bdv/overlay/OverlayItem.java @@ -1,5 +1,7 @@ package org.embl.mobie.lib.bdv.overlay; +import net.imglib2.FinalInterval; + import java.awt.*; public class OverlayItem @@ -10,4 +12,5 @@ public class OverlayItem public int width; public int height; public Font font; + public FinalInterval interval; }