/*-
* #%L
* Fiji distribution of ImageJ for the life sciences.
* %%
* Copyright (C) 2007 - 2017 Fiji developers.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-2.0.html>.
* #L%
*/
package spim.process.interestpointdetection;
import ij.ImageJ;
import java.util.ArrayList;
import java.util.Vector;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import mpicbg.spim.io.IOFunctions;
import net.imglib2.Cursor;
import net.imglib2.RandomAccess;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.img.Img;
import net.imglib2.img.ImgFactory;
import net.imglib2.img.array.ArrayImgFactory;
import net.imglib2.img.display.imagej.ImageJFunctions;
import net.imglib2.iterator.IntervalIterator;
import net.imglib2.iterator.ZeroMinIntervalIterator;
import net.imglib2.type.numeric.RealType;
import net.imglib2.type.numeric.real.FloatType;
import net.imglib2.view.Views;
import spim.Threads;
import spim.process.fusion.FusionHelper;
import spim.process.fusion.ImagePortion;
public class Downsample
{
public static < T extends RealType< T > > RandomAccessibleInterval< T > simple2x( final RandomAccessibleInterval<T> input, final ImgFactory< T > imgFactory )
{
final boolean[] downsampleInDim = new boolean[ input.numDimensions() ];
for ( int d = 0; d < downsampleInDim.length; ++d )
downsampleInDim[ d ] = true;
return simple2x( input, imgFactory, downsampleInDim );
}
public static < T extends RealType< T > > RandomAccessibleInterval< T > simple2x( final RandomAccessibleInterval<T> input, final ImgFactory< T > imgFactory, final boolean[] downsampleInDim )
{
RandomAccessibleInterval< T > src = input;
for ( int d = 0; d < input.numDimensions(); ++d )
if ( downsampleInDim[ d ] )
{
final long dim[] = new long[ input.numDimensions() ];
for ( int e = 0; e < input.numDimensions(); ++e )
{
if ( e == d )
dim[ e ] = src.dimension( e ) / 2;
else
dim[ e ] = src.dimension( e );
}
final Img< T > img = imgFactory.create( dim, Views.iterable( input ).firstElement() );
simple2x( src, img, d );
src = img;
}
return src;
}
public static < T extends RealType< T > > void simple2x( final RandomAccessibleInterval<T> input, final RandomAccessibleInterval<T> output, final int d )
{
final int n = input.numDimensions();
// iterate all dimensions but the one we are processing int
final long[] iterateD = new long[ n ];
long numLines = 1;
for ( int e = 0; e < n; ++e )
{
if ( e == d )
iterateD[ e ] = 1;
else
iterateD[ e ] = output.dimension( e );
numLines *= iterateD[ e ];
}
//final IterableInterval< T > iterable = new ZeroMinIntervalIterator( iterateD );
//Views.iterable( Views.hyperSlice( Views.zeroMin( output ), d, 0 ) );
// split up into many parts for multithreading
final Vector< ImagePortion > portions = FusionHelper.divideIntoPortions( numLines, Threads.numThreads() * 2 );
// set up executor service
final ExecutorService taskExecutor = Executors.newFixedThreadPool( Threads.numThreads() );
final ArrayList< Callable< Void > > tasks = new ArrayList< Callable< Void > >();
for ( final ImagePortion portion : portions )
{
tasks.add( new Callable< Void >()
{
@Override
public Void call() throws Exception
{
final long[] pos = new long[ n ];
final IntervalIterator cursorDim = new ZeroMinIntervalIterator( iterateD );
final RandomAccess< T > in = Views.zeroMin( input ).randomAccess();
final RandomAccess< T > out = Views.zeroMin( output ).randomAccess();
final long size = output.dimension( d ) - 1;
cursorDim.jumpFwd( portion.getStartPosition() );
for ( long j = 0; j < portion.getLoopSize(); ++j )
{
cursorDim.fwd();
cursorDim.localize( pos );
out.setPosition( pos );
// the first pixel (avoid outofbounds)
in.setPosition( pos );
double v0, v1, v2;
v1 = in.get().getRealDouble();
in.fwd( d );
v0 = v2 = in.get().getRealDouble();
out.get().setReal( ( v1 + v2 * 0.5 ) / 1.5 );
// other pixels
for ( int p = 1; p < size; ++p )
{
v0 = v2;
in.fwd( d );
v1 = in.get().getRealDouble();
in.fwd( d );
v2 = in.get().getRealDouble();
out.fwd( d );
out.get().setReal( ( v0 * 0.5 + v1 + v2 * 0.5 ) / 2.0 );
}
// last pixel
in.fwd( d );
v1 = in.get().getRealDouble();
out.fwd( d );
out.get().setReal( ( v1 + v2 * 0.5 ) / 1.5 );
}
return null;
}
});
}
try
{
// invokeAll() returns when all tasks are complete
taskExecutor.invokeAll( tasks );
}
catch ( final InterruptedException e )
{
IOFunctions.println( "Failed to compute downsampling: " + e );
e.printStackTrace();
return;
}
taskExecutor.shutdown();
return;
}
public static void main( String[] args )
{
final Img< FloatType > img;
//img = OpenImg.open( "/Users/preibischs/Documents/Microscopy/SPIM/HisYFP-SPIM/img_Angle0.tif", new ArrayImgFactory< FloatType >() );
img = new ArrayImgFactory< FloatType >().create( new long[]{ 515, 231, 15 }, new FloatType() );
final Cursor< FloatType > c = img.localizingCursor();
while ( c.hasNext() )
{
c.next().set( c.getIntPosition( 0 ) % 10 + c.getIntPosition( 1 ) % 13 + c.getIntPosition( 2 ) % 3 );
}
new ImageJ();
ImageJFunctions.show( img );
ImageJFunctions.show( simple2x( img, img.factory(), new boolean[]{ true, true, true } ) );
}
}