/*- * #%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.fusion.weights; import ij.ImageJ; import net.imglib2.Cursor; import net.imglib2.Interval; import net.imglib2.Localizable; import net.imglib2.RealLocalizable; import net.imglib2.RealRandomAccess; import net.imglib2.Sampler; import net.imglib2.img.Img; import net.imglib2.img.array.ArrayImgs; import net.imglib2.img.display.imagej.ImageJFunctions; import net.imglib2.type.numeric.real.FloatType; public class BlendingRealRandomAccess implements RealRandomAccess< FloatType > { final Interval interval; final int[] min, dimMinus1; final float[] l, border, blending; final int n; final FloatType v; // static lookup table for the blending function final static private double[] lookUp; private static final int indexFor( final double d ) { return (int)Math.round( d * 1000.0 ); } static { lookUp = new double[ 1001 ]; for ( double d = 0; d <= 1.0001; d = d + 0.001 ) lookUp[ indexFor( d ) ] = ( Math.cos( ( 1 - d ) * Math.PI ) + 1 ) / 2; } /** * RealRandomAccess that computes a blending function for a certain {@link Interval} * * @param interval - the interval it is defined on (return zero outside of it) * @param border - how many pixels to skip before starting blending (on each side of each dimension) * @param blending - how many pixels to compute the blending function on (on each side of each dimension) */ public BlendingRealRandomAccess( final Interval interval, final float[] border, final float[] blending ) { this.interval = interval; this.n = interval.numDimensions(); this.l = new float[ n ]; this.border = border; this.blending = blending; this.v = new FloatType(); this.min = new int[ n ]; this.dimMinus1 = new int[ n ]; for ( int d = 0; d < n; ++d ) { this.min[ d ] = (int)interval.min( d ); this.dimMinus1[ d ] = (int)interval.max( d ) - min[ d ]; } } @Override public FloatType get() { v.set( computeWeight( l, min, dimMinus1, border, blending, n ) ); return v; } final private static float computeWeight( final float[] location, final int[] min, final int[] dimMinus1, final float[] border, final float[] blending, final int n ) { // compute multiplicative distance to the respective borders [0...1] float minDistance = 1; for ( int d = 0; d < n; ++d ) { // the position in the image relative to the boundaries and the border final float l = ( location[ d ] - min[ d ] ); // the distance to the border that is closer final float dist = Math.max( 0, Math.min( l - border[ d ], dimMinus1[ d ] - l - border[ d ] ) ); // if this is 0, the total result will be 0, independent of the number of dimensions if ( dist == 0 ) return 0; final float relDist = dist / blending[ d ]; if ( relDist < 1 ) minDistance *= lookUp[ indexFor( relDist ) ]; //( Math.cos( ( 1 - relDist ) * Math.PI ) + 1 ) / 2; } return minDistance; } @Override public void localize( final float[] position ) { for ( int d = 0; d < n; ++d ) position[ d ] = l[ d ]; } @Override public void localize( final double[] position ) { for ( int d = 0; d < n; ++d ) position[ d ] = l[ d ]; } @Override public float getFloatPosition( final int d ){ return l[ d ]; } @Override public double getDoublePosition( final int d ) { return l[ d ]; } @Override public int numDimensions() { return n; } @Override public void move( final float distance, final int d ) { l[ d ] += distance; } @Override public void move( final double distance, final int d ) { l[ d ] += distance; } @Override public void move( final RealLocalizable localizable ) { for ( int d = 0; d < n; ++d ) l[ d ] += localizable.getFloatPosition( d ); } @Override public void move( final float[] distance ) { for ( int d = 0; d < n; ++d ) l[ d ] += distance[ d ]; } @Override public void move( final double[] distance ) { for ( int d = 0; d < n; ++d ) l[ d ] += distance[ d ]; } @Override public void setPosition( final RealLocalizable localizable ) { for ( int d = 0; d < n; ++d ) l[ d ] = localizable.getFloatPosition( d ); } @Override public void setPosition( final float[] position ) { for ( int d = 0; d < n; ++d ) l[ d ] = position[ d ]; } @Override public void setPosition( final double[] position ) { for ( int d = 0; d < n; ++d ) l[ d ] =(float)position[ d ]; } @Override public void setPosition( final float position, final int d ) { l[ d ] = position; } @Override public void setPosition( final double position, final int d ) { l[ d ] = (float)position; } @Override public void fwd( final int d ) { ++l[ d ]; } @Override public void bck( final int d ) { --l[ d ]; } @Override public void move( final int distance, final int d ) { l[ d ] += distance; } @Override public void move( final long distance, final int d ) { l[ d ] += distance; } @Override public void move( final Localizable localizable ) { for ( int d = 0; d < n; ++d ) l[ d ] += localizable.getFloatPosition( d ); } @Override public void move( final int[] distance ) { for ( int d = 0; d < n; ++d ) l[ d ] += distance[ d ]; } @Override public void move( final long[] distance ) { for ( int d = 0; d < n; ++d ) l[ d ] += distance[ d ]; } @Override public void setPosition( final Localizable localizable ) { for ( int d = 0; d < n; ++d ) l[ d ] = localizable.getFloatPosition( d ); } @Override public void setPosition( final int[] position ) { for ( int d = 0; d < n; ++d ) l[ d ] = position[ d ]; } @Override public void setPosition( final long[] position ) { for ( int d = 0; d < n; ++d ) l[ d ] = position[ d ]; } @Override public void setPosition( final int position, final int d ) { l[ d ] = position; } @Override public void setPosition( final long position, final int d ) { l[ d ] = position; } @Override public Sampler<FloatType> copy() { return copyRealRandomAccess(); } @Override public RealRandomAccess<FloatType> copyRealRandomAccess() { final BlendingRealRandomAccess r = new BlendingRealRandomAccess( interval, border, blending ); r.setPosition( this ); return r; } public static void main( String[] args ) { new ImageJ(); Img< FloatType > img = ArrayImgs.floats( 500, 500 ); BlendingRealRandomAccess blend = new BlendingRealRandomAccess( img, new float[]{ 100, 0 }, new float[]{ 12, 150 } ); Cursor< FloatType > c = img.localizingCursor(); while ( c.hasNext() ) { c.fwd(); blend.setPosition( c ); c.get().setReal( blend.get().getRealFloat() ); } ImageJFunctions.show( img ); } }