public static Img< FloatType > convolve( final Img< FloatType > img, final Img< FloatType > psf ) { Tools.normImage( psf ); final Img< FloatType > result = img.factory().create( img, img.firstElement() ); final FFTConvolution< FloatType > conv = new FFTConvolution<FloatType>( img, psf, result ); // this fixes the wrong default kernel flipping in older versions of FFTConvolution conv.setComputeComplexConjugate(false); conv.convolve(); return result; }
/** * Utility function to create an ExecutorService * * Number of threads utilized matches available processors in runtime. * * @return - the new ExecutorService */ public static final ExecutorService createExecutorService() { return createExecutorService( Runtime.getRuntime().availableProcessors() ); }
/** * Compute a Fourier space based convolution * The image will be extended by mirroring with single boundary, the kernel will be zero-padded. * The {@link ImgFactory} for creating the FFT will be identical to the one used by the 'img' if * possible, otherwise an {@link ArrayImgFactory} or {@link CellImgFactory} depending on the size. * * @param img - the image * @param kernel - the convolution kernel * @param output - the result of the convolution */ public FFTConvolution( final Img< R > img, final Img< R > kernel, final RandomAccessibleInterval< R > output ) { this ( img, kernel, output, getFFTFactory( img ) ); }
public void convolve() { final long[] min = new long[ img.numDimensions() ]; final long[] max = new long[ img.numDimensions() ]; final Pair< Interval, Interval > fftIntervals = setupFFTs( imgInterval, kernelInterval, min, max ); // compute the FFT of the image if it does not exist yet if ( fftImg == null ) fftImg = computeImgFFT( fftIntervals.getA(), img, fftFactory, service ); // compute the FFT of the kernel if it does not exist yet if ( fftKernel == null ) fftKernel = computeKernelFFT( fftIntervals.getB(), min, max, complexConjugate, kernel, fftFactory, service ); computeConvolution( fftImg, fftKernel, output, keepImgFFT, service ); }
FFTConvolution< FloatType > fftConv = new FFTConvolution<FloatType>( input, createGaussianKernel( sigma1 ), conv, imgFactory ); fftConv.convolve(); fftConv = new FFTConvolution<FloatType>( conv, createGaussianKernel( sigma2 ), imgFactory ); fftConv.convolve();
final FFTConvolution< FloatType > fftconv = new FFTConvolution<>( floatImg, kernel ); fftinterval = Intervals.expand( fftinterval, kernel.dimension( d ), d ); final ImgFactory< ComplexFloatType > imgFactory = Util.getArrayOrCellImgFactory( fftinterval, new ComplexFloatType() ); fftconv.setFFTImgFactory( imgFactory ); fftconv.setExecutorService(service); fftconv.convolve(); service.shutdown();
new FFTConvolution< FloatType >( image2, kernel ); c.convolve();
public static < R extends RealType< R > > void computeConvolution( final Img< ComplexFloatType > fftImg, final Img< ComplexFloatType > fftKernel, final RandomAccessibleInterval< R > output, final boolean keepImgFFT, final ExecutorService service ) { final Img< ComplexFloatType > fftconvolved; if ( keepImgFFT ) fftconvolved = fftImg.copy(); else fftconvolved = fftImg; // multiply in place multiplyComplex( fftconvolved, fftKernel ); // inverse FFT in place FFT.complexToRealUnpad( fftconvolved, output, service ); }
this.fftFactory = factory; setExecutorService( service );
new FFTConvolution< FloatType >( image2, kernel ); c.convolve();
final FFTConvolution< FloatType > fftconv = new FFTConvolution<>( floatImg, kernel ); fftinterval = Intervals.expand( fftinterval, kernel.dimension( d ), d ); final ImgFactory< ComplexFloatType > imgFactory = Util.getArrayOrCellImgFactory( fftinterval, new ComplexFloatType() ); fftconv.setFFTImgFactory( imgFactory ); fftconv.setExecutorService(service); fftconv.convolve(); service.shutdown();
new FFTConvolution< FloatType >( image2, kernel ); c.convolve();
multiplyComplex( fftImg, fftKernel );
new FFTConvolution< FloatType >( image2, kernel ); c.convolve();
multiplyComplex( fftImg, fftKernel );
public static ExecutorService createExecutorService() { return FFTConvolution.createExecutorService( Threads.numThreads() ); } }
/** * Compute a Fourier space based convolution The image will be extended by * mirroring with single boundary, the kernel will be zero-padded. The * {@link ImgFactory} for creating the FFT will be identical to the one used * by the 'img' if possible, otherwise an {@link ArrayImgFactory} or * {@link CellImgFactory} depending on the size. * * @param img * - the image * @param kernel * - the convolution kernel * @param output * - the result of the convolution * @param service * - service providing threads for multi-threading */ public FFTConvolution( final Img< R > img, final Img< R > kernel, final RandomAccessibleInterval< R > output, final ExecutorService service ) { this( img, kernel, output, getFFTFactory( img ), service ); }
new FFTConvolution< FloatType >( image2, kernel ); c.convolve();
multiplyComplex( fftconvolved, fftKernel );
public DeconViews( final Collection< DeconView > input, final ExecutorService service ) { this.views = new ArrayList<>(); this.views.addAll( input ); this.service = FFTConvolution.createExecutorService( Threads.numThreads() ); if ( ThreadPoolExecutor.class.isInstance( service ) ) this.numThreads = ((ThreadPoolExecutor)service).getMaximumPoolSize(); else this.numThreads = Threads.numThreads(); final RandomAccessibleInterval< ? > firstImg = input.iterator().next().getImage(); final long[] dim = new long[ firstImg.numDimensions() ]; firstImg.dimensions( dim ); for ( final DeconView view : views ) for ( int d = 0; d < dim.length; ++d ) if ( dim[ d ] != view.getImage().dimension( d ) || dim[ d ] != view.getWeight().dimension( d ) ) throw new RuntimeException( "Dimensions of the input images & weights do not match." ); this.dimensions = new FinalDimensions( dim ); // init the psfs for ( final DeconView view : views ) view.getPSF().init( this, view.getBlockSize() ); }