From fc481bfa35ef8312fa4734e87cbd8731d4e49051 Mon Sep 17 00:00:00 2001 From: AndreasBurger Date: Wed, 6 Jul 2016 19:50:39 +0200 Subject: [PATCH] Various bugfixes for the combined image view, especially when synchronizing images with different dimensions. --- .../nodes/view/CombinedCellViewFactory.java | 36 +++++++++--- .../core/ui/imgviewer/CombinedImgViewer.java | 3 + .../NormalizationParametersChgEvent.java | 4 +- .../panels/providers/CombinedRU.java | 27 ++++++++- .../imgviewer/panels/providers/ImageRU.java | 56 ++++++++++++++++--- .../panels/providers/LabelingRU.java | 17 +++++- 6 files changed, 121 insertions(+), 22 deletions(-) diff --git a/org.knime.knip.base/src/org/knime/knip/base/nodes/view/CombinedCellViewFactory.java b/org.knime.knip.base/src/org/knime/knip/base/nodes/view/CombinedCellViewFactory.java index 98e73fa8..d2f47022 100644 --- a/org.knime.knip.base/src/org/knime/knip/base/nodes/view/CombinedCellViewFactory.java +++ b/org.knime.knip.base/src/org/knime/knip/base/nodes/view/CombinedCellViewFactory.java @@ -62,6 +62,7 @@ import org.knime.knip.cellviewer.interfaces.CellViewFactory; import org.knime.knip.core.awt.ColorLabelingRenderer; import org.knime.knip.core.awt.Real2GreyRenderer; +import org.knime.knip.core.data.img.DefaultImgMetadata; import org.knime.knip.core.ui.imgviewer.CombinedImgViewer; import org.knime.knip.core.ui.imgviewer.events.ImgWithMetadataChgEvent; import org.knime.knip.core.ui.imgviewer.events.LabelingWithMetadataChgEvent; @@ -71,7 +72,11 @@ import org.knime.knip.core.ui.imgviewer.panels.providers.LabelingRU; import org.knime.knip.core.util.waitingindicator.WaitingIndicatorUtils; +import net.imagej.ImgPlusMetadata; +import net.imglib2.img.Img; +import net.imglib2.img.ImgView; import net.imglib2.type.numeric.RealType; +import net.imglib2.view.Views; /** * TODO Auto-generated @@ -111,6 +116,7 @@ public void onReset() { // Nothing to do here } + @SuppressWarnings("unchecked") @Override public void updateComponent(final List valueToView) { WaitingIndicatorUtils.setWaiting(m_view, true); @@ -120,12 +126,28 @@ public void updateComponent(final List valueToView) { for (DataValue v : valueToView) { if (v instanceof ImgPlusValue) { final ImgPlusValue imgPlusValue = (ImgPlusValue)v; - ImageRU ru = new ImageRU(((RealType)imgPlusValue.getImgPlus().firstElement()).getMinValue()); - m_view.addRU(ru); - m_view.publishToPrev(new RendererSelectionChgEvent(new Real2GreyRenderer( - ((RealType)imgPlusValue.getImgPlus().firstElement()).getMinValue()))); - m_view.publishToPrev(new ImgWithMetadataChgEvent<>(imgPlusValue.getImgPlus(), - imgPlusValue.getMetadata())); + + if (imgPlusValue.getMetadata().numDimensions() <= 1) { + Img img2d = imgPlusValue.getImgPlus().getImg(); + ImgPlusMetadata meta = imgPlusValue.getMetadata(); + + img2d = ImgView.wrap(Views.addDimension(img2d, 0, 0), img2d.factory()); + meta = new DefaultImgMetadata(2); + ImageRU ru = new ImageRU(((RealType)img2d.firstElement()).getMinValue()); + m_view.addRU(ru); + m_view.publishToPrev(new RendererSelectionChgEvent( + new Real2GreyRenderer(((RealType)img2d.firstElement()).getMinValue()))); + m_view.publishToPrev(new ImgWithMetadataChgEvent<>(img2d, meta)); + + } else { + ImageRU ru = + new ImageRU(((RealType)imgPlusValue.getImgPlus().firstElement()).getMinValue()); + m_view.addRU(ru); + m_view.publishToPrev(new RendererSelectionChgEvent(new Real2GreyRenderer( + ((RealType)imgPlusValue.getImgPlus().firstElement()).getMinValue()))); + m_view.publishToPrev(new ImgWithMetadataChgEvent<>(imgPlusValue.getImgPlus(), + imgPlusValue.getMetadata())); + } } else if (v instanceof LabelingValue) { final LabelingValue labValue = (LabelingValue)v; @@ -189,7 +211,7 @@ public String getCellViewDescription() { } @Override - public int getPriority(){ + public int getPriority() { return Integer.MAX_VALUE; } diff --git a/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/CombinedImgViewer.java b/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/CombinedImgViewer.java index e872cb99..dab05dd8 100644 --- a/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/CombinedImgViewer.java +++ b/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/CombinedImgViewer.java @@ -195,6 +195,7 @@ public void addRU(final RenderUnit ru) { broadcast(new CombinedRUSynchEventClone(false)); m_ru.setStackedRendering(true); m_controlPanel.resetCheckboxes(); + m_tabbedMenu.setSelectedIndex(0); } public void clear() { @@ -250,6 +251,8 @@ public void onCombinedRUSynchChange(final CombinedRUSynchEvent e) { broadcast(new CombinedRUSynchEventClone(e)); if (!m_sync) { broadcast(new RebroadcastSelectionEvent()); + } else { + m_eventServices.get(m_tabbedMenu.getSelectedIndex()).publish(new RebroadcastSelectionEvent()); } } diff --git a/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/events/NormalizationParametersChgEvent.java b/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/events/NormalizationParametersChgEvent.java index 4876553b..6df6774d 100644 --- a/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/events/NormalizationParametersChgEvent.java +++ b/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/events/NormalizationParametersChgEvent.java @@ -159,10 +159,12 @@ public > double[] getNormalizationParameters(final RandomA final ValuePair oldMinMax = Operations.compute(new MinMaxWithSaturation(m_saturation, element), Views .iterable(Views.offsetInterval(Views.zeroMin(src), sel.getInterval(Views.zeroMin(src))))); - return new double[]{ + + double[] retVal = new double[]{ Normalize.normalizationFactor(oldMinMax.a.getRealDouble(), oldMinMax.b.getRealDouble(), element.getMinValue(), element.getMaxValue()), oldMinMax.a.getRealDouble()}; + return retVal; } } diff --git a/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/panels/providers/CombinedRU.java b/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/panels/providers/CombinedRU.java index e08bd160..3f4c1afb 100644 --- a/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/panels/providers/CombinedRU.java +++ b/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/panels/providers/CombinedRU.java @@ -62,7 +62,9 @@ import org.knime.knip.core.ui.event.EventService; import org.knime.knip.core.ui.imgviewer.events.TransparencyPanelValueChgEvent; import org.knime.knip.core.ui.imgviewer.panels.CombinedRUSynchEvent; +import org.knime.knip.core.util.MiscViews; +import net.imglib2.FinalInterval; import net.imglib2.Interval; /** @@ -150,10 +152,12 @@ public Image createImage() { int first = i; int w = 0, h = 0; Interval target = null; + if (m_sync) { - target = m_renderUnits.get(i).getInterval(); + target = calculateHull(); m_renderUnits.get(i).limitTo(target); } + Image img = m_renderUnits.get(i).createImage(); w += img.getWidth(null); h = Math.max(h, img.getHeight(null)); @@ -190,10 +194,12 @@ public Image createImage() { //at least one active image Interval target = null; + if (m_sync) { - target = m_renderUnits.get(i).getInterval(); + target = calculateHull(); m_renderUnits.get(i).limitTo(target); } + Image img = m_renderUnits.get(i).createImage(); joinedImg = m_graphicsConfig.createCompatibleImage(img.getWidth(null), img.getHeight(null), java.awt.Transparency.TRANSLUCENT); @@ -206,9 +212,11 @@ public Image createImage() { //blend in the other active images while (i < m_renderUnits.size()) { if (m_renderUnits.get(i).isActive()) { + if (m_sync) { m_renderUnits.get(i).limitTo(target); } + g.drawImage(Transparency.makeColorTransparent(m_renderUnits.get(i).createImage(), Color.WHITE, m_transparency), 0, 0, null); @@ -232,6 +240,21 @@ public Image createImage() { } + private Interval calculateHull() { + Interval result = new FinalInterval(); + for (RenderUnit ru : m_renderUnits) { + if (ru.isActive()) { + Interval target = ru.getInterval(); + if (result.numDimensions() > target.numDimensions()) { + result = MiscViews.synchronizeDimensionality(target, result); + } else { + result = MiscViews.synchronizeDimensionality(result, target); + } + } + } + return result; + } + /** * @return combined HashCode of all {@link RenderUnit}s. By contract that allows to identify images generated by * {@link #createImage()} including all parameters that have influence on the creation. diff --git a/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/panels/providers/ImageRU.java b/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/panels/providers/ImageRU.java index 8e8f78f8..0c5d74b1 100644 --- a/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/panels/providers/ImageRU.java +++ b/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/panels/providers/ImageRU.java @@ -63,12 +63,16 @@ import org.knime.knip.core.ui.imgviewer.events.ImgAndLabelingChgEvent; import org.knime.knip.core.ui.imgviewer.events.ImgWithMetadataChgEvent; import org.knime.knip.core.ui.imgviewer.events.NormalizationParametersChgEvent; +import org.knime.knip.core.ui.imgviewer.events.PlaneSelectionEvent; import org.knime.knip.core.ui.imgviewer.events.ViewClosedEvent; import org.knime.knip.core.ui.imgviewer.panels.transfunc.LookupTableChgEvent; +import org.knime.knip.core.util.MiscViews; +import net.imglib2.Interval; import net.imglib2.RandomAccessibleInterval; import net.imglib2.display.ColorTable; import net.imglib2.display.screenimage.awt.AWTScreenImage; +import net.imglib2.outofbounds.OutOfBoundsConstantValueFactory; import net.imglib2.type.numeric.ARGBType; import net.imglib2.type.numeric.RealType; import net.imglib2.view.Views; @@ -125,6 +129,9 @@ public int hashCode() { // event members + /** Caches the current restriction interval */ + private Interval m_interval; + private LookupTable m_lookupTable = new SimpleTable(); private NormalizationParametersChgEvent m_normalizationParameters = new NormalizationParametersChgEvent(0, false); @@ -133,11 +140,13 @@ public int hashCode() { private RandomAccessibleInterval m_src; + private RandomAccessibleInterval m_unmodSrc; + /** default constructor that creates a renderer selection dependent image {@link RenderUnit}. */ public ImageRU(final double min) { this(false); - this.m_greyRenderer = new Real2GreyRenderer(0.0); + } /** @@ -148,6 +157,7 @@ public ImageRU(final double min) { */ public ImageRU(final boolean enforceGreyScale) { m_enforceGreyScale = enforceGreyScale; + this.m_greyRenderer = new Real2GreyRenderer(0.0); } @SuppressWarnings("unchecked") @@ -156,13 +166,14 @@ public Image createImage() { if (m_lastImage != null && m_hashOfLastRendering == generateHashCode()) { return m_lastImage; } - + PlaneSelectionEvent pSel = m_planeSelection; + if(m_interval != null && m_planeSelection.numDimensions() != m_interval.numDimensions()) { + pSel = MiscViews.adjustPlaneSelection(m_planeSelection, m_interval); + } //+ allows normalization - breaks type safety @SuppressWarnings("rawtypes") RandomAccessibleInterval convertedSrc = AWTImageProvider.convertIfDouble(m_src); - final double[] normParams = - m_normalizationParameters.getNormalizationParameters(convertedSrc, m_planeSelection); - + final double[] normParams = m_normalizationParameters.getNormalizationParameters(convertedSrc, pSel); //set parameters of the renderer if (m_renderer instanceof RendererWithNormalization) { ((RendererWithNormalization)m_renderer).setNormalizationParameters(normParams[0], normParams[1]); @@ -178,12 +189,12 @@ public Image createImage() { final AWTScreenImage ret; if (!m_enforceGreyScale) { - ret = m_renderer.render(Views.zeroMin(convertedSrc), m_planeSelection.getPlaneDimIndex1(), - m_planeSelection.getPlaneDimIndex2(), m_planeSelection.getPlanePos()); + ret = m_renderer.render(Views.zeroMin(convertedSrc), pSel.getPlaneDimIndex1(), + pSel.getPlaneDimIndex2(), pSel.getPlanePos()); } else { m_greyRenderer.setNormalizationParameters(normParams[0], normParams[1]); - ret = m_greyRenderer.render(Views.zeroMin(convertedSrc), m_planeSelection.getPlaneDimIndex1(), - m_planeSelection.getPlaneDimIndex2(), m_planeSelection.getPlanePos()); + ret = m_greyRenderer.render(Views.zeroMin(convertedSrc), pSel.getPlaneDimIndex1(), + pSel.getPlaneDimIndex2(), pSel.getPlanePos()); } m_lastImage = ret.image(); @@ -213,6 +224,31 @@ public boolean isActive() { return (m_src != null); } + @Override + public void limitTo(final Interval interval) { + if (!interval.equals(m_interval)) { + T val = m_src.randomAccess().get().createVariable(); + val.setReal(val.getMinValue()); + OutOfBoundsConstantValueFactory> fac = + new OutOfBoundsConstantValueFactory<>(val); + m_interval = interval; + m_src = Views.interval(MiscViews.synchronizeDimensionality(m_unmodSrc, interval, fac), interval); + m_hashOfLastRendering = -1; + } + } + + @Override + public void resetLimit() { + m_interval = null; + m_src = m_unmodSrc; + m_hashOfLastRendering = -1; + } + + @Override + public Interval getInterval() { + return m_src; + } + //event handling /** @@ -244,6 +280,7 @@ public void onLookupTableChgEvent(final LookupTableChgEvent event) @EventListener public void onImageUpdated(final ImgWithMetadataChgEvent e) { m_src = e.getRandomAccessibleInterval(); + m_unmodSrc = e.getRandomAccessibleInterval(); final int size = e.getImgMetaData().getColorTableCount(); m_colorTables = new ColorTable[size]; @@ -261,6 +298,7 @@ public void onImageUpdated(final ImgWithMetadataChgEvent e) { @EventListener public void onImageUpdated(final ImgAndLabelingChgEvent e) { m_src = e.getRandomAccessibleInterval(); + m_unmodSrc = e.getRandomAccessibleInterval(); } /** diff --git a/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/panels/providers/LabelingRU.java b/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/panels/providers/LabelingRU.java index efcc1696..5472b3a6 100644 --- a/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/panels/providers/LabelingRU.java +++ b/org.knime.knip.core/src/org/knime/knip/core/ui/imgviewer/panels/providers/LabelingRU.java @@ -68,12 +68,15 @@ import org.knime.knip.core.ui.imgviewer.events.LabelPanelIsHiliteModeEvent; import org.knime.knip.core.ui.imgviewer.events.LabelPanelVisibleLabelsChgEvent; import org.knime.knip.core.ui.imgviewer.events.LabelingWithMetadataChgEvent; +import org.knime.knip.core.ui.imgviewer.events.PlaneSelectionEvent; import org.knime.knip.core.ui.imgviewer.events.RulebasedLabelFilter.Operator; import org.knime.knip.core.ui.imgviewer.events.ViewClosedEvent; +import org.knime.knip.core.util.MiscViews; import net.imglib2.Interval; import net.imglib2.RandomAccessibleInterval; import net.imglib2.display.screenimage.awt.AWTScreenImage; +import net.imglib2.outofbounds.OutOfBoundsConstantValueFactory; import net.imglib2.roi.labeling.LabelingType; import net.imglib2.view.Views; @@ -134,6 +137,11 @@ public Image createImage() { return m_lastImage; } + PlaneSelectionEvent pSel = m_planeSelection; + if(m_interval != null && m_planeSelection.numDimensions() != m_interval.numDimensions()) { + pSel = MiscViews.adjustPlaneSelection(m_planeSelection, m_interval); + } + if (m_renderer instanceof RendererWithLabels) { @SuppressWarnings("unchecked") final RendererWithLabels r = (RendererWithLabels)m_renderer; @@ -155,8 +163,8 @@ public Image createImage() { } final AWTScreenImage ret = - m_renderer.render(m_src, m_planeSelection.getPlaneDimIndex1(), m_planeSelection.getPlaneDimIndex2(), - m_planeSelection.getPlanePos()); + m_renderer.render(m_src, pSel.getPlaneDimIndex1(), pSel.getPlaneDimIndex2(), + pSel.getPlanePos()); m_hashOfLastRendering = generateHashCode(); m_lastImage = ret.image(); @@ -169,8 +177,11 @@ public void limitTo(final Interval interval) { if (!interval.equals(m_interval)) { LabelingType val = m_src.randomAccess().get().createVariable(); val.clear(); + OutOfBoundsConstantValueFactory, RandomAccessibleInterval>> fac = + new OutOfBoundsConstantValueFactory<>(val); m_interval = interval; - m_src = Views.interval(Views.extendValue(m_unmodSrc, val), interval); + m_src = Views.interval(MiscViews.synchronizeDimensionality(m_unmodSrc, interval, fac), interval); + m_hashOfLastRendering = -1; } }