net.imglib2.util.Util Maven / Gradle / Ivy
Show all versions of imglib2 Show documentation
/*
* #%L
* ImgLib2: a general-purpose, multidimensional image processing library.
* %%
* Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld,
* John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke,
* Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner,
* Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert,
* Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin,
* Jean-Yves Tinevez and Michael Zinsmaier.
* %%
* 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 net.imglib2.util;
import net.imglib2.Dimensions;
import net.imglib2.Interval;
import net.imglib2.IterableInterval;
import net.imglib2.Localizable;
import net.imglib2.RandomAccessible;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.RealInterval;
import net.imglib2.RealLocalizable;
import net.imglib2.RealRandomAccessible;
import net.imglib2.exception.IncompatibleTypeException;
import net.imglib2.img.Img;
import net.imglib2.img.ImgFactory;
import net.imglib2.img.array.ArrayImg;
import net.imglib2.img.array.ArrayImgFactory;
import net.imglib2.img.cell.CellImgFactory;
import net.imglib2.img.list.ListImgFactory;
import net.imglib2.type.NativeType;
import net.imglib2.type.Type;
import net.imglib2.type.numeric.RealType;
import net.imglib2.type.operators.ValueEquals;
import net.imglib2.view.Views;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiPredicate;
import java.util.stream.StreamSupport;
/**
* A collection of general-purpose utility methods for working with ImgLib2 data
* structures.
*
* @author Stephan Preibisch
* @author Stephan Saalfeld
* @author Curtis Rueden
* @author Philipp Hanslovsky
*/
public class Util
{
/**
* The possible java array size is JVM dependent an actually
* slightly below Integer.MAX_VALUE. This is the same MAX_ARRAY_SIZE
* as used for example in ArrayList in OpenJDK8.
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* This does only work when T is erased to Object at call site.
*
* See https://github.com/imglib/imglib2/issues/253
*/
@Deprecated
@SuppressWarnings( "unchecked" )
public static < T > T[] genericArray( final int length )
{
return ( T[] ) ( new Object[ length ] );
}
public static double log2( final double value )
{
return Math.log( value ) / Math.log( 2.0 );
}
// TODO: move to ArrayUtil?
public static double[] getArrayFromValue( final double value, final int numDimensions )
{
final double[] values = new double[ numDimensions ];
Arrays.fill( values, value );
return values;
}
// TODO: move to ArrayUtil?
public static float[] getArrayFromValue( final float value, final int numDimensions )
{
final float[] values = new float[ numDimensions ];
Arrays.fill( values, value );
return values;
}
// TODO: move to ArrayUtil?
public static int[] getArrayFromValue( final int value, final int numDimensions )
{
final int[] values = new int[ numDimensions ];
Arrays.fill( values, value );
return values;
}
// TODO: move to ArrayUtil?
public static long[] getArrayFromValue( final long value, final int numDimensions )
{
final long[] values = new long[ numDimensions ];
Arrays.fill( values, value );
return values;
}
/**
* Expand or truncate the provided array of {@code values} to length {@code
* newLength}.
*
* If {@code values.length < newLength} then the last value is repeated.
* That is, the remaining elements are filled with {@code
* values[values.length - 1]}.
*
* If {@code values.length == newLength} then {@code values} is returned,
* otherwise a new array is created.
*
* @param values
* values to copy
* @param newLength
* length of expanded array
*
* @return an array where {@code array.length == newLength} and {@code array[i] == values[Math.max(i, values.length)]}
*/
public static double[] expandArray( final double[] values, final int newLength )
{
final double[] expandedValues = ( values.length == newLength ) ? values : Arrays.copyOf( values, newLength );
if ( values.length < newLength )
Arrays.fill( expandedValues, values.length, newLength, values[ values.length - 1 ] );
return expandedValues;
}
/**
* Expand or truncate the provided array of {@code values} to length {@code
* newLength}.
*
* If {@code values.length < newLength} then the last value is repeated.
* That is, the remaining elements are filled with {@code
* values[values.length - 1]}.
*
* If {@code values.length == newLength} then {@code values} is returned,
* otherwise a new array is created.
*
* @param values
* values to copy
* @param newLength
* length of expanded array
*
* @return an array where {@code array.length == newLength} and {@code array[i] == values[Math.max(i, values.length)]}
*/
public static long[] expandArray( final long[] values, final int newLength )
{
final long[] expandedValues = ( values.length == newLength ) ? values : Arrays.copyOf( values, newLength );
if ( values.length < newLength )
Arrays.fill( expandedValues, values.length, newLength, values[ values.length - 1 ] );
return expandedValues;
}
/**
* Expand or truncate the provided array of {@code values} to length {@code
* newLength}.
*
* If {@code values.length < newLength} then the last value is repeated.
* That is, the remaining elements are filled with {@code
* values[values.length - 1]}.
*
* If {@code values.length == newLength} then {@code values} is returned,
* otherwise a new array is created.
*
* @param values
* values to copy
* @param newLength
* length of expanded array
*
* @return an array where {@code array.length == newLength} and {@code array[i] == values[Math.max(i, values.length)]}
*/
public static int[] expandArray( final int[] values, final int newLength )
{
final int[] expandedValues = ( values.length == newLength ) ? values : Arrays.copyOf( values, newLength );
if ( values.length < newLength )
Arrays.fill( expandedValues, values.length, newLength, values[ values.length - 1 ] );
return expandedValues;
}
/**
* Expand or truncate the provided array of {@code values} to length {@code
* newLength}.
*
* If {@code values.length < newLength} then the last value is repeated.
* That is, the remaining elements are filled with {@code
* values[values.length - 1]}.
*
* If {@code values.length == newLength} then {@code values} is returned,
* otherwise a new array is created.
*
* @param values
* values to copy
* @param newLength
* length of expanded array
*
* @return an array where {@code array.length == newLength} and {@code array[i] == values[Math.max(i, values.length)]}
*/
public static boolean[] expandArray( final boolean[] values, final int newLength )
{
final boolean[] expandedValues = ( values.length == newLength ) ? values : Arrays.copyOf( values, newLength );
if ( values.length < newLength )
Arrays.fill( expandedValues, values.length, newLength, values[ values.length - 1 ] );
return expandedValues;
}
public static double distance( final RealLocalizable position1, final RealLocalizable position2 )
{
double dist = 0;
final int n = position1.numDimensions();
for ( int d = 0; d < n; ++d )
{
final double pos = position2.getDoublePosition( d ) - position1.getDoublePosition( d );
dist += pos * pos;
}
return Math.sqrt( dist );
}
public static double distance( final long[] position1, final long[] position2 )
{
double dist = 0;
for ( int d = 0; d < position1.length; ++d )
{
final long pos = position2[ d ] - position1[ d ];
dist += pos * pos;
}
return Math.sqrt( dist );
}
/**
* Computes the percentile of a collection of doubles (percentile 0.5
* roughly corresponds to median)
*
* @param values
* - the values
* @param percentile
* - the percentile [0...1]
* @return the corresponding value
*/
public static double percentile( final double[] values, final double percentile )
{
final double temp[] = values.clone();
final int length = temp.length;
final int pos = Math.min( length - 1, Math.max( 0, ( int ) Math.round( ( length - 1 ) * percentile ) ) );
KthElement.kthElement( pos, temp );
return temp[ pos ];
}
public static double averageDouble( final List< Double > values )
{
final double size = values.size();
double avg = 0;
for ( final double v : values )
avg += v / size;
return avg;
}
public static float averageFloat( final List< Float > values )
{
final double size = values.size();
double avg = 0;
for ( final double v : values )
avg += v / size;
return ( float ) avg;
}
public static float min( final List< Float > values )
{
float min = Float.MAX_VALUE;
for ( final float v : values )
if ( v < min )
min = v;
return min;
}
public static float max( final List< Float > values )
{
float max = -Float.MAX_VALUE;
for ( final float v : values )
if ( v > max )
max = v;
return max;
}
public static float average( final float[] values )
{
final double size = values.length;
double avg = 0;
for ( final float v : values )
avg += v / size;
return ( float ) avg;
}
public static double average( final double[] values )
{
final double size = values.length;
double avg = 0;
for ( final double v : values )
avg += v / size;
return avg;
}
public static double min( final double[] values )
{
double min = values[ 0 ];
for ( final double v : values )
if ( v < min )
min = v;
return min;
}
public static double max( final double[] values )
{
double max = values[ 0 ];
for ( final double v : values )
if ( v > max )
max = v;
return max;
}
public static long median( final long[] values )
{
final long temp[] = values.clone();
long median;
final int length = temp.length;
quicksort( temp, 0, length - 1 );
if ( length % 2 == 1 ) // odd length
median = temp[ length / 2 ];
else
// even length
median = ( temp[ length / 2 ] + temp[ ( length / 2 ) - 1 ] ) / 2;
return median;
}
public static double median( final double[] values )
{
final double temp[] = values.clone();
double median;
final int length = temp.length;
quicksort( temp, 0, length - 1 );
if ( length % 2 == 1 ) // odd length
median = temp[ length / 2 ];
else
// even length
median = ( temp[ length / 2 ] + temp[ ( length / 2 ) - 1 ] ) / 2;
return median;
}
public static float median( final float[] values )
{
final float temp[] = values.clone();
float median;
final int length = temp.length;
quicksort( temp, 0, length - 1 );
if ( length % 2 == 1 ) // odd length
median = temp[ length / 2 ];
else
// even length
median = ( temp[ length / 2 ] + temp[ ( length / 2 ) - 1 ] ) / 2;
return median;
}
public static void quicksort( final long[] data )
{
quicksort( data, 0, data.length - 1 );
}
public static void quicksort( final long[] data, final int left, final int right )
{
if ( data == null || data.length < 2 )
return;
int i = left, j = right;
final long x = data[ ( left + right ) / 2 ];
do
{
while ( data[ i ] < x )
i++;
while ( x < data[ j ] )
j--;
if ( i <= j )
{
final long temp = data[ i ];
data[ i ] = data[ j ];
data[ j ] = temp;
i++;
j--;
}
}
while ( i <= j );
if ( left < j )
quicksort( data, left, j );
if ( i < right )
quicksort( data, i, right );
}
public static void quicksort( final double[] data )
{
quicksort( data, 0, data.length - 1 );
}
public static void quicksort( final double[] data, final int left, final int right )
{
if ( data == null || data.length < 2 )
return;
int i = left, j = right;
final double x = data[ ( left + right ) / 2 ];
do
{
while ( data[ i ] < x )
i++;
while ( x < data[ j ] )
j--;
if ( i <= j )
{
final double temp = data[ i ];
data[ i ] = data[ j ];
data[ j ] = temp;
i++;
j--;
}
}
while ( i <= j );
if ( left < j )
quicksort( data, left, j );
if ( i < right )
quicksort( data, i, right );
}
public static void quicksort( final float[] data )
{
quicksort( data, 0, data.length - 1 );
}
public static void quicksort( final float[] data, final int left, final int right )
{
if ( data == null || data.length < 2 )
return;
int i = left, j = right;
final float x = data[ ( left + right ) / 2 ];
do
{
while ( data[ i ] < x )
i++;
while ( x < data[ j ] )
j--;
if ( i <= j )
{
final float temp = data[ i ];
data[ i ] = data[ j ];
data[ j ] = temp;
i++;
j--;
}
}
while ( i <= j );
if ( left < j )
quicksort( data, left, j );
if ( i < right )
quicksort( data, i, right );
}
public static void quicksort( final double[] data, final int[] sortAlso, final int left, final int right )
{
if ( data == null || data.length < 2 )
return;
int i = left, j = right;
final double x = data[ ( left + right ) / 2 ];
do
{
while ( data[ i ] < x )
i++;
while ( x < data[ j ] )
j--;
if ( i <= j )
{
final double temp = data[ i ];
data[ i ] = data[ j ];
data[ j ] = temp;
final int temp2 = sortAlso[ i ];
sortAlso[ i ] = sortAlso[ j ];
sortAlso[ j ] = temp2;
i++;
j--;
}
}
while ( i <= j );
if ( left < j )
quicksort( data, sortAlso, left, j );
if ( i < right )
quicksort( data, sortAlso, i, right );
}
public static double gLog( final double z, final double c )
{
if ( c == 0 )
return z;
return Math.log10( ( z + Math.sqrt( z * z + c * c ) ) / 2.0 );
}
public static float gLog( final float z, final float c )
{
if ( c == 0 )
return z;
return ( float ) Math.log10( ( z + Math.sqrt( z * z + c * c ) ) / 2.0 );
}
public static double gLogInv( final double w, final double c )
{
if ( c == 0 )
return w;
return Math.pow( 10, w ) - ( ( ( c * c ) * Math.pow( 10, -w ) ) / 4.0 );
}
public static double gLogInv( final float w, final float c )
{
if ( c == 0 )
return w;
return Math.pow( 10, w ) - ( ( ( c * c ) * Math.pow( 10, -w ) ) / 4.0 );
}
public static boolean isApproxEqual( final float a, final float b, final float threshold )
{
if ( a == b )
return true;
else if ( a + threshold > b && a - threshold < b )
return true;
else
return false;
}
public static boolean isApproxEqual( final double a, final double b, final double threshold )
{
if ( a == b )
return true;
else if ( a + threshold > b && a - threshold < b )
return true;
else
return false;
}
public static int round( final float value )
{
return roundToInt( value );
}
public static long round( final double value )
{
return roundToLong( value );
}
public static int roundToInt( final float value )
{
return ( int ) ( value + ( 0.5f * Math.signum( value ) ) );
}
public static int roundToInt( final double value )
{
return ( int ) ( value + ( 0.5d * Math.signum( value ) ) );
}
public static long roundToLong( final float value )
{
return ( long ) ( value + ( 0.5f * Math.signum( value ) ) );
}
public static long roundToLong( final double value )
{
return ( long ) ( value + ( 0.5d * Math.signum( value ) ) );
}
/**
* This method creates a gaussian kernel
*
* @param sigma
* Standard Derivation of the gaussian function
* @param normalize
* Normalize integral of gaussian function to 1 or not...
* @return double[] The gaussian kernel
*
*/
public static double[] createGaussianKernel1DDouble( final double sigma, final boolean normalize )
{
int size = 3;
final double[] gaussianKernel;
if ( sigma <= 0 )
{
gaussianKernel = new double[ 3 ];
gaussianKernel[ 1 ] = 1;
}
else
{
size = Math.max( 3, ( 2 * ( int ) ( 3 * sigma + 0.5 ) + 1 ) );
final double two_sq_sigma = 2 * sigma * sigma;
gaussianKernel = new double[ size ];
for ( int x = size / 2; x >= 0; --x )
{
final double val = Math.exp( -( x * x ) / two_sq_sigma );
gaussianKernel[ size / 2 - x ] = val;
gaussianKernel[ size / 2 + x ] = val;
}
}
if ( normalize )
{
double sum = 0;
for ( final double value : gaussianKernel )
sum += value;
for ( int i = 0; i < gaussianKernel.length; ++i )
gaussianKernel[ i ] /= sum;
}
return gaussianKernel;
}
public static int getSuggestedKernelDiameter( final double sigma )
{
int size = 3;
if ( sigma > 0 )
size = Math.max( 3, ( 2 * ( int ) ( 3 * sigma + 0.5 ) + 1 ) );
return size;
}
public static String printCoordinates( final float[] value )
{
String out = "(Array empty)";
if ( value == null || value.length == 0 )
return out;
out = "(" + value[ 0 ];
for ( int i = 1; i < value.length; i++ )
out += ", " + value[ i ];
out += ")";
return out;
}
public static String printCoordinates( final double[] value )
{
String out = "(Array empty)";
if ( value == null || value.length == 0 )
return out;
out = "(" + value[ 0 ];
for ( int i = 1; i < value.length; i++ )
out += ", " + value[ i ];
out += ")";
return out;
}
public static String printCoordinates( final RealLocalizable localizable )
{
String out = "(RealLocalizable empty)";
if ( localizable == null || localizable.numDimensions() == 0 )
return out;
out = "(" + localizable.getFloatPosition( 0 );
for ( int i = 1; i < localizable.numDimensions(); i++ )
out += ", " + localizable.getFloatPosition( i );
out += ")";
return out;
}
public static String printInterval( final Interval interval )
{
String out = "(Interval empty)";
if ( interval == null || interval.numDimensions() == 0 )
return out;
out = "[" + interval.min( 0 );
for ( int i = 1; i < interval.numDimensions(); i++ )
out += ", " + interval.min( i );
out += "] -> [" + interval.max( 0 );
for ( int i = 1; i < interval.numDimensions(); i++ )
out += ", " + interval.max( i );
out += "], dimensions (" + interval.dimension( 0 );
for ( int i = 1; i < interval.numDimensions(); i++ )
out += ", " + interval.dimension( i );
out += ")";
return out;
}
public static String printCoordinates( final int[] value )
{
String out = "(Array empty)";
if ( value == null || value.length == 0 )
return out;
out = "(" + value[ 0 ];
for ( int i = 1; i < value.length; i++ )
out += ", " + value[ i ];
out += ")";
return out;
}
public static String printCoordinates( final long[] value )
{
String out = "(Array empty)";
if ( value == null || value.length == 0 )
return out;
out = "(" + value[ 0 ];
for ( int i = 1; i < value.length; i++ )
out += ", " + value[ i ];
out += ")";
return out;
}
public static String printCoordinates( final boolean[] value )
{
String out = "(Array empty)";
if ( value == null || value.length == 0 )
return out;
out = "(";
if ( value[ 0 ] )
out += "1";
else
out += "0";
for ( int i = 1; i < value.length; i++ )
{
out += ", ";
if ( value[ i ] )
out += "1";
else
out += "0";
}
out += ")";
return out;
}
public static int pow( final int a, final int b )
{
if ( b == 0 )
return 1;
else if ( b == 1 )
return a;
else
{
int result = a;
for ( int i = 1; i < b; i++ )
result *= a;
return result;
}
}
public static < T extends Type< T > & Comparable< T > > T max( final T value1, final T value2 )
{
if ( value1.compareTo( value2 ) >= 0 )
return value1;
else
return value2;
}
public static < T extends Type< T > & Comparable< T > > T min( final T value1, final T value2 )
{
if ( value1.compareTo( value2 ) <= 0 )
return value1;
else
return value2;
}
final static public int[] long2int( final long[] a )
{
final int[] i = new int[ a.length ];
for ( int d = 0; d < a.length; ++d )
i[ d ] = ( int ) a[ d ];
return i;
}
final static public long[] int2long( final int[] i )
{
final long[] l = new long[ i.length ];
for ( int d = 0; d < l.length; ++d )
l[ d ] = i[ d ];
return l;
}
/**
* Cast {@code value} to {@code int}, checking for overflow.
*
* @param value
* value to cast to {@code int}
*
* @return {@code value} cast to {@code int}
*
* @throws IllegalArgumentException
* if {@code value > Integer.MAX_VALUE}
*/
public static int safeInt( final long value )
{
if ( value > Integer.MAX_VALUE )
throw new IllegalArgumentException( "value too large" );
return ( int ) value;
}
/**
*
* This method has been deprecated.
* Use {@link RandomAccessibleInterval#getType()} instead.
* TODO: Cannot deprecate because rai parameter is not actually a RandomAccessibleInterval
*
* Gets an instance of T from the {@link RandomAccessibleInterval} by
* querying the value at the min coordinate
*
* @param
* - the T
* @param rai
* - the {@link RandomAccessibleInterval}
* @return - an instance of T
*/
@Deprecated
public static < T, F extends Interval & RandomAccessible< T > > T getTypeFromInterval( final F rai )
{
final T type = rai.getType();
return type instanceof Type ? ( T ) ( ( Type ) type ).createVariable() : type;
}
/**
* Gets an instance of T from the {@link RandomAccessibleInterval} by
* querying the value at the min coordinate
*
* @param
* - the T
* @param rai
* - the {@link RandomAccessibleInterval}
* @return - an instance of T
*/
@Deprecated
public static < T, F extends RealInterval & RealRandomAccessible< T > > T getTypeFromRealInterval( final F rai )
{
final T type = rai.getType();
return type instanceof Type ? ( T ) ( ( Type ) type ).createVariable() : type;
}
/**
* Create an {@link ArrayImgFactory} if an image of the requested
* targetSize
could be held in an {@link ArrayImg}. Otherwise
* return a {@link CellImgFactory} with as large as possible cell size.
*
* @param targetSize
* size of image that the factory should be able to create.
* @param type
* type of the factory.
* @return an {@link ArrayImgFactory} or a {@link CellImgFactory}.
*/
public static < T extends NativeType< T > > ImgFactory< T > getArrayOrCellImgFactory( final Dimensions targetSize, final T type )
{
return getArrayOrCellImgFactory( targetSize, Integer.MAX_VALUE, type );
}
/**
* Create an {@link ArrayImgFactory} if an image of the requested
* targetSize
could be held in an {@link ArrayImg}. Otherwise
* return a {@link CellImgFactory} with cell size
* targetCellSize
(or as large as possible if
* targetCellSize
is too large).
*
* @param targetSize
* size of image that the factory should be able to create.
* @param targetCellSize
* if a {@link CellImgFactory} is created, what should be the
* cell size.
* @param type
* type of the factory.
* @return an {@link ArrayImgFactory} or a {@link CellImgFactory}.
*/
public static < T extends NativeType< T > > ImgFactory< T > getArrayOrCellImgFactory( final Dimensions targetSize, final int targetCellSize, final T type )
{
Fraction entitiesPerPixel = type.getEntitiesPerPixel();
final long numElements = Intervals.numElements( targetSize );
final long numEntities = entitiesPerPixel.mulCeil( numElements );
if ( numElements <= Integer.MAX_VALUE && numEntities <= MAX_ARRAY_SIZE )
return new ArrayImgFactory<>( type );
final int maxCellSize = ( int ) Math.pow( Math.min( MAX_ARRAY_SIZE / entitiesPerPixel.getRatio(), Integer.MAX_VALUE ), 1.0 / targetSize.numDimensions() );
final int cellSize = Math.min( targetCellSize, maxCellSize );
return new CellImgFactory<>( type, cellSize );
}
/**
* Create an appropriate {@link ImgFactory} for the requested
* {@code targetSize} and {@code type}. If the target size is a {@link Img},
* return its {@link ImgFactory}. If the type is a {@link NativeType}, then
* {@link #getArrayOrCellImgFactory(Dimensions, NativeType)} is used; if
* not, a {@link ListImgFactory} is returned.
*
* @param targetSize
* size of image that the factory should be able to create.
* @param type
* type of the factory.
* @return an {@link ArrayImgFactory}, {@link CellImgFactory} or
* {@link ListImgFactory} as appropriate.
*/
public static < T > ImgFactory< T > getSuitableImgFactory( final Dimensions targetSize, final T type )
{
if ( targetSize instanceof Img )
{
final Img< ? > targetImg = ( Img< ? > ) targetSize;
final ImgFactory< ? > factory = targetImg.factory();
if ( factory != null )
{
try
{
return factory.imgFactory( type );
}
catch ( IncompatibleTypeException e )
{
}
}
}
if ( type instanceof NativeType )
{
// NB: Eclipse does not demand the cast to ImgFactory< T >, but javac does.
@SuppressWarnings( { "cast", "rawtypes", "unchecked" } )
final ImgFactory< T > arrayOrCellImgFactory = ( ImgFactory< T > ) getArrayOrCellImgFactory( targetSize, ( NativeType ) type );
return arrayOrCellImgFactory;
}
return new ListImgFactory<>( type );
}
/**
* (Hopefully) fast floor log2 of an unsigned(!) integer value.
*
* @param v
* unsigned integer
* @return floor log2
*/
final static public int ldu( int v )
{
int c = 0;
do
{
v >>= 1;
++c;
}
while ( v > 1 );
return c;
}
/**
* Checks whether n {@link IterableInterval} have the same iteration order.
*/
public static boolean equalIterationOrder( final IterableInterval< ? >... intervals )
{
final Object order = intervals[ 0 ].iterationOrder();
for ( int i = 1; i < intervals.length; i++ )
{
if ( !order.equals( intervals[ i ].iterationOrder() ) )
return false;
}
return true;
}
/**
* Determines whether the two {@link Localizable} objects have the same
* position, with {@code long} precision.
*
* At first glance, this method may appear to be unnecessary, since there is
* also {@link #locationsEqual(RealLocalizable, RealLocalizable)}, which is
* more general. The difference is that this method compares the positions
* using {@link Localizable#getLongPosition(int)}, which has higher
* precision in integer space than
* {@link RealLocalizable#getDoublePosition(int)} does, which is what the
* {@link #locationsEqual(RealLocalizable, RealLocalizable)} method uses.
*
*
* @param l1
* The first {@link Localizable}.
* @param l2
* The second {@link Localizable}.
* @return True iff the positions are the same, including dimensionality.
* @see Localizable#getLongPosition(int)
*/
public static boolean locationsEqual( final Localizable l1, final Localizable l2 )
{
final int numDims = l1.numDimensions();
if ( l2.numDimensions() != numDims )
return false;
for ( int d = 0; d < numDims; d++ )
{
if ( l1.getLongPosition( d ) != l2.getLongPosition( d ) )
return false;
}
return true;
}
/**
* Determines whether the two {@link RealLocalizable} objects have the same
* position, with {@code double} precision.
*
* @param l1
* The first {@link RealLocalizable}.
* @param l2
* The second {@link RealLocalizable}.
* @return True iff the positions are the same, including dimensionality.
* @see RealLocalizable#getDoublePosition(int)
*/
public static boolean locationsEqual( final RealLocalizable l1, final RealLocalizable l2 )
{
final int numDims = l1.numDimensions();
if ( l2.numDimensions() != numDims )
return false;
for ( int d = 0; d < numDims; d++ )
{
if ( l1.getDoublePosition( d ) != l2.getDoublePosition( d ) )
return false;
}
return true;
}
/**
* Checks if both images have equal intervals and content.
*/
public static < T extends ValueEquals< U >, U > boolean imagesEqual( final RandomAccessibleInterval< ? extends T > a, final RandomAccessibleInterval< ? extends U > b )
{
return imagesEqual( a, b, ValueEquals::valueEquals );
}
/**
* Checks if both images have equal intervals and content.
* A predicate must be given to check if two pixels are equal.
*/
public static < T, U > boolean imagesEqual( final RandomAccessibleInterval< ? extends T > a, final RandomAccessibleInterval< ? extends U > b, final BiPredicate< T, U > pixelEquals )
{
if ( !Intervals.equals( a, b ) )
return false;
for ( final Pair< ? extends T, ? extends U > pair : Views.interval( Views.pair( a, b ), b ) )
if ( !pixelEquals.test( pair.getA(), pair.getB() ) )
return false;
return true;
}
/**
* Writes min(a,b) into a
*
* @param a
* @param b
*/
final static public void min( final double[] a, final double[] b )
{
for ( int i = 0; i < a.length; ++i )
if ( b[ i ] < a[ i ] )
a[ i ] = b[ i ];
}
/**
* Writes max(a,b) into a
*
* @param a
* @param b
*/
final static public void max( final double[] a, final double[] b )
{
for ( int i = 0; i < a.length; ++i )
if ( b[ i ] > a[ i ] )
a[ i ] = b[ i ];
}
/**
* Returns the content of {@code Iterable} as array of doubles.
*/
public static double[] asDoubleArray( final Iterable< ? extends RealType< ? > > iterable )
{
return StreamSupport.stream( iterable.spliterator(), false ).mapToDouble( RealType::getRealDouble ).toArray();
}
/**
* Returns the pixels of an RandomAccessibleInterval of RealType as array of doubles.
* The pixels are sorted in flat iteration order.
*/
public static double[] asDoubleArray( final RandomAccessibleInterval< ? extends RealType< ? > > rai )
{
return Views.flatIterable( rai ).stream().mapToDouble( RealType::getRealDouble ).toArray();
}
/**
* This method should be used in implementations of {@link ValueEquals}, to
* override {@link Object#equals(Object)}.
*
* @see net.imglib2.type.AbstractNativeType#equals(Object)
*/
public static < T extends ValueEquals< T > > boolean valueEqualsObject( final T a, final Object b )
{
if ( !a.getClass().isInstance( b ) )
return false;
@SuppressWarnings( "unchecked" )
final T t = ( T ) b;
return a.valueEquals( t );
}
public static int combineHash( final int hash1, final int hash2 )
{
return 31 * hash1 + hash2;
}
}