package gdsc.smlm.results; import java.awt.Rectangle; import com.thoughtworks.xstream.annotations.XStreamOmitField; /*----------------------------------------------------------------------------- * GDSC SMLM Software * * Copyright (C) 2013 Alex Herbert * Genome Damage and Stability Centre * University of Sussex, UK * * 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 3 of the License, or * (at your option) any later version. *---------------------------------------------------------------------------*/ /** * Wraps an image source and allows data to be interlaced within regular blocks. */ public class InterlacedImageSource extends ImageSource { private final int start, size, skip; private final ImageSource imageSource; // Record the number of frames returned from the current block @XStreamOmitField private int counter; /** * Create a new interlaced image source using the given image source * <p> * Note: The input source cannot be aggregated as the data to interlace is assumed to be contiguous from frame 1 * * @param imageSource * The image source of interlaced data (must not be null or an AggregatedImageSource) * @param start * The first frame that contains data * @param size * The number of continuous frames containing data * @param skip * The number of continuous frames to ignore before the next data */ public InterlacedImageSource(ImageSource imageSource, int start, int size, int skip) { super(""); if (imageSource == null) throw new IllegalArgumentException("Image source must not be null"); if (imageSource instanceof AggregatedImageSource) throw new IllegalArgumentException("Image source must not be aggregated"); if (start < 1) throw new IllegalArgumentException("The start frame must be 1 or above"); if (size < 1) throw new IllegalArgumentException("The read size must be 1 or above"); if (skip < 0) throw new IllegalArgumentException("The skip length must be 0 or above"); setName(String.format("Interlaced (%d,%d,%d) %s", start, size, skip, imageSource.getName())); this.imageSource = imageSource; this.start = start; this.size = size; this.skip = skip; } /* * (non-Javadoc) * * @see gdsc.smlm.results.ImageSource#getWidth() */ @Override public int getWidth() { return imageSource.getWidth(); } /* * (non-Javadoc) * * @see gdsc.smlm.results.ImageSource#getHeight() */ @Override public int getHeight() { return imageSource.getHeight(); } /* * (non-Javadoc) * * @see gdsc.smlm.results.ImageSource#getFrames() */ @Override public int getFrames() { return (int) Math.ceil((imageSource.getFrames() - start + 1) * ((double) size / (size + skip))); } /* * (non-Javadoc) * * @see gdsc.smlm.results.ImageSource#getParent() */ @Override public ImageSource getParent() { return imageSource; } /* * (non-Javadoc) * * @see gdsc.smlm.results.ImageSource#getOriginal() */ @Override public ImageSource getOriginal() { return imageSource.getOriginal(); } /* * (non-Javadoc) * * @see gdsc.smlm.results.ResultsSource#openSource() */ @Override protected boolean openSource() { // Assume frame start at 1 and set the intial skip final int initialSkip = (start - 1); counter = -initialSkip; return imageSource.openSource(); } /* * (non-Javadoc) * * @see gdsc.smlm.results.ResultsSource#close() */ @Override public void close() { imageSource.close(); } /* * (non-Javadoc) * * @see gdsc.smlm.results.ImageSource#nextFrame(java.awt.Rectangle) */ @Override protected float[] nextFrame(Rectangle bounds) { // Skip frames until at the start of the next block while (counter < 0) { if (imageSource.next(bounds) == null) return null; counter++; } // Read the next frame in the current block final float[] image = imageSource.next(bounds); // Check if this is the final frame in the current block if (++counter >= size) { counter = -skip; } // Set the frame to the last one read from the source setFrameNumber(imageSource.getStartFrameNumber(), imageSource.getEndFrameNumber()); //System.out.printf("Interlaced %d-%d\n", getStartFrameNumber(), getEndFrameNumber()); return image; } /* * (non-Javadoc) * * @see gdsc.smlm.results.ImageSource#getFrame(int, java.awt.Rectangle) */ @Override protected float[] getFrame(int frame, Rectangle bounds) { if (frame < 1) return null; // Check if the frame is allowed: // Start // | // |----|Block|Skip|Block|Skip|Block|Skip if (frame < start) { return null; } int frameInBlock = (frame - start) % (size + skip); if (frameInBlock >= size) { return null; } return imageSource.get(frame, bounds); } /** * @param frame * @return */ @Override public boolean isValid(int frame) { return imageSource.isValid(frame); } /* * (non-Javadoc) * * @see gdsc.smlm.results.ImageSource#toString() */ @Override public String toString() { return String.format("%s (Interlaced %d,%d,%d)", imageSource.toString(), start, size, skip); } /** * @return The first frame that contains data */ public int getStart() { return start; } /** * @return The number of continuous frames containing data */ public int getSize() { return size; } /** * @return The number of continuous frames to ignore before the next data */ public int getSkip() { return skip; } }