/*-
* #%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.cuda;
import java.util.ArrayList;
import net.imglib2.iterator.LocalizingZeroMinIntervalIterator;
import net.imglib2.util.Util;
/**
* This BlockGenerator only cares that the overlap within the image is accounted for, not about
* an outofbounds strategy.
*
* @author Stephan Preibisch
*/
public class BlockGeneratorVariableSizeSimple implements BlockGenerator< Block >
{
final long[] numBlocks;
public BlockGeneratorVariableSizeSimple( final long[] numBlocksDim )
{
this.numBlocks = numBlocksDim;
}
/**
* Divides an image into blocks
*
* @param imgSize - the size of the image
* @param kernelSize - the size of the kernel (has to be odd!)
* @return
*/
public Block[] divideIntoBlocks( final long[] imgSize, final long[] kernelSize )
{
final int numDimensions = imgSize.length;
// compute the effective size & local offset of each block
// this is the same for all blocks
/*
final int[] effectiveSizeGeneral = new int[ numDimensions ];
final int[] effectiveLocalOffset = new int[ numDimensions ];
for ( int d = 0; d < numDimensions; ++d )
{
effectiveSizeGeneral[ d ] = blockSize[ d ] - kernelSize[ d ] + 1;
if ( effectiveSizeGeneral[ d ] <= 0 )
{
System.out.println( "Blocksize in dimension " + d + " (" + blockSize[ d ] + ") is smaller than the kernel (" + kernelSize[ d ] + ") which results in an negative effective size: " + effectiveSizeGeneral[ d ] + ". Quitting." );
return null;
}
effectiveLocalOffset[ d ] = kernelSize[ d ] / 2;
}
// compute the amount of blocks needed
final int[] numBlocks = new int[ numDimensions ];
for ( int d = 0; d < numDimensions; ++d )
{
numBlocks[ d ] = imgSize[ d ] / effectiveSizeGeneral[ d ];
// if the modulo is not 0 we need one more that is only partially useful
if ( imgSize[ d ] % effectiveSizeGeneral[ d ] != 0 )
++numBlocks[ d ];
}
*/
// now we instantiate the individual blocks iterating over all dimensions
// we use the well-known ArrayLocalizableCursor for that
final LocalizingZeroMinIntervalIterator cursor = new LocalizingZeroMinIntervalIterator( numBlocks );
final ArrayList< Block > blockList = new ArrayList< Block >();
final long[] currentBlock = new long[ numDimensions ];
while ( cursor.hasNext() )
{
cursor.fwd();
cursor.localize( currentBlock );
// the blocksize
final long[] blockSize = new long[ numDimensions ];
// compute the current offset
final long[] offset = new long[ numDimensions ];
final long[] effectiveOffset = new long[ numDimensions ];
final long[] effectiveSize = new long[ numDimensions ];
final long[] effectiveLocalOffset = new long[ numDimensions ];
for ( int d = 0; d < numDimensions; ++d )
{
if ( numBlocks[ d ] == 1 ) // is there only one block?
{
effectiveLocalOffset[ d ] = offset[ d ] = effectiveOffset[ d ] = 0;
blockSize[ d ] = effectiveSize[ d ] = imgSize[ d ];
}
else if ( currentBlock[ d ] == 0 ) // is the first block?
{
effectiveLocalOffset[ d ] = offset[ d ] = effectiveOffset[ d ] = 0;
effectiveSize[ d ] = imgSize[ d ] / numBlocks[ d ];
blockSize[ d ] = effectiveSize[ d ] + kernelSize[ d ]/2;
}
else if ( currentBlock[ d ] < numBlocks[ d ] - 1 ) // it is some block in the middle
{
effectiveLocalOffset[ d ] = kernelSize[ d ] / 2;
effectiveSize[ d ] = imgSize[ d ] / numBlocks[ d ];
blockSize[ d ] = effectiveSize[ d ] + kernelSize[ d ] - 1;
effectiveOffset[ d ] = currentBlock[ d ] * effectiveSize[ d ];
offset[ d ] = effectiveOffset[ d ] - kernelSize[ d ]/2;
}
else // is the last block?
{
effectiveLocalOffset[ d ] = kernelSize[ d ] / 2;
effectiveSize[ d ] = imgSize[ d ] / numBlocks[ d ] + imgSize[ d ] % numBlocks[ d ];
blockSize[ d ] = effectiveSize[ d ] + kernelSize[ d ]/2;
effectiveOffset[ d ] = currentBlock[ d ] * effectiveSize[ d ];
offset[ d ] = effectiveOffset[ d ] - kernelSize[ d ]/2;
}
if ( effectiveSize[ d ] <= 0 )
{
System.out.println( "Blocksize in dimension " + d + " (" + blockSize[ d ] + ") is smaller than the kernel (" + kernelSize[ d ] + ") which results in an negative effective size: " + effectiveSize[ d ] + ". Quitting." );
return null;
}
}
blockList.add( new Block( blockSize, offset, effectiveSize, effectiveOffset, effectiveLocalOffset, false ) );
System.out.println( "block " + Util.printCoordinates( currentBlock ) + " offset: " + Util.printCoordinates( offset ) + " effectiveOffset: " + Util.printCoordinates( effectiveOffset ) + " effectiveLocalOffset: " + Util.printCoordinates( effectiveLocalOffset ) + " effectiveSize: " + Util.printCoordinates( effectiveSize ) + " blocksize: " + Util.printCoordinates( blockSize ) );
}
final Block[] blocks = new Block[ blockList.size() ];
for ( int i = 0; i < blockList.size(); ++i )
blocks[ i ] = blockList.get( i );
return blocks;
}
public static void main( String[] args )
{
new BlockGeneratorVariableSizeSimple( new long[]{ 3, 2, 1 } ).divideIntoBlocks( new long[] { 1025, 1024, 117 }, new long[]{ 17, 17, 4 } );
}
}