/*- * #%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.deconvolution; import java.util.ArrayList; import java.util.Vector; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import mpicbg.spim.io.IOFunctions; import net.imglib2.Cursor; import net.imglib2.RandomAccess; import net.imglib2.img.Img; import net.imglib2.type.Type; import spim.Threads; import spim.process.fusion.FusionHelper; import spim.process.fusion.ImagePortion; /** * Mirrors an n-dimensional image along an axis (one of the dimensions). * The calculation is performed in-place and multithreaded. * * @author Stephan Preibisch (stephan.preibisch@gmx.de) */ public class Mirror { /** * @param image - The {@link Img} to mirror * @param dimension - The axis to mirror (e.g. 0->x-Axis->horizontally, 1->y-axis->vertically) * @param numThreads - number of threads */ public static < T extends Type< T > > boolean mirror( final Img< T > image, final int dimension, final int numThreads ) { final int n = image.numDimensions(); // divide the image into chunks final long imageSize = image.size(); final Vector< ImagePortion > portions = FusionHelper.divideIntoPortions( imageSize, numThreads * 4 ); final long maxMirror = image.dimension( dimension ) - 1; final long sizeMirrorH = image.dimension( dimension ) / 2; // set up executor service final ExecutorService taskExecutor = Executors.newFixedThreadPool( Threads.numThreads() ); final ArrayList< Callable< Void > > tasks = new ArrayList< Callable< Void > >(); for ( final ImagePortion portion : portions ) { tasks.add( new Callable< Void >() { @Override public Void call() throws Exception { final Cursor< T > cursorIn = image.localizingCursor(); final RandomAccess< T > cursorOut = image.randomAccess(); final T temp = image.firstElement().createVariable(); final long[] position = new long[ n ]; // set the cursorIn to right offset final long startPosition = portion.getStartPosition(); final long loopSize = portion.getLoopSize(); if ( startPosition > 0 ) cursorIn.jumpFwd( startPosition ); // iterate over all pixels, if they are above the middle switch them with their counterpart // from the other half in the respective dimension for ( long i = 0; i < loopSize; ++i ) { cursorIn.fwd(); cursorIn.localize( position ); if ( position[ dimension ] <= sizeMirrorH ) { // set the localizable to the correct mirroring position position[ dimension ] = maxMirror - position[ dimension ]; cursorOut.setPosition( position ); // do a triangle switching final T in = cursorIn.get(); final T out = cursorOut.get(); temp.set( in ); in.set( out ); out.set( temp ); } } return null; } }); } try { // invokeAll() returns when all tasks are complete taskExecutor.invokeAll( tasks ); } catch ( final InterruptedException e ) { IOFunctions.println( "Failed to compute downsampling: " + e ); e.printStackTrace(); return false; } taskExecutor.shutdown(); return true; } }