/* * Copyright 2010-2015 Institut Pasteur. * * This file is part of Icy. * * Icy 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 3 of the License, or * (at your option) any later version. * * Icy 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 Icy. If not, see <http://www.gnu.org/licenses/>. */ package icy.sequence; import icy.image.IcyBufferedImage; import icy.image.ImageDataIterator; import icy.roi.ROI; import icy.type.DataIterator; import icy.type.DataType; import icy.type.rectangle.Rectangle5D; import icy.type.rectangle.Rectangle5D.Integer; import java.awt.Rectangle; import java.util.NoSuchElementException; /** * Sequence data iterator.<br> * This class permit to use simple iterator to read / write <code>Sequence</code> data<br> * as double in XYCZT <i>([T[Z[C[Y[X}}]]])</i> dimension order.<br> * Whatever is the internal {@link DataType} data is returned and set as double.<br> * <b>If the sequence size or type is modified during iteration the iterator * becomes invalid and can exception can happen.</b> * * @author Stephane */ public class SequenceDataIterator implements DataIterator { protected final Sequence sequence; protected final ROI roi; protected final Rectangle XYBounds; protected final int startC, endC; protected final int startZ, endZ; protected final int startT, endT; protected final boolean inclusive; /** * internals */ protected int c, z, t; protected boolean done; protected ImageDataIterator imageIterator; /** * Create a new SequenceData iterator to iterate data through the specified 5D region * (inclusive). * * @param sequence * Sequence we want to iterate data from * @param bounds5D * the 5D rectangular region we want to iterate */ public SequenceDataIterator(Sequence sequence, Rectangle5D.Integer bounds5D) { super(); this.sequence = sequence; roi = null; imageIterator = null; inclusive = true; if (sequence != null) { final Rectangle5D.Integer bounds = (Integer) bounds5D.createIntersection(sequence.getBounds5D()); XYBounds = (Rectangle) bounds.toRectangle2D(); startZ = bounds.z; endZ = (bounds.z + bounds.sizeZ) - 1; startT = bounds.t; endT = (bounds.t + bounds.sizeT) - 1; startC = bounds.c; endC = (bounds.c + bounds.sizeC) - 1; } else { XYBounds = null; startZ = 0; endZ = 0; startT = 0; endT = 0; startC = 0; endC = 0; } // start iterator reset(); } /** * Create a new SequenceData iterator to iterate data through the specified dimensions * (inclusive). * * @param sequence * Sequence we want to iterate data from * @param XYBounds * XY region to iterate * @param z * Z position (stack) we want to iterate data * @param t * T position (time) we want to iterate data * @param c * C position (channel) we want to iterate data */ public SequenceDataIterator(Sequence sequence, Rectangle XYBounds, int z, int t, int c) { this(sequence, new Rectangle5D.Integer(XYBounds.x, XYBounds.y, z, t, c, (XYBounds.x + XYBounds.width) - 1, (XYBounds.y + XYBounds.height) - 1, 1, 1, 1)); } /** * @deprecated Use {@link #SequenceDataIterator(Sequence, Rectangle5D.Integer)} instead */ @Deprecated public SequenceDataIterator(Sequence sequence, int startX, int endX, int startY, int endY, int startC, int endC, int startZ, int endZ, int startT, int endT) { this(sequence, new Rectangle5D.Integer(startX, startY, startZ, startT, startC, (endX - startX) + 1, (endY - startY) + 1, (endZ - startZ) + 1, (endT - startT) + 1, (endC - startC) + 1)); } /** * @deprecated Use {@link #SequenceDataIterator(Sequence, Rectangle, int, int, int)} instead */ @Deprecated public SequenceDataIterator(Sequence sequence, int startX, int endX, int startY, int endY, int c, int z, int t) { this(sequence, new Rectangle5D.Integer(startX, startY, z, t, c, (endX - startX) + 1, (endY - startY) + 1, 1, 1, 1)); } /** * Create a new SequenceData iterator to iterate data of specified channel. * * @param sequence * Sequence we want to iterate data from * @param z * Z position (stack) we want to iterate data * @param t * T position (time) we want to iterate data * @param c * C position (channel) we want to iterate data */ public SequenceDataIterator(Sequence sequence, int z, int t, int c) { this(sequence, new Rectangle5D.Integer(0, 0, z, t, c, sequence.getSizeX(), sequence.getSizeY(), 1, 1, 1)); } /** * Create a new SequenceData iterator to iterate all data. * * @param sequence * Sequence we want to iterate data from. */ public SequenceDataIterator(Sequence sequence) { this(sequence, new Rectangle5D.Integer(0, 0, 0, 0, 0, sequence.getSizeX(), sequence.getSizeY(), sequence.getSizeZ(), sequence.getSizeT(), sequence.getSizeC())); } /** * Create a new SequenceData iterator to iterate data through the specified ROI. * * @param sequence * Sequence we want to iterate data from. * @param roi * ROI defining the region to iterate. * @param inclusive * If true then all partially contained (intersected) pixels in the ROI are included. * @param z * The specific Z position (slice) we want to iterate or <code>-1</code> to iterate over * the whole ROI Z dimension. * @param t * The specific T position (frame) we want to iterate or <code>-1</code> to iterate over * the whole ROI T dimension. * @param c * The specific C position (channel) we want to iterate or <code>-1</code> to iterate * over the whole ROI C dimension. */ public SequenceDataIterator(Sequence sequence, ROI roi, boolean inclusive, int z, int t, int c) { super(); this.sequence = sequence; this.roi = roi; this.inclusive = inclusive; XYBounds = null; if ((sequence != null) && (roi != null)) { final Rectangle5D bounds5D = roi.getBounds5D(); // force Z position if (z != -1) { bounds5D.setZ(z); bounds5D.setSizeZ(1d); } // force T position if (t != -1) { bounds5D.setT(t); bounds5D.setSizeT(1d); } // force C position if (c != -1) { bounds5D.setC(c); bounds5D.setSizeC(1d); } // get final bounds final Rectangle5D.Integer bounds = (Integer) sequence.getBounds5D().createIntersection(bounds5D); startZ = bounds.z; endZ = (bounds.z + bounds.sizeZ) - 1; startT = bounds.t; endT = (bounds.t + bounds.sizeT) - 1; startC = bounds.c; endC = (bounds.c + bounds.sizeC) - 1; } else { startZ = 0; endZ = 0; startT = 0; endT = 0; startC = 0; endC = 0; } // start iterator reset(); } /** * Create a new SequenceData iterator to iterate data through the specified ROI. * * @param sequence * Sequence we want to iterate data from. * @param roi * ROI defining the region to iterate. * @param inclusive * If true then all partially contained (intersected) pixels in the ROI are included. */ public SequenceDataIterator(Sequence sequence, ROI roi, boolean inclusive) { this(sequence, roi, inclusive, -1, -1, -1); } /** * Create a new SequenceData iterator to iterate data through the specified ROI. * * @param sequence * Sequence we want to iterate data from. * @param roi * ROI defining the region to iterate. */ public SequenceDataIterator(Sequence sequence, ROI roi) { this(sequence, roi, false); } @Override public void reset() { done = (sequence == null) || (startT > endT) || (startZ > endZ) || (startC > endC); if (!done) { t = startT; z = startZ; c = startC; // prepare XY data prepareDataXY(); nextImageifNeeded(); } } /** * Prepare data for XY iteration. */ protected void prepareDataXY() { final IcyBufferedImage img = sequence.getImage(t, z); // get the 2D mask for specified C if (roi != null) { switch (roi.getDimension()) { case 2: // ignore Z, T and C roi informations (wanted for fixed Z, T and C positions) imageIterator = new ImageDataIterator(img, roi.getBooleanMask2D(-1, -1, -1, inclusive), c); break; case 3: // ignore T and C roi informations (wanted for fixed T and C positions) imageIterator = new ImageDataIterator(img, roi.getBooleanMask2D(z, -1, -1, inclusive), c); break; case 4: // ignore C roi information (wanted for fixed C position) imageIterator = new ImageDataIterator(img, roi.getBooleanMask2D(z, t, -1, inclusive), c); break; // assume 5D default: imageIterator = new ImageDataIterator(img, roi.getBooleanMask2D(z, t, c, inclusive), c); } } else imageIterator = new ImageDataIterator(img, XYBounds, c); } @Override public void next() { imageIterator.next(); nextImageifNeeded(); } /** * Advance one image position. */ protected void nextImageifNeeded() { while (imageIterator.done() && !done) { if (++c > endC) { c = startC; if (++z > endZ) { z = startZ; if (++t > endT) { done = true; return; } } } prepareDataXY(); } } @Override public boolean done() { return done; } @Override public double get() { if (done) throw new NoSuchElementException(null); return imageIterator.get(); } @Override public void set(double value) { if (done) throw new NoSuchElementException(null); imageIterator.set(value); } /** * Return current X position. */ public int getPositionX() { if (imageIterator != null) return imageIterator.getPositionX(); return 0; } /** * Return current Y position. */ public int getPositionY() { if (imageIterator != null) return imageIterator.getPositionY(); return 0; } /** * Return current C position. */ public int getPositionC() { return c; } /** * Return current Z position. */ public int getPositionZ() { return z; } /** * Return current T position. */ public int getPositionT() { return t; } }