diff --git a/src/main/java/plugins/adufour/projection/Projection.java b/src/main/java/plugins/adufour/projection/Projection.java index 6e85f6af86e56e5c12124dc545874309a42f6030..78e98bad685966c5bdd81c731cf6458120eade59 100644 --- a/src/main/java/plugins/adufour/projection/Projection.java +++ b/src/main/java/plugins/adufour/projection/Projection.java @@ -3,10 +3,9 @@ package plugins.adufour.projection; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.List; import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; import icy.image.IcyBufferedImage; import icy.main.Icy; @@ -15,10 +14,11 @@ import icy.plugin.PluginLauncher; import icy.plugin.PluginLoader; import icy.roi.ROI; import icy.sequence.Sequence; -import icy.sequence.SequenceUtil; import icy.system.SystemUtil; +import icy.system.thread.Processor; import icy.type.DataType; import icy.type.collection.array.Array1DUtil; +import icy.util.OMEUtil; import plugins.adufour.blocks.lang.Block; import plugins.adufour.blocks.util.VarList; import plugins.adufour.ezplug.EzPlug; @@ -86,12 +86,12 @@ public class Projection extends EzPlug implements Block, EzStoppable switch (projectionDir.getValue()) { case T: - output.setValue( - tProjection(input.getValue(true), projectionType.getValue(), true, restrictToROI.getValue())); + output.setValue(tProjection(input.getValue(true), projectionType.getValue(), true, + restrictToROI.getValue().booleanValue())); break; case Z: - output.setValue( - zProjection(input.getValue(true), projectionType.getValue(), true, restrictToROI.getValue())); + output.setValue(zProjection(input.getValue(true), projectionType.getValue(), true, + restrictToROI.getValue().booleanValue())); break; default: throw new UnsupportedOperationException( @@ -105,7 +105,22 @@ public class Projection extends EzPlug implements Block, EzStoppable @Override public void clean() { + // + } + /** + * Performs a Z projection of the input sequence using the specified algorithm. If the sequence + * is already 2D, then a copy of the sequence is returned + * + * @param in + * the sequence to project + * @param projection + * the type of projection to perform (see {@link ProjectionType} enumeration) + * @return the projected sequence + */ + public static Sequence zProjection(final Sequence in, final ProjectionType projection) + { + return zProjection(in, projection, true, false); } /** @@ -117,7 +132,7 @@ public class Projection extends EzPlug implements Block, EzStoppable * @param projection * the type of projection to perform (see {@link ProjectionType} enumeration) * @param multiThread - * true if the process should be multi-threaded + * deprecated (there is not reason to not use it) * @return the projected sequence */ public static Sequence zProjection(final Sequence in, final ProjectionType projection, boolean multiThread) @@ -134,7 +149,7 @@ public class Projection extends EzPlug implements Block, EzStoppable * @param projection * the type of projection to perform (see {@link ProjectionType} enumeration) * @param multiThread - * true if the process should be multi-threaded + * deprecated (there is not reason to not use it) * @param restrictToROI * <code>true</code> projects only data located within the sequence ROI, * <code>false</code> projects the entire data set @@ -143,331 +158,328 @@ public class Projection extends EzPlug implements Block, EzStoppable public static Sequence zProjection(final Sequence in, final ProjectionType projection, boolean multiThread, boolean restrictToROI) { - final int depth = in.getSizeZ(); - if (depth == 1 && !restrictToROI) - return SequenceUtil.getCopy(in); - - final Sequence out = new Sequence(projection.name() + " projection of " + in.getName()); - out.copyMetaDataFrom(in, false); + final Sequence out = new Sequence(OMEUtil.createOMEXMLMetadata(in.getOMEXMLMetadata()), + projection.name() + " projection of " + in.getName()); final int width = in.getSizeX(); final int height = in.getSizeY(); + final int depth = in.getSizeZ(); final int frames = in.getSizeT(); final int channels = in.getSizeC(); final DataType dataType = in.getDataType_(); final Collection<ROI> rois = in.getROISet(); final boolean processROI = restrictToROI && (rois.size() > 0); - final int cpus = SystemUtil.getNumberOfCPUs(); - ExecutorService service = multiThread ? Executors.newFixedThreadPool(cpus) - : Executors.newSingleThreadExecutor(); - ArrayList<Future<?>> futures = new ArrayList<Future<?>>(); + final Processor processor = new Processor(Math.max(1024, height), SystemUtil.getNumberOfCPUs()); + final List<Future<?>> futures = new ArrayList<Future<?>>(); for (int frame = 0; frame < frames; frame++) { - if (Thread.currentThread().isInterrupted()) - { - // stop all task now - service.shutdownNow(); - break; - } - final int t = frame; // set new image in result sequence - out.setImage(t, 0, new IcyBufferedImage(width, height, channels, dataType)); + final IcyBufferedImage resultImg = new IcyBufferedImage(width, height, channels, dataType); + // to optimize image access in main loop ! + final IcyBufferedImage[] images = in.getImages(t).toArray(new IcyBufferedImage[0]); for (int channel = 0; channel < channels; channel++) { final int c = channel; - // to optimize image access in main loop ! - final IcyBufferedImage[] imagesZ = in.getImages(t).toArray(new IcyBufferedImage[0]); + // fast access to result pixel data for this channel + final Object resultData = resultImg.getDataXY(c); - futures.add(service.submit(new Runnable() + try { - @Override - public void run() + for (int line = 0; line < height; line++) { - final IcyBufferedImage resultImg = out.getImage(t, 0); - final Object resultData = resultImg.getDataXY(c); - int offset = 0; + final int y = line; - for (int y = 0; y < height; y++) + futures.add(processor.submit(new Runnable() { - for (int x = 0; x < width; x++, offset++) + @Override + public void run() { - double[] stackPixels = new double[depth]; - int nbPixel = 0; + double[] pixelStack = new double[depth]; + int offset = y * width; - for (int z = 0; z < depth; z++) + for (int x = 0; x < width; x++, offset++) { - boolean processPixel; + int nbPixel = 0; - if (processROI) + for (int z = 0; z < depth; z++) { - processPixel = false; + boolean processPixel; - for (ROI roi : rois) + if (processROI) { - if (roi.contains(x, y, z, t, c)) + processPixel = false; + + for (ROI roi : rois) { - processPixel = true; - break; + if (roi.contains(x, y, z, t, c)) + { + processPixel = true; + break; + } } } - } - else - processPixel = true; + else + processPixel = true; - if (processPixel) - stackPixels[nbPixel++] = imagesZ[z].getData(x, y, c); - } + if (processPixel) + pixelStack[nbPixel++] = images[z].getData(x, y, c); + } - if (nbPixel == 0) - continue; + // no pixel processed here ? --> next + if (nbPixel == 0) + continue; - // adjust pixel array size if needed - stackPixels = Arrays.copyOf(stackPixels, nbPixel); + final double[] pixels; - double result = 0d; + // adjust pixel array size if needed + if (pixelStack.length > nbPixel) + pixels = Arrays.copyOf(pixelStack, nbPixel); + else + pixels = pixelStack; - switch (projection) - { - case MAX: - result = ArrayMath.max(stackPixels); - break; - case MEAN: - result = ArrayMath.mean(stackPixels); - break; - case MED: - result = ArrayMath.median(stackPixels, false); - break; - case MIN: - result = ArrayMath.min(stackPixels); - break; - case STD: - result = ArrayMath.std(stackPixels, true); - break; - case SATSUM: - result = ArrayMath.sum(stackPixels); - break; - default: - throw new UnsupportedOperationException( - projection + " intensity projection not implemented"); - } + double result = 0d; - // set result in data array - Array1DUtil.setValue(resultData, offset, dataType, result); - } + switch (projection) + { + case MAX: + result = ArrayMath.max(pixels); + break; + case MEAN: + result = ArrayMath.mean(pixels); + break; + case MED: + result = ArrayMath.median(pixels, false); + break; + case MIN: + result = ArrayMath.min(pixels); + break; + case STD: + result = ArrayMath.std(pixels, true); + break; + case SATSUM: + result = ArrayMath.sum(pixels); + break; + default: + throw new UnsupportedOperationException( + projection + " intensity projection not implemented"); + } - // task interrupted ? - if (Thread.currentThread().isInterrupted()) - { - // propagate partial changes and stop here - resultImg.setDataXY(c, resultData); - return; + // set result in data array + Array1DUtil.setValue(resultData, offset, dataType, result); + } } - } - - // data changed and cache update - resultImg.setDataXY(c, resultData); + })); } - })); - } - } - - try - { - for (Future<?> future : futures) - future.get(); - } - catch (InterruptedException e) - { - // ignore - service.shutdownNow(); - } - catch (Exception e) - { - throw new RuntimeException(e); - } - - service.shutdown(); - - // Copy color map information - for (int c = 0; c < in.getSizeC(); c++) - out.getColorModel().setColorMap(c, in.getColorMap(c), true); - - return out; - } - - /** - * Performs a Z projection of the input sequence using the specified algorithm. If the sequence - * is already 2D, then a copy of the sequence is returned - * - * @param in - * the sequence to project - * @param projection - * the type of projection to perform (see {@link ProjectionType} enumeration) - * @param multiThread - * true if the process should be multi-threaded - * @param restrictToROI - * <code>true</code> projects only data located within the sequence ROI, - * <code>false</code> projects the entire data set - * @return the projected sequence - */ - public static Sequence zProjection_(final Sequence in, final ProjectionType projection, boolean multiThread, - boolean restrictToROI) - { - final int depth = in.getSizeZ(); - if (depth == 1 && !restrictToROI) - return SequenceUtil.getCopy(in); - - final Sequence out = new Sequence(projection.name() + " projection of " + in.getName()); - out.copyMetaDataFrom(in, false); - - final int width = in.getSizeX(); - final int height = in.getSizeY(); - final int frames = in.getSizeT(); - final int channels = in.getSizeC(); - final DataType dataType = in.getDataType_(); - - final Collection<ROI> rois = in.getROISet(); - final boolean processROI = restrictToROI && rois.size() > 0; - - int cpus = SystemUtil.getNumberOfCPUs(); - int chunkSize = width * height / cpus; - final int[] minOffsets = new int[cpus]; - final int[] maxOffsets = new int[cpus]; - for (int cpu = 0; cpu < cpus; cpu++) - { - minOffsets[cpu] = chunkSize * cpu; - maxOffsets[cpu] = chunkSize * (cpu + 1); - } - // NB: the last chunk must include the remaining pixels (in case rounding off occurs) - maxOffsets[cpus - 1] = width * height; - ExecutorService service = multiThread ? Executors.newFixedThreadPool(cpus) - : Executors.newSingleThreadExecutor(); - ArrayList<Future<?>> futures = new ArrayList<Future<?>>(channels * frames * cpus); - - for (int frame = 0; frame < frames; frame++) - { - final int t = frame; - - if (Thread.currentThread().isInterrupted()) - break; - - out.setImage(t, 0, new IcyBufferedImage(width, height, channels, dataType)); - - for (int channel = 0; channel < channels; channel++) - { - final int c = channel; - final Object[] in_Z_XY = (Object[]) in.getDataXYZ(t, c); - final Object out_Z_XY = out.getDataXY(t, 0, c); - - for (int cpu = 0; cpu < cpus; cpu++) + // wait for completion for tasks + for (Future<?> future : futures) + future.get(); + } + catch (RejectedExecutionException e) { - final int minOffset = minOffsets[cpu]; - final int maxOffset = maxOffsets[cpu]; - - futures.add(service.submit(new Runnable() - { - @Override - public void run() - { - double[] buffer = new double[depth]; - double[] dataToProject = null; - - for (int offset = minOffset; offset < maxOffset; offset++) - { - if (processROI) - { - int x = offset % width; - int y = offset / width; - - int nbValues = 0; - - for (int z = 0; z < depth; z++) - for (ROI roi : rois) - if (roi.contains(x, y, z, t, c)) - { - buffer[nbValues++] = Array1DUtil.getValue(in_Z_XY[z], offset, dataType); - break; - } - - if (nbValues == 0) - continue; - - dataToProject = (nbValues == buffer.length) ? buffer - : Arrays.copyOf(buffer, nbValues); - } - else - { - for (int z = 0; z < depth; z++) - buffer[z] = Array1DUtil.getValue(in_Z_XY[z], offset, dataType); - dataToProject = buffer; - } - - switch (projection) - { - case MAX: - Array1DUtil.setValue(out_Z_XY, offset, dataType, ArrayMath.max(dataToProject)); - break; - case MEAN: - Array1DUtil.setValue(out_Z_XY, offset, dataType, ArrayMath.mean(dataToProject)); - break; - case MED: - Array1DUtil.setValue(out_Z_XY, offset, dataType, - ArrayMath.median(dataToProject, false)); - break; - case MIN: - Array1DUtil.setValue(out_Z_XY, offset, dataType, ArrayMath.min(dataToProject)); - break; - case STD: - Array1DUtil.setValue(out_Z_XY, offset, dataType, - ArrayMath.std(dataToProject, true)); - break; - case SATSUM: - Array1DUtil.setValue(out_Z_XY, offset, dataType, - Math.min(ArrayMath.sum(dataToProject), dataType.getMaxValue())); - break; - default: - throw new UnsupportedOperationException( - projection + " intensity projection not implemented"); - } - } // offset - } - })); + // mean that we were interrupted + processor.shutdownNow(); + } + catch (InterruptedException e) + { + // ignore + processor.shutdownNow(); + } + catch (Exception e) + { + throw new RuntimeException(e); } + + // data changed and cache update + resultImg.setDataXY(c, resultData); } - } - try - { - for (Future<?> future : futures) - future.get(); - } - catch (InterruptedException iE) - { - Thread.currentThread().interrupt(); - } - catch (ExecutionException eE) - { - throw new RuntimeException(eE); + // set image in sequence + out.setImage(t, 0, resultImg); } - service.shutdown(); + processor.shutdown(); // Copy color map information for (int c = 0; c < in.getSizeC(); c++) out.getColorModel().setColorMap(c, in.getColorMap(c), true); - out.dataChanged(); - return out; } + // /** + // * Performs a Z projection of the input sequence using the specified algorithm. If the sequence + // * is already 2D, then a copy of the sequence is returned + // * + // * @param in + // * the sequence to project + // * @param projection + // * the type of projection to perform (see {@link ProjectionType} enumeration) + // * @param multiThread + // * true if the process should be multi-threaded + // * @param restrictToROI + // * <code>true</code> projects only data located within the sequence ROI, + // * <code>false</code> projects the entire data set + // * @return the projected sequence + // */ + // public static Sequence zProjection_(final Sequence in, final ProjectionType projection, boolean multiThread, + // boolean restrictToROI) + // { + // final int depth = in.getSizeZ(); + // if (depth == 1 && !restrictToROI) + // return SequenceUtil.getCopy(in); + // + // final Sequence out = new Sequence(projection.name() + " projection of " + in.getName()); + // out.copyMetaDataFrom(in, false); + // + // final int width = in.getSizeX(); + // final int height = in.getSizeY(); + // final int frames = in.getSizeT(); + // final int channels = in.getSizeC(); + // final DataType dataType = in.getDataType_(); + // + // final Collection<ROI> rois = in.getROISet(); + // final boolean processROI = restrictToROI && rois.size() > 0; + // + // int cpus = SystemUtil.getNumberOfCPUs(); + // int chunkSize = width * height / cpus; + // final int[] minOffsets = new int[cpus]; + // final int[] maxOffsets = new int[cpus]; + // for (int cpu = 0; cpu < cpus; cpu++) + // { + // minOffsets[cpu] = chunkSize * cpu; + // maxOffsets[cpu] = chunkSize * (cpu + 1); + // } + // // NB: the last chunk must include the remaining pixels (in case rounding off occurs) + // maxOffsets[cpus - 1] = width * height; + // + // ExecutorService service = multiThread ? Executors.newFixedThreadPool(cpus) + // : Executors.newSingleThreadExecutor(); + // ArrayList<Future<?>> futures = new ArrayList<Future<?>>(channels * frames * cpus); + // + // for (int frame = 0; frame < frames; frame++) + // { + // final int t = frame; + // + // if (Thread.currentThread().isInterrupted()) + // break; + // + // out.setImage(t, 0, new IcyBufferedImage(width, height, channels, dataType)); + // + // for (int channel = 0; channel < channels; channel++) + // { + // final int c = channel; + // final Object[] in_Z_XY = (Object[]) in.getDataXYZ(t, c); + // final Object out_Z_XY = out.getDataXY(t, 0, c); + // + // for (int cpu = 0; cpu < cpus; cpu++) + // { + // final int minOffset = minOffsets[cpu]; + // final int maxOffset = maxOffsets[cpu]; + // + // futures.add(service.submit(new Runnable() + // { + // @Override + // public void run() + // { + // double[] buffer = new double[depth]; + // double[] dataToProject = null; + // + // for (int offset = minOffset; offset < maxOffset; offset++) + // { + // if (processROI) + // { + // int x = offset % width; + // int y = offset / width; + // + // int nbValues = 0; + // + // for (int z = 0; z < depth; z++) + // for (ROI roi : rois) + // if (roi.contains(x, y, z, t, c)) + // { + // buffer[nbValues++] = Array1DUtil.getValue(in_Z_XY[z], offset, dataType); + // break; + // } + // + // if (nbValues == 0) + // continue; + // + // dataToProject = (nbValues == buffer.length) ? buffer + // : Arrays.copyOf(buffer, nbValues); + // } + // else + // { + // for (int z = 0; z < depth; z++) + // buffer[z] = Array1DUtil.getValue(in_Z_XY[z], offset, dataType); + // dataToProject = buffer; + // } + // + // switch (projection) + // { + // case MAX: + // Array1DUtil.setValue(out_Z_XY, offset, dataType, ArrayMath.max(dataToProject)); + // break; + // case MEAN: + // Array1DUtil.setValue(out_Z_XY, offset, dataType, ArrayMath.mean(dataToProject)); + // break; + // case MED: + // Array1DUtil.setValue(out_Z_XY, offset, dataType, + // ArrayMath.median(dataToProject, false)); + // break; + // case MIN: + // Array1DUtil.setValue(out_Z_XY, offset, dataType, ArrayMath.min(dataToProject)); + // break; + // case STD: + // Array1DUtil.setValue(out_Z_XY, offset, dataType, + // ArrayMath.std(dataToProject, true)); + // break; + // case SATSUM: + // Array1DUtil.setValue(out_Z_XY, offset, dataType, + // Math.min(ArrayMath.sum(dataToProject), dataType.getMaxValue())); + // break; + // default: + // throw new UnsupportedOperationException( + // projection + " intensity projection not implemented"); + // } + // } // offset + // } + // })); + // } + // } + // } + // + // try + // { + // for (Future<?> future : futures) + // future.get(); + // } + // catch (InterruptedException iE) + // { + // Thread.currentThread().interrupt(); + // } + // catch (ExecutionException eE) + // { + // throw new RuntimeException(eE); + // } + // + // service.shutdown(); + // + // // Copy color map information + // for (int c = 0; c < in.getSizeC(); c++) + // out.getColorModel().setColorMap(c, in.getColorMap(c), true); + // + // out.dataChanged(); + // + // return out; + // } + /** * Performs a T projection of the input sequence using the specified algorithm. If the sequence * has only one time point, then a copy of the sequence is returned @@ -503,159 +515,320 @@ public class Projection extends EzPlug implements Block, EzStoppable public static Sequence tProjection(final Sequence in, final ProjectionType projection, boolean multiThread, boolean restrictToROI) { - final int frames = in.getSizeT(); - if (frames == 1 && !restrictToROI) - return SequenceUtil.getCopy(in); - - final Sequence out = new Sequence(projection.name() + " projection of " + in.getName()); - out.copyMetaDataFrom(in, false); + final Sequence out = new Sequence(OMEUtil.createOMEXMLMetadata(in.getOMEXMLMetadata()), + projection.name() + " projection of " + in.getName()); final int width = in.getSizeX(); final int height = in.getSizeY(); final int depth = in.getSizeZ(); + final int frames = in.getSizeT(); final int channels = in.getSizeC(); final DataType dataType = in.getDataType_(); final Collection<ROI> rois = in.getROISet(); final boolean processROI = restrictToROI && (rois.size() > 0); - final int cpus = SystemUtil.getNumberOfCPUs(); - ExecutorService service = multiThread ? Executors.newFixedThreadPool(cpus) - : Executors.newSingleThreadExecutor(); - ArrayList<Future<?>> futures = new ArrayList<Future<?>>(); + final Processor processor = new Processor(Math.max(1024, height), SystemUtil.getNumberOfCPUs()); + final List<Future<?>> futures = new ArrayList<Future<?>>(); + + // to optimize image access in main loop ! + final IcyBufferedImage[] images = new IcyBufferedImage[depth * frames]; + for (int z = 0; z < depth; z++) + for (int t = 0; t < frames; t++) + images[(z * frames) + t] = in.getImage(t, z); for (int slice = 0; slice < depth; slice++) { - if (Thread.currentThread().isInterrupted()) - { - // stop all task now - service.shutdownNow(); - break; - } - final int z = slice; + final int imgOff = z * frames; // set new image in result sequence - out.setImage(0, z, new IcyBufferedImage(width, height, channels, dataType)); + final IcyBufferedImage resultImg = new IcyBufferedImage(width, height, channels, dataType); for (int channel = 0; channel < channels; channel++) { final int c = channel; + // fast access to result pixel data for this channel + final Object resultData = resultImg.getDataXY(c); - futures.add(service.submit(new Runnable() + try { - @Override - public void run() + for (int line = 0; line < height; line++) { - final IcyBufferedImage resultImg = out.getImage(0, z); - final Object resultData = resultImg.getDataXY(c); - int offset = 0; + final int y = line; - for (int y = 0; y < height; y++) + futures.add(processor.submit(new Runnable() { - for (int x = 0; x < width; x++, offset++) + @Override + public void run() { - double[] framePixels = new double[frames]; - int nbPixel = 0; + double[] pixelFrames = new double[frames]; + int offset = y * width; - for (int t = 0; t < frames; t++) + for (int x = 0; x < width; x++, offset++) { - boolean processPixel; + int nbPixel = 0; - if (processROI) + for (int t = 0; t < frames; t++) { - processPixel = false; + boolean processPixel; - for (ROI roi : rois) + if (processROI) { - if (roi.contains(x, y, z, t, c)) + processPixel = false; + + for (ROI roi : rois) { - processPixel = true; - break; + if (roi.contains(x, y, z, t, c)) + { + processPixel = true; + break; + } } } + else + processPixel = true; + + if (processPixel) + pixelFrames[nbPixel++] = images[imgOff + t].getData(x, y, c); } - else - processPixel = true; - if (processPixel) - framePixels[nbPixel++] = in.getData(t, z, c, y, x); - } + // no pixel processed here ? --> next + if (nbPixel == 0) + continue; - if (nbPixel == 0) - continue; + final double[] pixels; - // adjust pixel array size if needed - framePixels = Arrays.copyOf(framePixels, nbPixel); + // adjust pixel array size if needed + if (pixelFrames.length > nbPixel) + pixels = Arrays.copyOf(pixelFrames, nbPixel); + else + pixels = pixelFrames; - double result = 0d; + double result = 0d; - switch (projection) - { - case MAX: - result = ArrayMath.max(framePixels); - break; - case MEAN: - result = ArrayMath.mean(framePixels); - break; - case MED: - result = ArrayMath.median(framePixels, false); - break; - case MIN: - result = ArrayMath.min(framePixels); - break; - case STD: - result = ArrayMath.std(framePixels, true); - break; - case SATSUM: - result = ArrayMath.sum(framePixels); - break; - default: - throw new UnsupportedOperationException( - projection + " intensity projection not implemented"); - } + switch (projection) + { + case MAX: + result = ArrayMath.max(pixels); + break; + case MEAN: + result = ArrayMath.mean(pixels); + break; + case MED: + result = ArrayMath.median(pixels, false); + break; + case MIN: + result = ArrayMath.min(pixels); + break; + case STD: + result = ArrayMath.std(pixels, true); + break; + case SATSUM: + result = ArrayMath.sum(pixels); + break; + default: + throw new UnsupportedOperationException( + projection + " intensity projection not implemented"); + } - // set result in data array - Array1DUtil.setValue(resultData, offset, dataType, result); + // set result in data array + Array1DUtil.setValue(resultData, offset, dataType, result); + } } + })); + } - // task interrupted ? - if (Thread.currentThread().isInterrupted()) - { - // propagate partial changes and stop here - resultImg.setDataXY(c, resultData); - return; - } - } + // wait for completion for tasks + for (Future<?> future : futures) + future.get(); + } + catch (RejectedExecutionException e) + { + // mean that we were interrupted + processor.shutdownNow(); + } + catch (InterruptedException e) + { + // ignore + processor.shutdownNow(); + } + catch (Exception e) + { + throw new RuntimeException(e); + } - // data changed and cache update - resultImg.setDataXY(c, resultData); - } - })); + // data changed and cache update + resultImg.setDataXY(c, resultData); } - } - try - { - for (Future<?> future : futures) - future.get(); - } - catch (InterruptedException e) - { - service.shutdownNow(); - } - catch (Exception e) - { - throw new RuntimeException(e); + // set image in sequence + out.setImage(0, z, resultImg); } - service.shutdown(); + processor.shutdown(); // Copy color map information for (int c = 0; c < in.getSizeC(); c++) out.getColorModel().setColorMap(c, in.getColorMap(c), true); return out; + + /* + * + * + * final Sequence out = new Sequence(OMEUtil.createOMEXMLMetadata(in.getOMEXMLMetadata()), + * projection.name() + " projection of " + in.getName()); + * + * final int width = in.getSizeX(); + * final int height = in.getSizeY(); + * final int depth = in.getSizeZ(); + * final int frames = in.getSizeT(); + * final int channels = in.getSizeC(); + * final DataType dataType = in.getDataType_(); + * + * final Collection<ROI> rois = in.getROISet(); + * final boolean processROI = restrictToROI && (rois.size() > 0); + * final int cpus = SystemUtil.getNumberOfCPUs(); + * + * ExecutorService service = multiThread ? Executors.newFixedThreadPool(cpus) + * : Executors.newSingleThreadExecutor(); + * ArrayList<Future<?>> futures = new ArrayList<Future<?>>(); + * + * for (int slice = 0; slice < depth; slice++) + * { + * if (Thread.currentThread().isInterrupted()) + * { + * // stop all task now + * service.shutdownNow(); + * break; + * } + * + * final int z = slice; + * + * // set new image in result sequence + * out.setImage(0, z, new IcyBufferedImage(width, height, channels, dataType)); + * + * for (int channel = 0; channel < channels; channel++) + * { + * final int c = channel; + * + * futures.add(service.submit(new Runnable() + * { + * + * @Override + * public void run() + * { + * final IcyBufferedImage resultImg = out.getImage(0, z); + * final Object resultData = resultImg.getDataXY(c); + * int offset = 0; + * + * for (int y = 0; y < height; y++) + * { + * for (int x = 0; x < width; x++, offset++) + * { + * double[] framePixels = new double[frames]; + * int nbPixel = 0; + * + * for (int t = 0; t < frames; t++) + * { + * boolean processPixel; + * + * if (processROI) + * { + * processPixel = false; + * + * for (ROI roi : rois) + * { + * if (roi.contains(x, y, z, t, c)) + * { + * processPixel = true; + * break; + * } + * } + * } + * else + * processPixel = true; + * + * if (processPixel) + * framePixels[nbPixel++] = in.getData(t, z, c, y, x); + * } + * + * if (nbPixel == 0) + * continue; + * + * // adjust pixel array size if needed + * framePixels = Arrays.copyOf(framePixels, nbPixel); + * + * double result = 0d; + * + * switch (projection) + * { + * case MAX: + * result = ArrayMath.max(framePixels); + * break; + * case MEAN: + * result = ArrayMath.mean(framePixels); + * break; + * case MED: + * result = ArrayMath.median(framePixels, false); + * break; + * case MIN: + * result = ArrayMath.min(framePixels); + * break; + * case STD: + * result = ArrayMath.std(framePixels, true); + * break; + * case SATSUM: + * result = ArrayMath.sum(framePixels); + * break; + * default: + * throw new UnsupportedOperationException( + * projection + " intensity projection not implemented"); + * } + * + * // set result in data array + * Array1DUtil.setValue(resultData, offset, dataType, result); + * } + * + * // task interrupted ? + * if (Thread.currentThread().isInterrupted()) + * { + * // propagate partial changes and stop here + * resultImg.setDataXY(c, resultData); + * return; + * } + * } + * + * // data changed and cache update + * resultImg.setDataXY(c, resultData); + * } + * })); + * } + * } + * + * try + * { + * for (Future<?> future : futures) + * future.get(); + * } + * catch (InterruptedException e) + * { + * service.shutdownNow(); + * } + * catch (Exception e) + * { + * throw new RuntimeException(e); + * } + * + * service.shutdown(); + * + * // Copy color map information + * for (int c = 0; c < in.getSizeC(); c++) + * out.getColorModel().setColorMap(c, in.getColorMap(c), true); + * + * return out; + */ } @Override