diff --git a/pom.xml b/pom.xml index ac8db6c..e4914ca 100644 --- a/pom.xml +++ b/pom.xml @@ -144,7 +144,7 @@ 0.8.1 0.7.3 - 8.0.0-SNAPSHOT + 7.3.1 diff --git a/src/main/java/ch/epfl/biop/bdv/img/bioformats/BioFormatsHelper.java b/src/main/java/ch/epfl/biop/bdv/img/bioformats/BioFormatsHelper.java index 414a8e3..65933e8 100644 --- a/src/main/java/ch/epfl/biop/bdv/img/bioformats/BioFormatsHelper.java +++ b/src/main/java/ch/epfl/biop/bdv/img/bioformats/BioFormatsHelper.java @@ -202,7 +202,6 @@ public static Length[] getSeriesVoxelSizeAsLengths(IMetadata omeMeta, } protected static AffineTransform3D getSeriesRootTransform(IMetadata omeMeta, - IFormatReader reader, int iSerie, Unit u, // Bioformats location fix double[] positionPreTransformMA, double[] positionPostTransformMA, @@ -236,7 +235,7 @@ protected static AffineTransform3D getSeriesRootTransform(IMetadata omeMeta, voxSizePostTransform.set(voxSizePostTransformMA); } - return getSeriesRootTransform(omeMeta, reader, iSerie, u, + return getSeriesRootTransform(omeMeta, iSerie, u, // Bioformats location fix positionPreTransform, positionPostTransform, positionReferenceFrameLength, positionIsImageCenter, @@ -247,7 +246,6 @@ protected static AffineTransform3D getSeriesRootTransform(IMetadata omeMeta, } public static AffineTransform3D getSeriesRootTransform(IMetadata omeMeta, - IFormatReader reader, int iSerie, Unit u, // Bioformats location fix AffineTransform3D positionPreTransform, @@ -284,7 +282,7 @@ else if (voxSize[iDimension].unit().getSymbol().equals( Length[] pos = getSeriesPositionAsLengths(omeMeta, iSerie); double[] p = new double[3]; - Dimensions dims = getSeriesDimensions(omeMeta, reader, iSerie); + Dimensions dims = getSeriesDimensions(omeMeta, iSerie); for (int iDimension = 0; iDimension < 3; iDimension++) { // X:0; Y:1; Z:2 if ((pos[iDimension].unit() != null) && (pos[iDimension].unit() @@ -406,16 +404,14 @@ public int numDimensions() { return voxelDimensions; } - public static Dimensions getSeriesDimensions(IMetadata omeMeta, IFormatReader reader, int iSerie) { + public static Dimensions getSeriesDimensions(IMetadata omeMeta, int iSerie) { // Always set 3d to allow for Big Stitcher compatibility int numDimensions = 3; - omeMeta.getPixelsSizeX(iSerie); - reader.setSeries(iSerie); - int sX = reader.getSizeX(); - int sY = reader.getSizeY(); - int sZ = reader.getSizeZ(); + int sX = omeMeta.getPixelsSizeX(iSerie).getValue();//reader.getSizeX(); + int sY = omeMeta.getPixelsSizeY(iSerie).getValue();//reader.getSizeY(); + int sZ = omeMeta.getPixelsSizeZ(iSerie).getValue();//reader.getSizeZ(); long[] dims = new long[3]; diff --git a/src/main/java/ch/epfl/biop/bdv/img/bioformats/BioFormatsOpener.java b/src/main/java/ch/epfl/biop/bdv/img/bioformats/BioFormatsOpener.java index fe54e54..5ad5933 100644 --- a/src/main/java/ch/epfl/biop/bdv/img/bioformats/BioFormatsOpener.java +++ b/src/main/java/ch/epfl/biop/bdv/img/bioformats/BioFormatsOpener.java @@ -24,6 +24,8 @@ import bdv.img.cache.VolatileGlobalCellCache; import ch.epfl.biop.bdv.img.OpenerSetupLoader; +import ch.epfl.biop.bdv.img.entity.Field; +import ch.epfl.biop.bdv.img.entity.Plate; import ch.epfl.biop.bdv.img.opener.ChannelProperties; import ch.epfl.biop.bdv.img.opener.Opener; import ch.epfl.biop.bdv.img.ResourcePool; @@ -57,6 +59,9 @@ import ome.units.UNITS; import ome.units.quantity.Length; import ome.units.unit.Unit; +import ome.xml.meta.OMEXMLMetadataRoot; +import ome.xml.model.Well; +import ome.xml.model.WellSample; import org.apache.commons.io.FilenameUtils; import org.scijava.Context; import org.slf4j.Logger; @@ -66,9 +71,11 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.function.Supplier; import static ch.epfl.biop.bdv.img.opener.OpenerHelper.memoize; @@ -125,8 +132,6 @@ public class BioFormatsOpener implements Opener { private final Map readerOptions; - IFormatReader model; - /** * * @param context @@ -214,11 +219,17 @@ public BioFormatsOpener( return currentIndexFilename; }); - this.model = this.getNewReader(); this.pool = memoize("opener.bioformats."+splitRGBChannels+"."+dataLocation+"."+options, cachedObjects, - () -> new ReaderPool(poolSize, true, - this::getNewReader, model)); + () -> { + try { + return new ReaderPool(poolSize, true, + this::getNewReader, dataLocation.toUpperCase().trim().endsWith(".CZI") ); // Create base reader only for czi files + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + }); int pixelType; { // Indentation just for the pool / recycle operation -> force limiting the scope of reader IFormatReader reader = pool.takeOrCreate(); @@ -262,7 +273,6 @@ public BioFormatsOpener( AffineTransform3D rootTransform = BioFormatsHelper.getSeriesRootTransform( this.omeMeta, //metadata - model, iSerie, // serie BioFormatsHelper.getUnitFromString(unit), // unit positionPreTransformMatrixArray, // AffineTransform3D for positionPreTransform, @@ -294,6 +304,7 @@ public List getEntities(int iChannel) { ArrayList entityList = new ArrayList<>(); entityList.add(new FileName(idxFilename, filename)); entityList.add(new SeriesIndex(iSerie)); + addPlateInfo(entityList, options, iSerie, cachedObjects); return entityList; } @@ -311,6 +322,67 @@ public AffineTransform3D getTransform() { } else meta = null; } + private void addPlateInfo(ArrayList entityList, + String options, + int iSerie, + Map cachedObjects) { + if (omeMeta.getPlateCount() == 0 ) return; // No plate information + + // Check that we can read information + if (omeMeta.getPlateCount() > 1) { + logger.warn("Plate information ignored: only bio-formats containing single wells are supported"); + return; + } + + if (!(omeMeta.getRoot() instanceof OMEXMLMetadataRoot)) { + logger.warn("Can't detect plate information since ome meta root is not of class OMEXMLMetadataRoot"); + return; + } + + OMEXMLMetadataRoot r = (OMEXMLMetadataRoot) omeMeta.getRoot(); + ome.xml.model.Plate plate = r.getPlate(0); + + // Gets a unique identifier for the plate + + Integer currentPlateIndex = memoize("opener.bioformats.currentplateindex", cachedObjects, () -> 0); + int idxPlate = memoize("opener.bioformats.plateIndex."+dataLocation+"."+options, cachedObjects, () -> { + cachedObjects.put("opener.bioformats.currentplateindex", currentPlateIndex + 1 ); + return currentPlateIndex; + }); + + entityList.add(new Plate(idxPlate, plate.getName())); + + Map idToWellSample = memoize("opener.bioformats.idtowell."+dataLocation+"."+options, cachedObjects, () -> { + Map idToWS = new HashMap<>(); + plate.copyWellList().forEach(well -> well.copyWellSampleList().forEach(ws -> { + if (ws.getLinkedImage()!=null) { + if (ws.getLinkedImage().getID()!=null) { + // "Image:0" + idToWS.put(Integer.parseInt(ws.getLinkedImage().getID().split(":")[1]), ws); + } + } + })); + return idToWS; + }); + + if (idToWellSample.containsKey(iSerie)) { + WellSample ws = idToWellSample.get(iSerie); + System.out.println("ws="+ws.getID()); + // WellSample:0:0:2 + int id = Integer.parseInt(ws.getID().split(":")[3]); + entityList.add(new Field(id)); + if (ws.getWell()!=null) { + Well w = ws.getWell(); + entityList.add( + new ch.epfl.biop.bdv.img.entity.Well( + Integer.parseInt(w.getID().split(":")[2]), + (char)(w.getRow().getValue()+'A')+Integer.toString(w.getColumn().getValue()+1), + w.getRow().getValue(), w.getColumn().getValue())); + } + } + + } + /** * Build a channelProperties object for each image channel. * @param omeMeta = image metadata @@ -435,7 +507,7 @@ public IFormatReader getNewReader() { reader = new ChannelSeparator(reader); } - if (memoize) { // Can't memoize with bf Options + if (memoize) { Memoizer memo = new Memoizer(reader); try { memo.setId(dataLocation); @@ -590,14 +662,6 @@ public void close() { e.printStackTrace(); } }); - if (model!=null) { - try { - model.close(); - } catch (IOException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } } /** @@ -620,22 +684,15 @@ private static class ReaderPool extends ResourcePool { final IFormatReader model; public ReaderPool(int size, Boolean dynamicCreation, - Supplier readerSupplier) - { - super(size, dynamicCreation); - createPool(); - this.readerSupplier = readerSupplier; - model = null; - } - - public ReaderPool(int size, Boolean dynamicCreation, - Supplier readerSupplier, - IFormatReader model) - { + Supplier readerSupplier, boolean createBase) throws Exception { super(size, dynamicCreation); - this.model = model; createPool(); this.readerSupplier = readerSupplier; + if (createBase) { + model = this.takeOrCreate(); + } else { + model = null; + } } @Override @@ -648,5 +705,19 @@ public IFormatReader createObject() { } return readerSupplier.get(); } + + @Override + public synchronized void shutDown(Consumer closer) { + if (model!=null) { + try { + recycle(model); + } catch (Exception e) { + e.printStackTrace(); + } + closer.accept(model); + } + super.shutDown(closer); + } + } } diff --git a/src/main/java/ch/epfl/biop/bdv/img/entity/Field.java b/src/main/java/ch/epfl/biop/bdv/img/entity/Field.java new file mode 100644 index 0000000..7c35954 --- /dev/null +++ b/src/main/java/ch/epfl/biop/bdv/img/entity/Field.java @@ -0,0 +1,47 @@ +/*- + * #%L + * Various image loaders for bigdataviewer (Bio-Formats, Omero, QuPath) + * %% + * Copyright (C) 2022 - 2024 ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland, BioImaging And Optics Platform (BIOP) + * %% + * 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. + * + * 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 + * . + * #L% + */ + +package ch.epfl.biop.bdv.img.entity; + +import mpicbg.spim.data.generic.base.Entity; + +public class Field extends Entity implements + Comparable +{ + + public Field(final int id) { + super(id); + } + + /** + * Compares the {@link #getId() ids}. + */ + @Override + public int compareTo(final Field o) { + return getId() - o.getId(); + } + + /** + * Empty constructor strictly necessary for dataset deserialization + */ + protected Field() {} +} diff --git a/src/main/java/ch/epfl/biop/bdv/img/entity/Plate.java b/src/main/java/ch/epfl/biop/bdv/img/entity/Plate.java new file mode 100644 index 0000000..6a5df3e --- /dev/null +++ b/src/main/java/ch/epfl/biop/bdv/img/entity/Plate.java @@ -0,0 +1,47 @@ +/*- + * #%L + * Various image loaders for bigdataviewer (Bio-Formats, Omero, QuPath) + * %% + * Copyright (C) 2022 - 2024 ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland, BioImaging And Optics Platform (BIOP) + * %% + * 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. + * + * 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 + * . + * #L% + */ + +package ch.epfl.biop.bdv.img.entity; + +import mpicbg.spim.data.generic.base.NamedEntity; + +public class Plate extends NamedEntity implements + Comparable +{ + + public Plate(final int id, final String name) { + super(id, name); + } + + /** + * Compares the {@link #getId() ids}. + */ + @Override + public int compareTo(final Plate o) { + return getId() - o.getId(); + } + + /** + * Empty constructor strictly necessary for dataset deserialization + */ + protected Plate() {} +} diff --git a/src/main/java/ch/epfl/biop/bdv/img/entity/Well.java b/src/main/java/ch/epfl/biop/bdv/img/entity/Well.java new file mode 100644 index 0000000..1274456 --- /dev/null +++ b/src/main/java/ch/epfl/biop/bdv/img/entity/Well.java @@ -0,0 +1,66 @@ +/*- + * #%L + * Various image loaders for bigdataviewer (Bio-Formats, Omero, QuPath) + * %% + * Copyright (C) 2022 - 2024 ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland, BioImaging And Optics Platform (BIOP) + * %% + * 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. + * + * 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 + * . + * #L% + */ + +package ch.epfl.biop.bdv.img.entity; + +import mpicbg.spim.data.SpimDataException; +import mpicbg.spim.data.XmlHelpers; +import mpicbg.spim.data.generic.base.NamedEntity; + + +public class Well extends NamedEntity implements + Comparable +{ + + int row, column; + + public Well(final int id, final String name, int row, int column) { + super(id, name); + this.row = row; + this.column = column; + } + + public int getRow() { + return row; + } + + public int getColumn() { + return column; + } + + /** + * Compares the {@link #getId() ids}. + */ + @Override + public int compareTo(final Well o) { + return getId() - o.getId(); + } + + /** + * Empty constructor strictly necessary for dataset deserialization + */ + protected Well() {} + + + + +} diff --git a/src/main/java/ch/epfl/biop/bdv/img/entity/XmlIoField.java b/src/main/java/ch/epfl/biop/bdv/img/entity/XmlIoField.java new file mode 100644 index 0000000..8c64b28 --- /dev/null +++ b/src/main/java/ch/epfl/biop/bdv/img/entity/XmlIoField.java @@ -0,0 +1,37 @@ +/*- + * #%L + * Various image loaders for bigdataviewer (Bio-Formats, Omero, QuPath) + * %% + * Copyright (C) 2022 - 2024 ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland, BioImaging And Optics Platform (BIOP) + * %% + * 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. + * + * 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 + * . + * #L% + */ +package ch.epfl.biop.bdv.img.entity; + +import mpicbg.spim.data.generic.base.ViewSetupAttributeIo; +import mpicbg.spim.data.generic.base.XmlIoEntity; + +/** + * For xml serialization and deserialization of {@link ImageName} + */ +@ViewSetupAttributeIo(name = "field", type = Field.class) +public class XmlIoField extends XmlIoEntity { + + public XmlIoField() { + super("field", Field.class); + } + +} diff --git a/src/main/java/ch/epfl/biop/bdv/img/entity/XmlIoPlate.java b/src/main/java/ch/epfl/biop/bdv/img/entity/XmlIoPlate.java new file mode 100644 index 0000000..c9378ce --- /dev/null +++ b/src/main/java/ch/epfl/biop/bdv/img/entity/XmlIoPlate.java @@ -0,0 +1,37 @@ +/*- + * #%L + * Various image loaders for bigdataviewer (Bio-Formats, Omero, QuPath) + * %% + * Copyright (C) 2022 - 2024 ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland, BioImaging And Optics Platform (BIOP) + * %% + * 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. + * + * 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 + * . + * #L% + */ +package ch.epfl.biop.bdv.img.entity; + +import mpicbg.spim.data.generic.base.ViewSetupAttributeIo; +import mpicbg.spim.data.generic.base.XmlIoNamedEntity; + +/** + * For xml serialization and deserialization of {@link ImageName} + */ +@ViewSetupAttributeIo(name = "plate", type = Plate.class) +public class XmlIoPlate extends XmlIoNamedEntity { + + public XmlIoPlate() { + super("plate", Plate.class); + } + +} diff --git a/src/main/java/ch/epfl/biop/bdv/img/entity/XmlIoWell.java b/src/main/java/ch/epfl/biop/bdv/img/entity/XmlIoWell.java new file mode 100644 index 0000000..c08026b --- /dev/null +++ b/src/main/java/ch/epfl/biop/bdv/img/entity/XmlIoWell.java @@ -0,0 +1,56 @@ +/*- + * #%L + * Various image loaders for bigdataviewer (Bio-Formats, Omero, QuPath) + * %% + * Copyright (C) 2022 - 2024 ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland, BioImaging And Optics Platform (BIOP) + * %% + * 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. + * + * 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 + * . + * #L% + */ +package ch.epfl.biop.bdv.img.entity; + +import mpicbg.spim.data.SpimDataException; +import mpicbg.spim.data.XmlHelpers; +import mpicbg.spim.data.generic.base.ViewSetupAttributeIo; +import mpicbg.spim.data.generic.base.XmlIoNamedEntity; +import org.jdom2.Element; + +/** + * For xml serialization and deserialization of {@link ImageName} + */ +@ViewSetupAttributeIo(name = "well", type = Well.class) +public class XmlIoWell extends XmlIoNamedEntity { + + public XmlIoWell() { + super("well", Well.class); + } + + @Override + public Element toXml(final Well w) { + final Element elem = super.toXml(w); + elem.addContent(XmlHelpers.intElement("row", w.row)); + elem.addContent(XmlHelpers.intElement("column", w.column)); + return elem; + } + + @Override + public Well fromXml(final Element elem) throws SpimDataException { + final Well w = super.fromXml(elem); + w.row = XmlHelpers.getInt(elem, "row"); + w.column = XmlHelpers.getInt(elem, "column"); + return w; + } + +} diff --git a/src/main/java/ch/epfl/biop/bdv/img/opener/ChannelProperties.java b/src/main/java/ch/epfl/biop/bdv/img/opener/ChannelProperties.java index 05391d3..b3548ec 100644 --- a/src/main/java/ch/epfl/biop/bdv/img/opener/ChannelProperties.java +++ b/src/main/java/ch/epfl/biop/bdv/img/opener/ChannelProperties.java @@ -21,7 +21,6 @@ */ package ch.epfl.biop.bdv.img.opener; -import IceInternal.Ex; import com.google.gson.Gson; import net.imglib2.type.Type; import net.imglib2.type.numeric.ARGBType;