Package org.cellprofiler.imageset

Source Code of org.cellprofiler.imageset.ImagePlaneDetailsStack

/**
* CellProfiler is distributed under the GNU General Public License.
* See the accompanying file LICENSE for details.
*
* Copyright (c) 2003-2009 Massachusetts Institute of Technology
* Copyright (c) 2009-2014 Broad Institute
* All rights reserved.
*
* Please see the AUTHORS file for credits.
*
* Website: http://www.cellprofiler.org
*/

package org.cellprofiler.imageset;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

import ome.xml.model.Annotation;
import ome.xml.model.Image;
import ome.xml.model.LongAnnotation;
import ome.xml.model.OME;
import ome.xml.model.Pixels;
import ome.xml.model.Plane;
import ome.xml.model.StructuredAnnotations;
import ome.xml.model.TiffData;
import ome.xml.model.UUID;
import ome.xml.model.enums.DimensionOrder;
import ome.xml.model.primitives.NonNegativeInteger;
import ome.xml.model.primitives.PositiveInteger;
import net.imglib2.meta.Axes;
import net.imglib2.meta.AxisType;
import net.imglib2.meta.TypedAxis;


/**
* @author Lee Kamentsky
*
* A PlaneStack of ImagePlaneDetails. This class is mostly
* here to give a class marker that can be used by
* the StackAdapter filter predicate's getInputClass method.
*/
public class ImagePlaneDetailsStack extends PlaneStack<ImagePlaneDetails> {
 
  /**
   * The "description" field for a plane's series (or image index).
   */
  final static public String SERIES_ANNOTATION_DESCRIPTION = "Series";
  /**
   * The "description" field for a plane's channel
   */
  final static public String CHANNEL_ANNOTATION_DESCRIPTION = "Channel";
  /**
   * The annotation namepace for the series annotation.
   */
  final static public String ANNOTATION_NAMESPACE = "info://cellprofiler.org/imageset/annotation/2014-04-17";

  final static private NonNegativeInteger NNI_ZERO = new NonNegativeInteger(0);
 
  public ImagePlaneDetailsStack(final TypedAxis... axes){
    super(axes);
  }
  /**
   * Make a one-frame stack
   *
   * @return
   */
  static public ImagePlaneDetailsStack makeMonochromeStack(ImagePlaneDetails plane) {
    ImagePlaneDetailsStack stack = new ImagePlaneDetailsStack(XYAxes);
    stack.add(plane, 0, 0);
    return stack;
  }
  /**
   * Make a color stack with one initial plane
   *
   * @param plane
   * @return a XYC stack containing the plane
   */
  static public ImagePlaneDetailsStack makeColorStack(ImagePlaneDetails plane) {
    ImagePlaneDetailsStack stack = new ImagePlaneDetailsStack(XYCAxes);
    stack.add(plane, 0, 0, 0);
    return stack;
  }
  /**
   * Make a stack of labels matrices with one initial plane
   *
   * @param plane
   * @return an XYO stack containing the plane
   */
  static public ImagePlaneDetailsStack makeObjectsStack(ImagePlaneDetails plane) {
    ImagePlaneDetailsStack stack = new ImagePlaneDetailsStack(XYOAxes);
    stack.add(plane, 0, 0, 0);
    return stack;
   
  }
  public boolean containsKey(String key) {
    for (ImagePlaneDetails ipd:this) {
      if (ipd.containsKey(key)) return true;
    }
    return false;
  }
  public String get(String key) {
    for (ImagePlaneDetails ipd:this) {
      final String value = ipd.get(key);
      if (value != null) return value;
    }
    return null;
  }
 
  /**
   * Add this stack to the OME root.
   *
   * @param ome root of OME schema
   * @param id the ID to use to name the stack.
   */
  public void addToOME(OME ome, final String id) {
    final Image image = new Image();
    image.setID(id);
    final Pixels pixels = new Pixels();
    image.setPixels(pixels);
    ome.addImage(image);
    pixels.setID(String.format("Pixels:%s", id));
    final ImagePlaneDetails firstIPD = iterator().next();
    final Image srcImage = firstIPD.getImagePlane().getSeries().getOMEImage();
    PositiveInteger xSize = new PositiveInteger(1);
    PositiveInteger ySize = new PositiveInteger(1);
    if (srcImage != null) {
      final Pixels srcPixels = srcImage.getPixels();
      xSize = srcPixels.getSizeX();
      ySize = srcPixels.getSizeY();
    }
    pixels.setSizeX(xSize);
    pixels.setSizeY(ySize);
    setDimensionOrder(this, pixels);
    int nPlanes = 1;
    for (int axisIdx=0; axisIdx<numDimensions(); axisIdx++) {
      TypedAxis a = axis(axisIdx);
      final PositiveInteger size = new PositiveInteger(size(axisIdx));
      if (a.type().equals(Axes.Z)) {
        pixels.setSizeZ(size);
      } else if (a.type().equals(Axes.CHANNEL)) {
        pixels.setSizeC(size);
      } else {
        // Both T and ObjectPlane go here
        pixels.setSizeT(size);
      }
      nPlanes = nPlanes * size(axisIdx);
    }
    int [] coords = new int [numDimensions()];
    int c = 0;
    int z = 0;
    int t = 0;
    for (int planeIdx=0; planeIdx < nPlanes; planeIdx++ ) {
      final ImagePlaneDetails ipd = get(coords);
      addOMEPlane(ome, pixels, xSize, ySize, c, z, t, ipd);
     
      // Advance to the next coordinate.
      boolean done = false;
      for (int j=2; (j< coords.length) && ! done; j++) {
        if (coords[j] == size(j)-1) {
          coords[j] = 0;
        } else {
          coords[j]++;
          done = true;
        }
        final AxisType axisType = axis(j).type();
        if (axisType.equals(Axes.CHANNEL) ) {
          c = coords[j];
        } else if (axisType.equals(Axes.Z)) {
          z = coords[j];
        } else {
          t = coords[j];
        }
      }
    }
  }
 
  /**
   * Load the stack from an OME Image
   *
   * @param ome the OME root node
   * @param id the ID of the Image node to load from 
   * @throws URISyntaxException
   */
  public void loadFromOME(OME ome, String id) throws URISyntaxException {
    for (int i=0; i<ome.sizeOfImageList(); i++) {
      Image omeImage = ome.getImage(i);
      if (omeImage.getID().equals(id)) {
        loadFromOMEImage(omeImage);
        return;
      }
    }
    throw new IndexOutOfBoundsException(String.format("Could not find image, \"%s\" in OME-XML", id));
  }
 
  /**
   * Load a stack from an OME Image node
   *
   * @param omeImage
   * @throws URISyntaxException
   */
  private void loadFromOMEImage(Image omeImage) throws URISyntaxException {
    Map<URI, ImageFileDetails> imageFiles = new HashMap<URI, ImageFileDetails>();
    Map<URI, Map<Integer, ImageSeriesDetails>> imageSeries = new HashMap<URI, Map<Integer,ImageSeriesDetails>>();
    final Pixels pixels = omeImage.getPixels();
    int [] coords = new int[numDimensions()];
    for (int planeIdx=0; planeIdx<pixels.sizeOfPlaneList() && planeIdx<pixels.sizeOfTiffDataList(); planeIdx++) {
      final Plane plane = pixels.getPlane(planeIdx);
      final TiffData location = pixels.getTiffData(planeIdx);
      final URI uri = new URI(location.getUUID().getFileName());
      if (! imageFiles.containsKey(uri)) {
        imageFiles.put(uri, new ImageFileDetails(new ImageFile(uri)));
      }
      final ImageFileDetails ifd = imageFiles.get(uri);
      final int series = getLongAnnotationFromPlane(plane, SERIES_ANNOTATION_DESCRIPTION, 0);
      if (! imageSeries.containsKey(uri)) {
        imageSeries.put(uri, new HashMap<Integer, ImageSeriesDetails>());
      }
      Map<Integer, ImageSeriesDetails> idx2Series = imageSeries.get(uri);
      if (! idx2Series.containsKey(series)) {
        idx2Series.put(series, new ImageSeriesDetails(new ImageSeries(ifd.getImageFile(), series), ifd));
      }
      final ImageSeriesDetails isd = idx2Series.get(series);
      final int idx = location.getIFD().getValue();
      final int channel = getLongAnnotationFromPlane(plane, CHANNEL_ANNOTATION_DESCRIPTION, ImagePlane.ALWAYS_MONOCHROME);
      final ImagePlane imagePlane = new ImagePlane(isd.getImageSeries(), idx, channel);
      final ImagePlaneDetails ipd = new ImagePlaneDetails(imagePlane, isd);
      for (int didx=0; didx<numDimensions();didx++) {
        AxisType at = axis(didx).type();
        if (at.equals(Axes.CHANNEL)) {
          coords[didx] = plane.getTheC().getValue();
        } else if (at.equals(Axes.Z)) {
          coords[didx] = plane.getTheZ().getValue();
        } else if (at.equals(Axes.TIME)) {
          coords[didx] = plane.getTheT().getValue();
        } else if (at.equals(OBJECT_PLANE_AXIS_TYPE)) {
          coords[didx] = planeIdx;
        }
      }
      add(ipd, coords);
    }
  }
 
  /**
   * Add an image plane to the "pixels" of an OME image
   *
   * @param ome the root node of the OME document
   * @param pixels add the plane to these pixels
   * @param xSize the size of a plane in the X direction (not definitive)
   * @param ySize the size of a plane in the Y direction
   * @param c the channel index of the plane
   * @param z the z index of the plane
   * @param t the time index of the plane
   * @param ipd the image plane that's the source of the pixels.
   */
  private static void addOMEPlane(OME ome, final Pixels pixels,
      PositiveInteger xSize, PositiveInteger ySize, int c, int z, int t,
      final ImagePlaneDetails ipd) {
    final Plane destPlane = new Plane();
    pixels.addPlane(destPlane);
    int series = 0;
    int channel = ImagePlane.ALWAYS_MONOCHROME;
    final TiffData location = new TiffData();
    final UUID uuid = new UUID();
    location.setPlaneCount(new NonNegativeInteger(1));
    if (ipd != null) {
      final ImagePlane imagePlane = ipd.getImagePlane();
      series = imagePlane.getSeries().getSeries();
      channel = imagePlane.getChannel();
      location.setIFD(new NonNegativeInteger(imagePlane.getIndex()));
      uuid.setFileName(imagePlane.getImageFile().getURI().toString());
      final Plane omePlane = imagePlane.getOMEPlane();
      if (omePlane != null) {
        location.setFirstC(omePlane.getTheC());
        location.setFirstT(omePlane.getTheT());
        location.setFirstZ(omePlane.getTheZ());
      } else {
        location.setFirstC(NNI_ZERO);
        location.setFirstT(NNI_ZERO);
        location.setFirstZ(NNI_ZERO);
       
      }
    } else {
      // A missing plane.
      // This retrieves a URI placeholder for it.
      uuid.setFileName(new ImageFile(xSize.getValue(), ySize.getValue()).getURI().toString());
      location.setIFD(NNI_ZERO);
      location.setFirstC(NNI_ZERO);
      location.setFirstT(NNI_ZERO);
      location.setFirstZ(NNI_ZERO);
    }
    location.setUUID(uuid);
    pixels.addTiffData(location);
    destPlane.setTheC(new NonNegativeInteger(c));
    destPlane.setTheZ(new NonNegativeInteger(z));
    destPlane.setTheT(new NonNegativeInteger(t));
    if (series > 0) {
      addLongAnnotationToPlane(ome, destPlane, SERIES_ANNOTATION_DESCRIPTION, series);
    }
    if (channel != ImagePlane.ALWAYS_MONOCHROME)
      addLongAnnotationToPlane(ome, destPlane, CHANNEL_ANNOTATION_DESCRIPTION, channel);
  }
  /**
   * Read a numeric annotation associated with the given plane
   *
   * @param plane the possibly annotated plane
   * @param description the annotation description
   * @param defaultValue the value to return if the annotation isn't present.
   * @return
   */
  private static int getLongAnnotationFromPlane(Plane plane, String description, int defaultValue) {
    int result = defaultValue;
    for (int annotationRefIdx=0; annotationRefIdx<plane.sizeOfLinkedAnnotationList(); annotationRefIdx++) {
      Annotation a = plane.getLinkedAnnotation(annotationRefIdx);
      if (a.getDescription().equals(description) &&
        a.getNamespace().equals(ANNOTATION_NAMESPACE) &&
        a instanceof LongAnnotation) {
        result = ((LongAnnotation)a).getValue().intValue();
        break;
      }
    }
    return result;
  }
  /**
   * Add an integer annotation to an image plane, such as series or channel
   *
   * @param ome the root node of the document
   * @param plane the plane to be annotated
   * @param description the annotation name
   * @param value the value to assign
   */
  private static void addLongAnnotationToPlane(OME ome, Plane plane, String description, long value) {
    // Non-standard, have to add a "Series" annotation
    //
    // First, see if we have one for this series before
    // creating a new one
    //
    StructuredAnnotations sa = ome.getStructuredAnnotations();
    if (sa == null) {
      ome.setStructuredAnnotations(sa = new StructuredAnnotations());
    }
    LongAnnotation seriesAnnotation = null;
    for (int saIdx=0; saIdx<sa.sizeOfLongAnnotationList(); saIdx++) {
      final LongAnnotation candidate = sa.getLongAnnotation(saIdx);
      if ((candidate.getDescription().equals(description)) &&
        (candidate.getNamespace().equals(ANNOTATION_NAMESPACE)) &&
        (candidate.getValue().equals(value))) {
        seriesAnnotation = candidate;
        break;
      }
    }
    if (seriesAnnotation == null) {
      seriesAnnotation = new LongAnnotation();
      seriesAnnotation.setDescription(description);
      seriesAnnotation.setNamespace(ANNOTATION_NAMESPACE);
      seriesAnnotation.setValue(value);
      seriesAnnotation.setID(String.format("%s/%s/%d", ANNOTATION_NAMESPACE, description, value));
      sa.addLongAnnotation(seriesAnnotation);
    }
    plane.linkAnnotation(seriesAnnotation);
   
  }
  /**
   * @param ipds
   * @param pixels
   */
  private static void setDimensionOrder(final ImagePlaneDetailsStack ipds,
      final Pixels pixels) {
    //
    // Determine the dimension order
    //
    if (ipds.numDimensions() == 2) {
      pixels.setDimensionOrder(DimensionOrder.XYCZT);
    } else {
      final AxisType type = ipds.axis(2).type();
      if (type.equals(Axes.CHANNEL)) {
        if (ipds.numDimensions() == 3) {
          pixels.setDimensionOrder(DimensionOrder.XYCZT);
        } else if (ipds.axis(3).type().equals(Axes.Z)) {
          pixels.setDimensionOrder(DimensionOrder.XYCZT);
        } else {
          pixels.setDimensionOrder(DimensionOrder.XYCTZ);
        }
      } else if (type.equals(Axes.Z)) {
        if (ipds.numDimensions() == 3) {
          pixels.setDimensionOrder(DimensionOrder.XYZCT);
        } else if (ipds.axis(3).type().equals(Axes.CHANNEL)) {
          pixels.setDimensionOrder(DimensionOrder.XYZCT);
        } else {
          pixels.setDimensionOrder(DimensionOrder.XYZTC);
        }
      } else if ((ipds.numDimensions() == 3) || (ipds.axis(3).type().equals(Axes.CHANNEL))) {
        pixels.setDimensionOrder(DimensionOrder.XYTCZ);
      } else {
        pixels.setDimensionOrder(DimensionOrder.XYTZC);
      }
    }
  }
 
}
TOP

Related Classes of org.cellprofiler.imageset.ImagePlaneDetailsStack

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.