/* * Copyright (c) 2012 Diamond Light Source Ltd. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package uk.ac.diamond.scisoft.analysis.io; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.List; import org.eclipse.dawnsci.analysis.api.io.IDataHolder; import org.eclipse.dawnsci.analysis.api.io.IFileLoader; import org.eclipse.dawnsci.analysis.api.io.ScanFileHolderException; import org.eclipse.january.IMonitor; import org.eclipse.january.dataset.DTypeUtils; import org.eclipse.january.dataset.Dataset; import org.eclipse.january.dataset.DatasetFactory; import org.eclipse.january.dataset.DatasetUtils; import org.eclipse.january.dataset.IDataset; import org.eclipse.january.dataset.ILazyDataset; import org.eclipse.january.dataset.ShapeUtils; import org.eclipse.january.dataset.SliceND; import org.eclipse.january.dataset.SliceNDIterator; import org.eclipse.january.dataset.StringDataset; import org.eclipse.january.io.ILazyLoader; import org.eclipse.january.metadata.IMetadata; /** * Class to create dataset from a dataset of filenames. * * The shape of the 'whole' dataset represented by the set of filenames appended with * the shape of the first image. * * The type of the dataset is set to equal the type of the first image. */ public class ImageStackLoader implements ILazyLoader { private StringDataset filenames; private int[] fShape; // filename shape private long[] mShape; // max total shape private int[] iShape; // image shape private int[] shape; private int dtype; private File parent = null; private Class<? extends IFileLoader> loaderClass; private boolean onlyOne; private String datasetName; public int getDType() { return dtype; } public ImageStackLoader(List<String> imageFilenames, IMonitor mon) throws Exception { this(imageFilenames, LoaderFactory.getData(imageFilenames.get(0), mon), mon); } @SuppressWarnings("unused") public ImageStackLoader(List<String> imageFilenames, IDataHolder dh, IMonitor mon) throws Exception { this((StringDataset) DatasetFactory.createFromList(imageFilenames), dh, null); } public ImageStackLoader(int[] dimensions, String[] imageFilenames, String directory) throws Exception { this(DatasetFactory.createFromObject(StringDataset.class, imageFilenames, dimensions), null, directory); } public ImageStackLoader(int[] dimensions, String[] imageFilenames) throws Exception { this(dimensions, imageFilenames, null); } public ImageStackLoader(StringDataset imageFilenames, String directory) throws Exception { this(imageFilenames, null, directory); } public ImageStackLoader(StringDataset imageFilenames, IDataHolder dh, String directory) throws Exception { this(imageFilenames,dh,directory,null); } public ImageStackLoader(StringDataset imageFilenames, IDataHolder dh, String directory, String datasetName) throws Exception { if (directory != null) { File file = new File(directory); if (file.isDirectory()) { parent = file; } } filenames = imageFilenames; fShape = imageFilenames.getShapeRef(); this.datasetName = datasetName; int fRank = fShape.length; // load the first image to get the shape of the whole thing ILazyDataset dataSetFromFile; if (dh == null || dh.getNames().length == 0) { dataSetFromFile = getDatasetFromFile(new int[fRank], null); } else { dataSetFromFile = datasetName == null ? dh.getDataset(0) : dh.getDataset(datasetName); loaderClass = dh.getLoaderClass(); } onlyOne = imageFilenames.getSize() == 1; dtype = DTypeUtils.getDType(dataSetFromFile); iShape = dataSetFromFile.getShape(); shape = Arrays.copyOf(fShape, fRank + iShape.length); for (int i = 0; i < iShape.length; i++) { shape[i + fRank] = iShape[i]; } } private ILazyDataset getDatasetFromFile(int[] location, IMonitor mon) throws ScanFileHolderException { File f = new File(getDLSWindowsPath(filenames.get(location))); if (parent != null) { // try local directory first File nf = null; if (!f.isAbsolute()) { // try relative path first nf = new File(parent, f.getPath()); } if (nf == null || !nf.exists()) { nf = new File(parent, f.getName()); } if (nf.exists()) { try { return loadDataset(nf.getAbsolutePath(), mon); } catch (Exception e) { } } } return loadDataset(f.getAbsolutePath(), mon); } private ILazyDataset loadDataset(String filename, IMonitor mon) throws ScanFileHolderException { IDataHolder data = null; if (loaderClass != null) { try { data = LoaderFactory.getData(loaderClass, filename, true, mon); } catch (Exception e) { // do nothing and try with all registered loaders } } if (data == null) { try { data = LoaderFactory.getData(filename, mon); } catch (Exception e) { throw new ScanFileHolderException("Cannot load image in image stack", e); } if (data == null) { throw new ScanFileHolderException("Cannot load image in image stack"); } } if (loaderClass == null) { loaderClass = data.getLoaderClass(); } ILazyDataset dataset = null; if (datasetName != null) { try { dataset = data.getLazyDataset(datasetName); } catch (Exception e) { throw new ScanFileHolderException("Could no slice data", e); } } else { dataset = data.getDataset(0); } IMetadata meta = data.getMetadata(); dataset.setMetadata(meta); return dataset; } /** * * @param dlsPath * @return String in windows format. */ private static String getDLSWindowsPath(String dlsPath) { if (!isWindows || dlsPath == null) return dlsPath; return dlsPath.startsWith("/dls/") ? "\\\\Data.diamond.ac.uk\\" + dlsPath.substring(5) : dlsPath; } private static final boolean isWindows = System.getProperty("os.name").startsWith("Windows"); @Override public boolean isFileReadable() { return true; } @Override public Dataset getDataset(IMonitor mon, SliceND slice) throws IOException { int[] newShape = slice.getShape(); if (ShapeUtils.calcSize(newShape) == 0) return DatasetFactory.zeros(newShape, dtype); int iRank = iShape.length; int nRank = newShape.length; int[] missing = new int[iRank]; int start = nRank - iRank; for (int i = 0; i < iRank; i++) { missing[i] = start + i; } SliceNDIterator it = new SliceNDIterator(slice, missing); Dataset result = onlyOne || ShapeUtils.calcSize(it.getShape()) == 1 ? null : DatasetFactory.zeros(newShape, dtype); int[] pos = it.getUsedPos(); SliceND iSlice = it.getOmittedSlice(); int[] iShape = iSlice.getShape(); SliceND dSlice = it.getOutputSlice(); while (it.hasNext()) { IDataset image; try { image = getDatasetFromFile(pos, mon).getSlice(iSlice); } catch (Exception e) { throw new IOException(e); } image.setShape(iShape); if (result == null) { result = DatasetUtils.convertToDataset(image); result.setShape(newShape); break; } result.setSlice(image, dSlice); } return result; } public int[] getShape() { return shape; } /** * @param maxShape original maximum shape for filenames dataset */ public void setMaxShape(long[] maxShape) { if (maxShape == null) { mShape = null; return; } if (maxShape.length != fShape.length) { throw new IllegalArgumentException("Maximum shape must be same rank as filename dataset"); } int rank = shape.length; int mrank = maxShape.length; mShape = new long[rank]; int i = 0; for (; i < mrank; i++) { mShape[i] = maxShape[i]; } for (; i < rank; i++) { mShape[i] = shape[i]; } } /** * Remove dimensions of one from shape (and max shape) */ public void squeeze() { int rank = shape.length; int unitDims = 0; for (int i = 0; i < rank; i++) { if (shape[i] == 1) { unitDims++; } } if (unitDims == 0) return; int nrank = rank - unitDims; int[] nShape = new int[nrank]; long[] nMaxShape = new long[nrank]; int j = 0; for (int i = 0; i < rank; i++) { if (shape[i] > 1) { nShape[j] = shape[i]; nMaxShape[j++] = mShape[i]; if (j == nrank) break; } } shape = nShape; mShape = nMaxShape; filenames.squeeze(); } /** * @return maximum shape */ public long[] getMaxShape() { return mShape; } /** * @return chunk shape */ public long[] getChunkShape() { // use each image as a chunk int rank = shape.length; long[] chunk = new long[rank]; int i = 0; int ibeg = rank - iShape.length; for (; i < ibeg; i++) { chunk[i] = 1; } for (; i < rank; i++) { chunk[i] = iShape[i - ibeg]; } return chunk; } }