/*- * #%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 ij.ImagePlus; import net.imglib2.Cursor; import net.imglib2.RandomAccess; import net.imglib2.RandomAccessibleInterval; import net.imglib2.RealInterval; import net.imglib2.RealRandomAccess; import net.imglib2.RealRandomAccessible; import net.imglib2.algorithm.fft2.FFTConvolution; import net.imglib2.converter.RealFloatConverter; import net.imglib2.converter.read.ConvertedRandomAccessibleInterval; import net.imglib2.exception.IncompatibleTypeException; import net.imglib2.img.Img; import net.imglib2.img.ImgFactory; import net.imglib2.img.array.ArrayImgFactory; import net.imglib2.img.array.ArrayImgs; import net.imglib2.img.display.imagej.ImageJFunctions; import net.imglib2.interpolation.randomaccess.NLinearInterpolatorFactory; import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.complex.ComplexFloatType; import net.imglib2.type.numeric.real.FloatType; import net.imglib2.util.Util; import net.imglib2.view.Views; import spim.process.fusion.FusionHelper; /** * Computes the content-based fusion on a given image * * @author Stephan Preibisch (stephan.preibisch@gmx.de) * * @param <T> */ public class ContentBased< T extends RealType< T > > implements RealRandomAccessible< FloatType > { /** * The Img containing the approxmimated content-based weights */ final Img< FloatType > contentBasedImg; final int n; public ContentBased( final RandomAccessibleInterval< T > input, final ImgFactory< ComplexFloatType > imgFactory, final double[] sigma1, final double[] sigma2 ) { this.n = input.numDimensions(); this.contentBasedImg = approximateEntropy( new ConvertedRandomAccessibleInterval< T, FloatType >( input, new RealFloatConverter< T >(), new FloatType() ), imgFactory, sigma1, sigma2 ); } public Img< FloatType > getContentBasedImg() { return contentBasedImg; } protected Img< FloatType > approximateEntropy( final RandomAccessibleInterval< FloatType > input, final ImgFactory< ComplexFloatType > imgFactory, final double[] sigma1, final double[] sigma2 ) { // the result ImgFactory<FloatType> f; try { f = imgFactory.imgFactory( new FloatType() ); } catch (IncompatibleTypeException e) { f = new ArrayImgFactory< FloatType >(); } final Img< FloatType > conv = f.create( input, new FloatType() ); // compute I*sigma1 FFTConvolution< FloatType > fftConv = new FFTConvolution<FloatType>( input, createGaussianKernel( sigma1 ), conv, imgFactory ); fftConv.convolve(); // compute ( I - I*sigma1 )^2 final Cursor< FloatType > c = conv.cursor(); final RandomAccess< FloatType > r = input.randomAccess(); while ( c.hasNext() ) { c.fwd(); r.setPosition( c ); final float diff = c.get().get() - r.get().get(); c.get().set( diff * diff ); } // compute ( ( I - I*sigma1 )^2 ) * sigma2 fftConv = new FFTConvolution<FloatType>( conv, createGaussianKernel( sigma2 ), imgFactory ); fftConv.convolve(); // normalize to [0...1] FusionHelper.normalizeImage( conv ); return conv; } @Override public int numDimensions() { return contentBasedImg.numDimensions(); } @Override public RealRandomAccess<FloatType> realRandomAccess() { return Views.interpolate( Views.extendZero( this.contentBasedImg ), new NLinearInterpolatorFactory< FloatType >() ).realRandomAccess(); } @Override public RealRandomAccess<FloatType> realRandomAccess( final RealInterval interval ) { return Views.interpolate( Views.extendZero( this.contentBasedImg ), new NLinearInterpolatorFactory< FloatType >() ).realRandomAccess( interval ); } final private static Img< FloatType > createGaussianKernel( final double[] sigmas ) { final int numDimensions = sigmas.length; final long[] imageSize = new long[ numDimensions ]; final double[][] kernel = new double[ numDimensions ][]; for ( int d = 0; d < numDimensions; ++d ) { kernel[ d ] = Util.createGaussianKernel1DDouble( sigmas[ d ], true ); imageSize[ d ] = kernel[ d ].length; } final Img< FloatType > kernelImg = ArrayImgs.floats( imageSize ); final Cursor< FloatType > cursor = kernelImg.localizingCursor(); final int[] position = new int[ numDimensions ]; while ( cursor.hasNext() ) { cursor.fwd(); cursor.localize( position ); double value = 1; for ( int d = 0; d < numDimensions; ++d ) value *= kernel[ d ][ position[ d ] ]; cursor.get().set( ( float ) value ); } return kernelImg; } public static void main( String[] args ) throws IncompatibleTypeException { new ImageJ(); ImagePlus imp = new ImagePlus( "/Users/preibischs/workspace/TestLucyRichardson/src/resources/dros-1.tif" ); Img< FloatType > img = ImageJFunctions.wrap( imp ); final double[] sigma1 = new double[]{ 20, 20 }; final double[] sigma2 = new double[]{ 30, 30 }; ContentBased< FloatType > cb = new ContentBased<FloatType>( img, img.factory().imgFactory( new ComplexFloatType() ), sigma1, sigma2 ); ImageJFunctions.show( cb.getContentBasedImg() ); } }