Skip to content

Commit

Permalink
Add support for arbitrary net.imglib2.converter.Converter in Convert
Browse files Browse the repository at this point in the history
  • Loading branch information
tpietzsch committed Mar 18, 2024
1 parent 90f4dba commit 0babe09
Show file tree
Hide file tree
Showing 3 changed files with 396 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@
*/
package net.imglib2.algorithm.blocks.convert;

import java.util.function.Supplier;

import net.imglib2.algorithm.blocks.DefaultUnaryBlockOperator;
import net.imglib2.algorithm.blocks.UnaryBlockOperator;
import net.imglib2.converter.Converter;
import net.imglib2.type.NativeType;

/**
Expand Down Expand Up @@ -77,4 +80,14 @@ UnaryBlockOperator< S, T > convert( final S sourceType, final T targetType, fina
{
return new DefaultUnaryBlockOperator<>( sourceType, targetType, new ConvertBlockProcessor<>( sourceType, targetType, clamp ) );
}

/**
* Create {@link UnaryBlockOperator} to convert blocks between {@code
* sourceType} and {@code targetType} with the specified {@code Converter}.
*/
public static < S extends NativeType< S >, T extends NativeType< T > >
UnaryBlockOperator< S, T > convert( final S sourceType, final T targetType, Supplier< Converter< ? super S, T > > converterSupplier )
{
return new DefaultUnaryBlockOperator<>( sourceType, targetType, new ConverterBlockProcessor<>( sourceType, targetType, converterSupplier ) );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
/*-
* #%L
* ImgLib2: a general-purpose, multidimensional image processing library.
* %%
* Copyright (C) 2009 - 2023 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.algorithm.blocks.convert;

import java.util.Arrays;
import java.util.function.Supplier;

import net.imglib2.Cursor;
import net.imglib2.Interval;
import net.imglib2.RandomAccess;
import net.imglib2.algorithm.blocks.BlockProcessor;
import net.imglib2.algorithm.blocks.util.BlockProcessorSourceInterval;
import net.imglib2.blocks.TempArray;
import net.imglib2.converter.Converter;
import net.imglib2.img.AbstractImg;
import net.imglib2.img.Img;
import net.imglib2.img.ImgFactory;
import net.imglib2.img.NativeImg;
import net.imglib2.type.NativeType;
import net.imglib2.type.NativeTypeFactory;
import net.imglib2.util.CloseableThreadLocal;
import net.imglib2.util.Intervals;

/**
* Convert primitive arrays between ImgLib2 {@code NativeType}s using a {@link }Converter}.
*
* @param <S>
* source type
* @param <T>
* target type
* @param <I>
* input primitive array type, e.g., float[]. Must correspond to S.
* @param <O>
* output primitive array type, e.g., float[]. Must correspond to T.
*/
class ConverterBlockProcessor< S extends NativeType< S >, T extends NativeType< T >, I, O > implements BlockProcessor< I, O >
{
private final S sourceType;

private final T targetType;

private final Supplier< Converter< ? super S, T > > converterSupplier;

private final TempArray< I > tempArray;

private Supplier< ConverterBlockProcessor< S, T, I, O > > threadSafeSupplier;

private long[] sourcePos;

private int[] sourceSize;

private int sourceLength;

private final BlockProcessorSourceInterval sourceInterval;

private final Converter< ? super S, T > converter;

private final Wrapper< S > wrapSource;

private final Wrapper< T > wrapTarget;

public ConverterBlockProcessor( final S sourceType, final T targetType, final Supplier< Converter< ? super S, T > > converterSupplier )
{
this.sourceType = sourceType;
this.targetType = targetType;
this.converterSupplier = converterSupplier;

tempArray = TempArray.forPrimitiveType( sourceType.getNativeTypeFactory().getPrimitiveType() );
sourceInterval = new BlockProcessorSourceInterval( this );
converter = converterSupplier.get();
wrapSource = Wrapper.of( sourceType );
wrapTarget = Wrapper.of( targetType );
}

private ConverterBlockProcessor( ConverterBlockProcessor< S, T, I, O > convert )
{
sourceType = convert.sourceType;
targetType = convert.targetType;
converterSupplier = convert.converterSupplier;

threadSafeSupplier = convert.threadSafeSupplier;

tempArray = convert.tempArray.newInstance();
sourceInterval = new BlockProcessorSourceInterval( this );
converter = converterSupplier.get();
wrapSource = Wrapper.of( sourceType );
wrapTarget = Wrapper.of( targetType );
}

private ConverterBlockProcessor< S, T, I, O > newInstance()
{
return new ConverterBlockProcessor<>( this );
}

@Override
public Supplier< ? extends BlockProcessor< I, O > > threadSafeSupplier()
{
if ( threadSafeSupplier == null )
threadSafeSupplier = CloseableThreadLocal.withInitial( this::newInstance )::get;
return threadSafeSupplier;
}

@Override
public void setTargetInterval( final Interval interval )
{
final int n = interval.numDimensions();
if ( sourcePos == null || sourcePos.length != n )
{
sourcePos = new long[ n ];
sourceSize = new int[ n ];
}
interval.min( sourcePos );
Arrays.setAll( sourceSize, d -> safeInt( interval.dimension( d ) ) );
sourceLength = safeInt( Intervals.numElements( sourceSize ) );
}

private static int safeInt( final long value )
{
if ( value > Integer.MAX_VALUE )
throw new IllegalArgumentException( "value too large" );
return ( int ) value;
}

@Override
public long[] getSourcePos()
{
return sourcePos;
}

@Override
public int[] getSourceSize()
{
return sourceSize;
}

@Override
public Interval getSourceInterval()
{
return sourceInterval;
}

@Override
public I getSourceBuffer()
{
return tempArray.get( sourceLength );
}

@Override
public void compute( final I src, final O dest )
{
final S in = wrapSource.wrap( src );
final T out = wrapTarget.wrap( dest );
for ( int i = 0; i < sourceLength; i++ )
{
in.index().set( i );
out.index().set( i );
converter.convert( in, out );
}
}

// ------------------------------------------------------------------------
//
// Wrap primitive array into a Type that can be passed to the Converter
//

private interface Wrapper< T extends NativeType< T > >
{
T wrap( final Object array );

static < T extends NativeType< T > > Wrapper<T> of( T type )
{
return new WrapperImpl<>( type );
}
}

private static class WrapperImpl< T extends NativeType< T >, A > extends AbstractImg< T > implements NativeImg< T, A >, Wrapper< T >
{
private final PrimitiveTypeProperties< ?, A > props;
private Object array;
private final T wrapper;

WrapperImpl( T type )
{
super( new long[ 0 ] );
final NativeTypeFactory< T, A > nativeTypeFactory = ( NativeTypeFactory< T, A > ) type.getNativeTypeFactory();
props = ( PrimitiveTypeProperties< ?, A > ) PrimitiveTypeProperties.get( nativeTypeFactory.getPrimitiveType() );
wrapper = nativeTypeFactory.createLinkedType( this );
}

@Override
public T wrap( final Object array )
{
this.array = array;
wrapper.updateContainer( null );
return wrapper;
}

@Override
public A update( final Object updater )
{
return props.wrap( array );
}

@Override public void setLinkedType( final T type ) {throw new UnsupportedOperationException();}
@Override public T createLinkedType() {throw new UnsupportedOperationException();}
@Override public Cursor< T > cursor() {throw new UnsupportedOperationException();}
@Override public Cursor< T > localizingCursor() {throw new UnsupportedOperationException();}
@Override public Object iterationOrder() {throw new UnsupportedOperationException();}
@Override public RandomAccess< T > randomAccess() {throw new UnsupportedOperationException();}
@Override public ImgFactory< T > factory() {throw new UnsupportedOperationException();}@Override public Img< T > copy() {throw new UnsupportedOperationException();}
}
}
Loading

0 comments on commit 0babe09

Please sign in to comment.