Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MaskedSource #607

Draft
wants to merge 30 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3610c16
Init CroppedViewCommand
tischi Feb 18, 2022
1bdf0cb
Add more code
tischi Feb 18, 2022
aac23a4
WIP FunctionRealRandomAccessible...
tischi Feb 18, 2022
4dd15ae
Implement crop
tischi Feb 19, 2022
5163455
Cropping works using mask
tischi Feb 19, 2022
cd15862
Make MaskedSource serialisable
tischi Feb 19, 2022
5a70be6
Make masked sources work with manual transformations
tischi Feb 19, 2022
cfd8c79
Add crop to source
tischi Feb 19, 2022
1a11971
Remove center parameter
tischi Feb 19, 2022
b11c7eb
Get MoBIE instance in Command
tischi Feb 19, 2022
002ce44
Get MoBIE instance in Command
tischi Feb 19, 2022
ff0e687
merge
tischi Feb 21, 2022
dffc0a3
Add crop to view and UI
tischi Feb 21, 2022
82248e2
WIP replace Resampled Source?|
tischi Feb 21, 2022
c2209d2
Successfully create a view for a cropped source
tischi Feb 21, 2022
fc12d68
Minor fix
tischi Feb 21, 2022
38f6968
Implement proper bounding box for crop
tischi Feb 22, 2022
60e8720
Improve MaskedSource
tischi Feb 22, 2022
baecaba
Improve...
tischi Feb 23, 2022
2909d94
merge develop
tischi Feb 23, 2022
edabbdf
Add option to center and rectify the crop
tischi Feb 24, 2022
bd2646d
new crop spec
tischi Feb 24, 2022
eeb028a
something
tischi Feb 25, 2022
ee0f128
Refactor
tischi Feb 25, 2022
997615a
Merge branch 'develop' into crop
tischi Feb 25, 2022
da2e157
Make BigWarp work better
tischi Feb 25, 2022
7b97128
Put back stuff that was actually working
tischi Feb 25, 2022
2450e79
Refactor
tischi Mar 1, 2022
c976040
Add MoBIEViewerTransformAdjuster
tischi Mar 3, 2022
de90930
Refactor
tischi Mar 4, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
<!-- EMBL CBA -->
<imagej-utils.version>0.6.4</imagej-utils.version>

<mobie-io.version>1.2.2</mobie-io.version>
<mobie-io.version>1.2.3</mobie-io.version>

<!-- Version 1.6.0-scijava-3-SNAPSHOT of j3dcore addresses a minor issue
https://github.com/fiji/3D_Viewer/issues/26
Expand Down
15 changes: 14 additions & 1 deletion src/main/java/org/embl/mobie/viewer/MoBIE.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.embl.mobie.viewer;

import bdv.img.n5.N5ImageLoader;
import bdv.util.BdvHandle;
import bdv.viewer.Source;
import bdv.viewer.SourceAndConverter;
import de.embl.cba.bdv.utils.Logger;
Expand Down Expand Up @@ -47,7 +48,7 @@ public class MoBIE
{
static { net.imagej.patcher.LegacyInjector.preinit(); }

public static final String PROTOTYPE_DISPLAY_VALUE = "01234567890123456789";
private static ConcurrentHashMap< Object, MoBIE > objectToMoBIE = new ConcurrentHashMap<>();;

private final String projectName;
private MoBIESettings settings;
Expand All @@ -63,13 +64,15 @@ public class MoBIE
private Map< String, SourceAndConverter< ? > > sourceNameToTransformedSourceAndConverter;
private ArrayList< String > projectCommands = new ArrayList<>();;


public MoBIE( String projectRoot ) throws IOException
{
this( projectRoot, MoBIESettings.settings() );
}

public MoBIE( String projectLocation, MoBIESettings settings ) throws IOException
{

IJ.log("MoBIE");
this.settings = settings.projectLocation( projectLocation );
setS3Credentials( settings );
Expand Down Expand Up @@ -647,4 +650,14 @@ public ArrayList< String > getProjectCommands()
{
return projectCommands;
}

public void register( Object object )
{
MoBIE.objectToMoBIE.put( object, this );
}

public static MoBIE getInstance( Object object )
{
return MoBIE.objectToMoBIE.get( object );
}
}
2 changes: 1 addition & 1 deletion src/main/java/org/embl/mobie/viewer/MoBIEUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ public static AffineTransform3D createNormalisedViewerTransform( BdvHandle bdv,
view.preConcatenate( translate.inverse() );

// divide by window width
final int bdvWindowWidth = BdvUtils.getBdvWindowWidth( bdv );
final int bdvWindowWidth = bdv.getBdvHandle().getViewerPanel().getDisplay().getWidth();
final Scale3D scale = new Scale3D( 1.0 / bdvWindowWidth, 1.0 / bdvWindowWidth, 1.0 / bdvWindowWidth );
view.preConcatenate( scale );

Expand Down
176 changes: 176 additions & 0 deletions src/main/java/org/embl/mobie/viewer/bdv/BdvBoundingBoxDialog.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*-
* #%L
* Fiji plugin for inspection and processing of big image data
* %%
* Copyright (C) 2018 - 2021 EMBL
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.embl.mobie.viewer.bdv;

import bdv.tools.boundingbox.BoxSelectionOptions;
import bdv.tools.boundingbox.TransformedRealBoxSelectionDialog;
import bdv.util.Affine3DHelpers;
import bdv.util.Bdv;
import bdv.util.BdvFunctions;
import bdv.util.BdvHandle;
import bdv.viewer.SourceAndConverter;
import net.imglib2.FinalInterval;
import net.imglib2.FinalRealInterval;
import net.imglib2.Interval;
import net.imglib2.RealInterval;
import net.imglib2.realtransform.AffineTransform3D;
import net.imglib2.realtransform.Scale3D;
import net.imglib2.util.Intervals;

import java.util.List;

public class BdvBoundingBoxDialog
{
private BdvHandle bdvHandle;
private final List< SourceAndConverter > sourceAndConverters;

private FinalRealInterval initialInterval;
private FinalRealInterval rangeInterval;
private RealInterval interval;
private int minTimepoint;
private int maxTimepoint;
private AffineTransform3D boxTransform;
private TransformedRealBoxSelectionDialog.Result result;

public BdvBoundingBoxDialog( BdvHandle bdvHandle, List< SourceAndConverter > sourceAndConverters )
{
this.bdvHandle = bdvHandle;
this.sourceAndConverters = sourceAndConverters;

// viewer transform: physical to screen (0,0,w,h)
this.boxTransform = bdvHandle.getViewerPanel().state().getViewerTransform();

// physical to screen with (-w/2,-h/2,w/2,h/2)
boxTransform.translate( -0.5 * bdvHandle.getViewerPanel().getDisplay().getWidth(), -0.5 * bdvHandle.getViewerPanel().getDisplay().getHeight(), 0 );

// remove bdv window scale from transform
// note that the scale of the viewer transform is uniform in 3-D
// thus we can just pick either width or height
final double scale = 1.0 / bdvHandle.getViewerPanel().getDisplay().getWidth();
final Scale3D scale3D = new Scale3D( scale, scale, scale );
boxTransform.preConcatenate( scale3D );

// inverse: box to physical
boxTransform = boxTransform.inverse();

// check that it is correct (just for debugging)
final double[] center = { 0, 0, 0 };
final double[] left = { -0.5, -0.5, -0.5 };
final double[] right = { 0.5, 0.5, 0.5 };
final double[] physicalLeft = { 0, 0, 0 };
final double[] physicalRight = { 0, 0, 0 };
final double[] physicalCenter = { 0, 0, 0 };
boxTransform.apply( left, physicalLeft );
boxTransform.apply( right, physicalRight );
boxTransform.apply( center, physicalCenter );
}

public void showDialog()
{
setInitialSelectionAndRange();
result = showRealBox( boxTransform );
}

public TransformedRealBoxSelectionDialog.Result getResult()
{
return result;
}

private TransformedRealBoxSelectionDialog.Result showRealBox( AffineTransform3D boxTransform )
{
return BdvFunctions.selectRealBox(
bdvHandle,
boxTransform,
initialInterval,
rangeInterval,
BoxSelectionOptions.options()
.title( "Crop" )
.initialTimepointRange( bdvHandle.getViewerPanel().state().getCurrentTimepoint(), bdvHandle.getViewerPanel().state().getCurrentTimepoint() )
.selectTimepointRange( 0, bdvHandle.getViewerPanel().state().getNumTimepoints() - 1 )
);
}

private void setInitialSelectionAndRange( )
{
final FinalRealInterval viewerBoundingInterval = getViewerGlobalBoundingInterval( bdvHandle );

double[] initialCenter = new double[ 3 ];
double[] initialSize = new double[ 3 ];

for (int d = 0; d < 3; d++)
{
initialCenter[ d ] = ( viewerBoundingInterval.realMax( d ) + viewerBoundingInterval.realMin( d ) ) / 2.0;
initialSize[ d ] = ( viewerBoundingInterval.realMax( d ) - viewerBoundingInterval.realMin( d ) );
}

initialSize[ 2 ] = 10.0;

double[] minInitial = new double[ 3 ];
double[] maxInitial = new double[ 3 ];
double[] minRange = new double[ 3 ];
double[] maxRange = new double[ 3 ];

for ( int d = 0; d < 3; d++ )
{
minInitial[ d ] = initialCenter[ d ] - initialSize[ d ] / 4;
maxInitial[ d ] = initialCenter[ d ] + initialSize[ d ] / 4;
minRange[ d ] = initialCenter[ d ] - initialSize[ d ] / 2;
maxRange[ d ] = initialCenter[ d ] + initialSize[ d ] / 2;
}

// initialInterval = Intervals.createMinMax(
// (long) minInitial[0], (long) minInitial[1], (long) minInitial[2],
// (long) maxInitial[0], (long) maxInitial[1], (long) maxInitial[2]);

// rangeInterval = Intervals.createMinMax(
// (long) minRange[0], (long) minRange[1], (long) minRange[2],
// (long) maxRange[0], (long) maxRange[1], (long) maxRange[2]);

initialInterval = new FinalRealInterval(
new double[]{-0.25,-0.25,-0.25},
new double[]{+0.25,+0.25,+0.25});
rangeInterval = new FinalRealInterval(
new double[]{-0.5,-0.5,-0.5},
new double[]{+0.5,+0.5,+0.5});
}

private static FinalRealInterval getViewerGlobalBoundingInterval( Bdv bdv )
{
AffineTransform3D viewerTransform = new AffineTransform3D();
bdv.getBdvHandle().getViewerPanel().state().getViewerTransform( viewerTransform );
viewerTransform = viewerTransform.inverse();
final long[] min = new long[ 3 ];
final long[] max = new long[ 3 ];
max[ 0 ] = bdv.getBdvHandle().getViewerPanel().getWidth();
max[ 1 ] = bdv.getBdvHandle().getViewerPanel().getHeight();
final FinalRealInterval realInterval
= viewerTransform.estimateBounds( new FinalInterval( min, max ) );
return realInterval;
}
}
2 changes: 2 additions & 0 deletions src/main/java/org/embl/mobie/viewer/bdv/view/SliceViewer.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.embl.mobie.viewer.bdv.MobieSerializableBdvOptions;
import org.embl.mobie.viewer.bdv.SourcesAtMousePositionSupplier;
import org.embl.mobie.viewer.bdv.ViewerTransformLogger;
import org.embl.mobie.viewer.command.CropSourcesCommand;
import org.embl.mobie.viewer.command.ImagePlusExportCommand;
import org.embl.mobie.viewer.command.ManualRegistrationCommand;
import org.embl.mobie.viewer.command.BigWarpRegistrationCommand;
Expand Down Expand Up @@ -106,6 +107,7 @@ private void installContextMenuAndKeyboardShortCuts( )
actions.add( sacService.getCommandName( ScreenShotMakerCommand.class ) );
actions.add( sacService.getCommandName( ImagePlusExportCommand.class ) );
actions.add( sacService.getCommandName( ViewerTransformLogger.class ) );
actions.add( sacService.getCommandName( CropSourcesCommand.class ) );
actions.add( sacService.getCommandName( BigWarpRegistrationCommand.class ) );
actions.add( sacService.getCommandName( ManualRegistrationCommand.class ) );
actions.add( sacService.getCommandName( SourceAndConverterBlendingModeChangerCommand.class ) );
Expand Down
105 changes: 105 additions & 0 deletions src/main/java/org/embl/mobie/viewer/command/CropSourcesCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package org.embl.mobie.viewer.command;

import bdv.tools.boundingbox.TransformedRealBoxSelectionDialog;
import bdv.tools.transformation.TransformedSource;
import bdv.util.BdvFunctions;
import bdv.util.BdvHandle;
import bdv.util.BdvOptions;
import bdv.viewer.SourceAndConverter;
import net.imagej.patcher.LegacyInjector;
import net.imglib2.RealInterval;
import net.imglib2.realtransform.AffineTransform3D;
import org.embl.mobie.viewer.MoBIE;
import org.embl.mobie.viewer.bdv.BdvBoundingBoxDialog;
import org.embl.mobie.viewer.playground.SourceAffineTransformer;
import org.embl.mobie.viewer.transform.MaskedSource;
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;
import sc.fiji.bdvpg.scijava.command.BdvPlaygroundActionCommand;
import sc.fiji.bdvpg.sourceandconverter.SourceAndConverterHelper;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@Plugin(type = BdvPlaygroundActionCommand.class, menuPath = CommandConstants.CONTEXT_MENU_ITEMS_ROOT + CropSourcesCommand.NAME )
public class CropSourcesCommand implements BdvPlaygroundActionCommand
{
static{ LegacyInjector.preinit(); }

public static final String NAME = "Crop Source(s)";

@Parameter( label = "Bdv" )
BdvHandle bdvHandle;

@Parameter( label = "Source(s)" )
public SourceAndConverter[] sourceAndConverterArray;

@Parameter( label = "Suffix" )
public String suffix = "_crop";

@Parameter( label = "Add to current view" )
public boolean addToCurrentView = true;

@Override
public void run()
{
final List< SourceAndConverter > sourceAndConverters = Arrays.stream( sourceAndConverterArray ).collect( Collectors.toList() );
if ( sourceAndConverters.size() == 0 ) return;

new Thread( () -> {
final BdvBoundingBoxDialog boxDialog = new BdvBoundingBoxDialog( bdvHandle, sourceAndConverters );
boxDialog.showDialog();
final TransformedRealBoxSelectionDialog.Result result = boxDialog.getResult();
if ( ! result.isValid() ) return;
final RealInterval maskInterval = result.getInterval();
final AffineTransform3D maskTransform = new AffineTransform3D();
result.getTransform( maskTransform );

for ( SourceAndConverter sourceAndConverter : sourceAndConverters )
{
final SourceAndConverter cropSource = cropSource( maskInterval, maskTransform, sourceAndConverter );

// TODO: can we create a view for this?
final MoBIE moBIE = MoBIE.getInstance( bdvHandle );
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@K-Meech Do you have experience here and could help? The point is to somehow create and register a new view for the cropSource (actually this is a MaskedSource, need to change names later, maybe).

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think you would need to create the relevant SourceTransformer by getting the min/max of the crop etc from the Source. Then somehow add it to the the currentSourceTransformers in the ViewManager. Then, when you save the current settings as a view, it will be made into a view when this function is called: https://github.com/mobie/mobie-viewer-fiji/blob/develop/src/main/java/org/embl/mobie/viewer/view/ViewManager.java#L208

moBIE.getViewManager(); // ....

if ( addToCurrentView )
{
// TODO: how to do this properly?
BdvFunctions.show( cropSource, BdvOptions.options().addTo( bdvHandle ) );
}

// TODO: Add to UI (maybe simply to same UI group as the input source)


}
}).start();
}

private SourceAndConverter cropSource( RealInterval maskInterval, AffineTransform3D maskTransform, SourceAndConverter sourceAndConverter )
{
final MaskedSource maskedSource = new MaskedSource<>( sourceAndConverter.getSpimSource(), sourceAndConverter.getSpimSource().getName() + suffix, maskInterval.minAsDoubleArray(), maskInterval.maxAsDoubleArray(), maskTransform );

final MaskedSource volatileMaskedSource = new MaskedSource<>( sourceAndConverter.asVolatile().getSpimSource(), sourceAndConverter.getSpimSource().getName() + suffix, maskInterval.minAsDoubleArray(), maskInterval.maxAsDoubleArray(), maskTransform );

final SourceAndConverter maskedSourceAndConverter = new SourceAndConverter( maskedSource, SourceAndConverterHelper.cloneConverter( sourceAndConverter.getConverter(), sourceAndConverter ), new SourceAndConverter( volatileMaskedSource, SourceAndConverterHelper.cloneConverter( sourceAndConverter.asVolatile().getConverter(), sourceAndConverter.asVolatile() ) ) );

// Wrap into TransformedSource for, e.g., manual transformation
final SourceAndConverter sourceOut = new SourceAffineTransformer( maskedSourceAndConverter, new AffineTransform3D() ).getSourceOut();
return sourceOut;
}

private HashMap< SourceAndConverter< ? >, AffineTransform3D > fetchTransforms( List< SourceAndConverter< ? > > sourceAndConverters )
{
final HashMap< SourceAndConverter< ? >, AffineTransform3D > sacToTransform = new HashMap<>();
for ( SourceAndConverter movingSac : sourceAndConverters )
{
final AffineTransform3D fixedTransform = new AffineTransform3D();
( ( TransformedSource ) movingSac.getSpimSource()).getFixedTransform( fixedTransform );
sacToTransform.put( movingSac, fixedTransform );
}
return sacToTransform;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.embl.mobie.viewer.command;

import bdv.tools.transformation.TransformedSource;
import bdv.util.Affine3DHelpers;
import bdv.viewer.Source;
import bdv.viewer.SourceAndConverter;
Expand Down Expand Up @@ -177,15 +176,4 @@ private RandomAccessibleInterval< T > getRAIXYZT( Source< T > source, int level,
return Views.stack( rais );
}

private HashMap< SourceAndConverter< T >, AffineTransform3D > fetchTransforms( List< SourceAndConverter< T > > movingSacs )
{
final HashMap< SourceAndConverter< T >, AffineTransform3D > sacToTransform = new HashMap<>();
for ( SourceAndConverter movingSac : movingSacs )
{
final AffineTransform3D fixedTransform = new AffineTransform3D();
( ( TransformedSource ) movingSac.getSpimSource()).getFixedTransform( fixedTransform );
sacToTransform.put( movingSac, fixedTransform );
}
return sacToTransform;
}
}
Loading