Changeset 1783


Ignore:
Timestamp:
11/09/06 17:21:31 (13 years ago)
Author:
curtis
Message:

Initial version of new and improved file stitcher.

Location:
trunk/loci/formats
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/loci/formats/AxisGuesser.java

    r1753 r1783  
    8080  protected int[] axes; 
    8181 
     82  /** Whether the guesser is confident that all axis types are correct. */ 
     83  protected boolean certain; 
     84 
    8285  // -- Constructor -- 
    8386 
     
    9093   * @param dimOrder The dimension order (e.g., XYZTC) within each file 
    9194   * @param sizeZ The number of Z positions within each file 
    92    * @param sizeT The number of Z positions within each file 
    93    * @param sizeC The number of Z positions within each file 
     95   * @param sizeT The number of T positions within each file 
     96   * @param sizeC The number of C positions within each file 
    9497   * @param isCertain Whether the dimension order given is known to be good, 
    9598   *   or merely a guess 
     
    195198    boolean canBeT = !foundT && sizeT == 1; 
    196199 
     200    certain = isCertain; 
     201 
    197202    for (int i=0; i<axes.length; i++) { 
    198203      if (axes[i] != UNKNOWN_AXIS) continue; 
     204      certain = false; 
    199205 
    200206      if (canBeZ) { 
     
    220226  /** Gets the adjusted dimension order. */ 
    221227  public String getAdjustedOrder() { return newOrder; } 
     228 
     229  /** Gets whether the guesser is confident that all axes are correct. */ 
     230  public boolean isCertain() { return certain; } 
    222231 
    223232  /** 
     
    225234   * @return An array containing values from the enumeration: 
    226235   *   <ul> 
    227    *     <li>Z: focal planes</li> 
    228    *     <li>T: time points</li> 
    229    *     <li>C: channels</li> 
     236   *     <li>Z_AXIS: focal planes</li> 
     237   *     <li>T_AXIS: time points</li> 
     238   *     <li>C_AXIS: channels</li> 
    230239   *   </ul> 
    231240   */ 
    232241  public int[] getAxisTypes() { return axes; } 
     242 
     243  /** Gets the number of Z axes in the pattern. */ 
     244  public int getAxisCountZ() { return getAxisCount(Z_AXIS); } 
     245 
     246  /** Gets the number of T axes in the pattern. */ 
     247  public int getAxisCountT() { return getAxisCount(T_AXIS); } 
     248 
     249  /** Gets the number of C axes in the pattern. */ 
     250  public int getAxisCountC() { return getAxisCount(C_AXIS); } 
     251 
     252  /** Gets the number of axes in the pattern of the given type. 
     253   *  @param axisType One of: 
     254   *   <ul> 
     255   *     <li>Z_AXIS: focal planes</li> 
     256   *     <li>T_AXIS: time points</li> 
     257   *     <li>C_AXIS: channels</li> 
     258   *   </ul> 
     259   */ 
     260  public int getAxisCount(int axisType) { 
     261    int num = 0; 
     262    for (int i=0; i<axes.length; i++) { 
     263      if (axes[i] == axisType) num++; 
     264    } 
     265    return num; 
     266  } 
    233267 
    234268  // -- Main method -- 
  • trunk/loci/formats/FileStitcher.java

    r1637 r1783  
    2828import java.io.*; 
    2929import java.lang.reflect.InvocationTargetException; 
    30 import java.util.Arrays; 
    31 import java.util.Vector; 
    32  
    33 /** Logic to stitch together files with similar names. */ 
    34 public class FileStitcher extends ReaderWrapper { 
    35  
    36   // -- Constants -- 
    37  
    38   /** Prefix endings indicating time dimension. */ 
    39   private static final String[] T = {"t", "tl", "tp"}; 
    40  
    41   /** Prefix endings indicating space dimension. */ 
    42   private static final String[] Z = {"bf", "focal", "fp", "sec", "z", "zs"}; 
    43  
    44   /** Prefix endings indicating channel dimension. */ 
    45   private static final String[] C = {"c", "ch", "w"}; 
     30import java.util.*; 
     31import javax.swing.JFileChooser; 
     32import javax.swing.filechooser.FileFilter; 
     33 
     34/** 
     35 * Logic to stitch together files with similar names. Only stitches the first 
     36 * series for each file, and assumes that all files have the same dimensions. 
     37 */ 
     38public class FileStitcher implements IFormatReader { 
    4639 
    4740  // -- Fields -- 
    4841 
    49   /** FilePattern used to build the list of files. */ 
     42  /** FormatReader to use as a template for constituent readers. */ 
     43  private IFormatReader reader; 
     44 
     45  /** 
     46   * Whether string ids given should be treated 
     47   * as file patterns rather than single file paths. 
     48   */ 
     49  private boolean patternIds = false; 
     50 
     51  /** Current file pattern string. */ 
     52  private String currentId; 
     53 
     54  /** File pattern object used to build the list of files. */ 
    5055  private FilePattern fp; 
    5156 
    52   /** The X, Y, Z, C and T dimensions. */ 
    53   private int[] dimensions; 
    54  
    55   /** Total number of images. */ 
    56   private int numImages; 
    57  
    58   /** Image count for each file. */ 
    59   private int[] imageCounts; 
     57  /** Axis guesser object used to guess which dimensional axes are which. */ 
     58  private AxisGuesser ag; 
    6059 
    6160  /** The matching files. */ 
    6261  private String[] files; 
    6362 
     63  /** Reader used for each file. */ 
     64  private IFormatReader[] readers; 
     65 
     66  /** Image dimensions. */ 
     67  private int width, height; 
     68 
     69  /** Number of images per file. */ 
     70  private int imagesPerFile; 
     71 
     72  /** Dimensional axis lengths per file. */ 
     73  private int sizeZ, sizeC, sizeT; 
     74 
     75  /** Total number of image planes. */ 
     76  private int totalImages; 
     77 
     78  /** Total dimensional axis lengths. */ 
     79  private int totalSizeZ, totalSizeC, totalSizeT; 
     80 
    6481  /** Dimension order. */ 
    6582  private String order; 
    6683 
    67   /** Next plane number to open. */ 
    68   private int number; 
    69  
    70   /** Initialized series. */ 
    71   private int validSeries = -1; 
    72  
    73   /** Index into the array of readers. */ 
    74   private int current = 0; 
    75  
    76   /** Whether each dimension size varies between files. */ 
    77   private boolean varyZ, varyC, varyT; 
    78  
    79   /** Reader used for each file. */ 
    80   private IFormatReader[] readers; 
    81  
    82   /** Whether to use a separate reader for each file. */ 
    83   private boolean multipleReaders = true; 
    84  
    85   /** 
    86    * Whether string ids given should be treated 
    87    * as file patterns rather than single file paths. 
    88    */ 
    89   private boolean patternIds = false; 
     84  /** Component lengths for each axis type. */ 
     85  private int[] lenZ, lenC, lenT; 
     86 
     87  /** Whether or not we're doing channel stat calculation (no by default). */ 
     88  protected boolean enableChannelStatCalculation = false; 
     89 
     90  /** Whether or not to ignore color tables, if present. */ 
     91  protected boolean ignoreColorTable = false; 
    9092 
    9193  // -- Constructors -- 
    9294 
    9395  /** Constructs a FileStitcher around a new image reader. */ 
    94   public FileStitcher() { super(); } 
     96  public FileStitcher() { this(new ImageReader()); } 
    9597 
    9698  /** 
     
    98100   * @param r The reader to use for reading stitched files. 
    99101   */ 
    100   public FileStitcher(IFormatReader r) { super(r); } 
     102  public FileStitcher(IFormatReader r) { this(r, false); } 
    101103 
    102104  /** 
    103105   * Constructs a FileStitcher with the given reader. 
    104106   * @param r The reader to use for reading stitched files. 
    105    * @param multipleReaders Whether to use a separate reader for each file. 
    106    */ 
    107   public FileStitcher(IFormatReader r, boolean multipleReaders) { 
    108     super(r); 
    109     this.multipleReaders = multipleReaders; 
    110   } 
    111  
    112   /** 
    113    * Constructs a FileStitcher with the given reader. 
    114    * @param multipleReaders Whether to use a separate reader for each file. 
    115107   * @param patternIds Whether string ids given should be treated as file 
    116108   *   patterns rather than single file paths. 
    117109   */ 
    118   public FileStitcher(IFormatReader r, boolean multipleReaders, 
    119     boolean patternIds) 
    120   { 
    121     super(r); 
    122     this.multipleReaders = multipleReaders; 
     110  public FileStitcher(IFormatReader r, boolean patternIds) { 
     111    reader = r; 
    123112    this.patternIds = patternIds; 
    124113  } 
     
    126115  // -- IFormatReader API methods -- 
    127116 
    128   /** Determines the number of images in the given file. */ 
     117  /* @see IFormatReader#isThisType(byte[]) */ 
     118  public boolean isThisType(byte[] block) { 
     119    return reader.isThisType(block); 
     120  } 
     121 
     122  /** Determines the number of images in the given file series. */ 
    129123  public int getImageCount(String id) throws FormatException, IOException { 
    130     if (getSeries(id) != validSeries) initFile(id); 
    131     return numImages; 
    132   } 
    133  
    134   /** Get the size of the X dimension. */ 
     124    if (!id.equals(currentId)) initFile(id); 
     125    return totalImages; 
     126  } 
     127 
     128  /** Checks if the images in the file are RGB. */ 
     129  public boolean isRGB(String id) throws FormatException, IOException { 
     130    if (!id.equals(currentId)) initFile(id); 
     131    return reader.isRGB(files[0]); 
     132  } 
     133 
     134  /* @see IFormatReader#getSizeX(String) */ 
    135135  public int getSizeX(String id) throws FormatException, IOException { 
    136     if (getSeries(id) != validSeries) initFile(id); 
    137     return dimensions[0]; 
    138   } 
    139  
    140   /** Get the size of the Y dimension. */ 
     136    if (!id.equals(currentId)) initFile(id); 
     137    return width; 
     138  } 
     139 
     140  /* @see IFormatReader#getSizeY(String) */ 
    141141  public int getSizeY(String id) throws FormatException, IOException { 
    142     if (getSeries(id) != validSeries) initFile(id); 
    143     return dimensions[1]; 
    144   } 
    145  
    146   /** Get the size of the Z dimension. */ 
     142    if (!id.equals(currentId)) initFile(id); 
     143    return height; 
     144  } 
     145 
     146  /* @see IFormatReader#getSizeZ(String) */ 
    147147  public int getSizeZ(String id) throws FormatException, IOException { 
    148     if (getSeries(id) != validSeries) initFile(id); 
    149     return dimensions[2]; 
    150   } 
    151  
    152   /** Get the size of the C dimension. */ 
     148    if (!id.equals(currentId)) initFile(id); 
     149    return totalSizeZ; 
     150  } 
     151 
     152  /* @see IFormatReader#getSizeC(String) */ 
    153153  public int getSizeC(String id) throws FormatException, IOException { 
    154     if (getSeries(id) != validSeries) initFile(id); 
    155     return dimensions[3]; 
    156   } 
    157  
    158   /** Get the size of the T dimension. */ 
     154    if (!id.equals(currentId)) initFile(id); 
     155    return totalSizeC; 
     156  } 
     157 
     158  /* @see IFormatReader#getSizeT(String) */ 
    159159  public int getSizeT(String id) throws FormatException, IOException { 
    160     if (getSeries(id) != validSeries) initFile(id); 
    161     return dimensions[4]; 
    162   } 
    163  
    164   /** 
    165    * Return a five-character string representing the dimension order 
    166    * within the file. 
     160    if (!id.equals(currentId)) initFile(id); 
     161    return totalSizeT; 
     162  } 
     163 
     164  /* @see IFormatReader#getPixelType(String) */ 
     165  public int getPixelType(String id) throws FormatException, IOException { 
     166    if (!id.equals(currentId)) initFile(id); 
     167    return reader.getPixelType(files[0]); 
     168  } 
     169 
     170  /* @see IFormatReader#getChannelGlobalMinimum(String, int) */ 
     171  public Double getChannelGlobalMinimum(String id, int theC) 
     172    throws FormatException, IOException 
     173  { 
     174    int[] include = getIncludeList(id, theC); 
     175    Double min = new Double(Double.POSITIVE_INFINITY); 
     176    for (int i=0; i<readers.length; i++) { 
     177      if (include[i] >= 0) { 
     178        Double d = readers[i].getChannelGlobalMinimum(files[i], include[i]); 
     179        if (d.compareTo(min) < 0) min = d; 
     180      } 
     181    } 
     182    return min; 
     183  } 
     184 
     185  /* @see IFormatReader#getChannelGlobalMaximum(String, int) */ 
     186  public Double getChannelGlobalMaximum(String id, int theC) 
     187    throws FormatException, IOException 
     188  { 
     189    int[] include = getIncludeList(id, theC); 
     190    Double max = new Double(Double.NEGATIVE_INFINITY); 
     191    for (int i=0; i<readers.length; i++) { 
     192      if (include[i] >= 0) { 
     193        Double d = readers[i].getChannelGlobalMaximum(files[i], include[i]); 
     194        if (d.compareTo(max) > 0) max = d; 
     195      } 
     196    } 
     197    return max; 
     198  } 
     199 
     200  /* @see IFormatReader#getThumbSizeX(String) */ 
     201  public int getThumbSizeX(String id) throws FormatException, IOException { 
     202    if (!id.equals(currentId)) initFile(id); 
     203    return reader.getThumbSizeX(files[0]); 
     204  } 
     205 
     206  /* @see IFormatReader#getThumbSizeY(String) */ 
     207  public int getThumbSizeY(String id) throws FormatException, IOException { 
     208    if (!id.equals(currentId)) initFile(id); 
     209    return reader.getThumbSizeY(files[0]); 
     210  } 
     211 
     212  /* @see IFormatReader#isLittleEndian(String) */ 
     213  public boolean isLittleEndian(String id) throws FormatException, IOException { 
     214    if (!id.equals(currentId)) initFile(id); 
     215    return reader.isLittleEndian(files[0]); 
     216  } 
     217 
     218  /** 
     219   * Gets a five-character string representing the 
     220   * dimension order across the file series. 
    167221   */ 
    168222  public String getDimensionOrder(String id) 
    169223    throws FormatException, IOException 
    170224  { 
    171     if (getSeries(id) != validSeries) initFile(id); 
     225    if (!id.equals(currentId)) initFile(id); 
    172226    return order; 
    173227  } 
    174228 
    175   /** Obtains the specified image from the given file. */ 
     229  /* @see IFormatReader#isOrderCertain(String) */ 
     230  public boolean isOrderCertain(String id) throws FormatException, IOException { 
     231    if (!id.equals(currentId)) initFile(id); 
     232    return ag.isCertain(); 
     233  } 
     234 
     235  /* @see IFormatReader#setChannelStatCalculationStatus(boolean) */ 
     236  public void setChannelStatCalculationStatus(boolean on) { 
     237    enableChannelStatCalculation = on; 
     238  } 
     239 
     240  /* @see IFormatReader#getChannelStatCalculationStatus */ 
     241  public boolean getChannelStatCalculationStatus() { 
     242    return enableChannelStatCalculation; 
     243  } 
     244 
     245  /* @see IFormatReader#isInterleaved(String) */ 
     246  public boolean isInterleaved(String id) throws FormatException, IOException { 
     247    if (!id.equals(currentId)) initFile(id); 
     248    return reader.isInterleaved(files[0]); 
     249  } 
     250 
     251  /** Obtains the specified image from the given file series. */ 
    176252  public BufferedImage openImage(String id, int no) 
    177253    throws FormatException, IOException 
    178254  { 
    179     if (getSeries(id) != validSeries) initFile(id); 
    180     return readers[current].openImage(findFile(no), number); 
    181   } 
    182  
    183   /** Obtains the specified image from the given file as a byte array. */ 
     255    int[] q = computeIndices(id, no); 
     256    int fno = q[0], ino = q[1]; 
     257    return readers[fno].openImage(files[fno], ino); 
     258 
     259    //CTR TODO - come up with an API for Chris, for setting the axes for the 
     260    //various blocks (pretty easy -- just setAxisType(int num, int type) or 
     261    //something similar), and also the internal ordering within each file, 
     262    //but make it intelligible (only show the internal dimensions that actually 
     263    //have size > 1). Similar to the current VisBio API? 
     264  } 
     265 
     266  /** Obtains the specified image from the given file series as a byte array. */ 
    184267  public byte[] openBytes(String id, int no) 
    185268    throws FormatException, IOException 
    186269  { 
    187     if (getSeries(id) != validSeries) initFile(id); 
    188     return readers[current].openBytes(findFile(no), number); 
    189   } 
    190  
     270    int[] q = computeIndices(id, no); 
     271    int fno = q[0], ino = q[1]; 
     272    return readers[fno].openBytes(files[fno], ino); 
     273  } 
     274 
     275  /* @see IFormatReader#openBytes(String, int, byte[]) */ 
     276  public byte[] openBytes(String id, int no, byte[] buf) 
     277    throws FormatException, IOException 
     278  { 
     279    int[] q = computeIndices(id, no); 
     280    int fno = q[0], ino = q[1]; 
     281    return readers[fno].openBytes(files[fno], ino, buf); 
     282  } 
     283 
     284  /* @see IFormatReader#openThumbImage(String, int) */ 
     285  public BufferedImage openThumbImage(String id, int no) 
     286    throws FormatException, IOException 
     287  { 
     288    int[] q = computeIndices(id, no); 
     289    int fno = q[0], ino = q[1]; 
     290    return readers[fno].openThumbImage(files[fno], ino); 
     291  } 
     292 
     293  /* @see IFormatReader#openThumbImage(String, int) */ 
     294  public byte[] openThumbBytes(String id, int no) 
     295    throws FormatException, IOException 
     296  { 
     297    int[] q = computeIndices(id, no); 
     298    int fno = q[0], ino = q[1]; 
     299    return readers[fno].openThumbBytes(files[fno], ino); 
     300  } 
     301 
     302  /* @see IFormatReader#close() */ 
     303  public void close() throws FormatException, IOException { 
     304    if (readers != null) { 
     305      for (int i=0; i<readers.length; i++) readers[i].close(); 
     306    } 
     307    readers = null; 
     308    currentId = null; 
     309  } 
     310 
     311  /* @see IFormatReader#getSeriesCount(String) */ 
     312  public int getSeriesCount(String id) throws FormatException, IOException { 
     313    if (!id.equals(currentId)) initFile(id); 
     314    return reader.getSeriesCount(files[0]); 
     315  } 
     316 
     317  /* @see IFormatReader#setSeries(String, int) */ 
     318  public void setSeries(String id, int no) throws FormatException, IOException { 
     319    if (!id.equals(currentId)) initFile(id); 
     320    reader.setSeries(files[0], no); 
     321  } 
     322 
     323  /* @see IFormatReader#getSeries(String) */ 
     324  public int getSeries(String id) throws FormatException, IOException { 
     325    if (!id.equals(currentId)) initFile(id); 
     326    return reader.getSeries(files[0]); 
     327  } 
     328 
     329  /* @see IFormatReader#setIgnoreColorTable(boolean) */ 
     330  public void setIgnoreColorTable(boolean ignore) { 
     331    ignoreColorTable = ignore; 
     332  } 
     333 
     334  /* @see IFormatReader#swapDimensions(String, String) */ 
     335  public void swapDimensions(String id, String order) 
     336    throws FormatException, IOException 
     337  { 
     338    throw new FormatException("Unimplemented"); 
     339  } 
     340 
     341  /* @see IFormatReader#getIndex(String, int, int, int) */ 
    191342  public int getIndex(String id, int z, int c, int t) 
    192343    throws FormatException, IOException 
     
    195346  } 
    196347 
     348  /* @see IFormatReader#getZCTCoords(String, int) */ 
    197349  public int[] getZCTCoords(String id, int index) 
    198350    throws FormatException, IOException 
     
    201353  } 
    202354 
     355 
     356  /* @see IFormatReader#getMetadataValue(String, String) */ 
     357  public Object getMetadataValue(String id, String field) 
     358    throws FormatException, IOException 
     359  { 
     360    if (!id.equals(currentId)) initFile(id); 
     361    return reader.getMetadataValue(files[0], field); 
     362  } 
     363 
     364  /* @see IFormatReader#getMetadata(String) */ 
     365  public Hashtable getMetadata(String id) throws FormatException, IOException { 
     366    if (!id.equals(currentId)) initFile(id); 
     367    return reader.getMetadata(files[0]); 
     368  } 
     369 
     370  /* @see IFormatReader#setMetadataStore(MetadataStore) */ 
     371  public void setMetadataStore(MetadataStore store) { 
     372    reader.setMetadataStore(store); 
     373  } 
     374 
     375  /* @see IFormatReader#getMetadataStore(String) */ 
     376  public MetadataStore getMetadataStore(String id) 
     377    throws FormatException, IOException 
     378  { 
     379    if (!id.equals(currentId)) initFile(id); 
     380    return reader.getMetadataStore(files[0]); 
     381  } 
     382 
     383  /* @see IFormatReader#getMetadataStoreRoot(String) */ 
     384  public Object getMetadataStoreRoot(String id) 
     385    throws FormatException, IOException 
     386  { 
     387    if (!id.equals(currentId)) initFile(id); 
     388    return reader.getMetadataStoreRoot(files[0]); 
     389  } 
     390 
     391  /* @see IFormatReader#testRead(String[]) */ 
    203392  public boolean testRead(String[] args) throws FormatException, IOException { 
    204393    return FormatReader.testRead(this, args); 
    205394  } 
    206395 
     396  // -- IFormatHandler API methods -- 
     397 
     398  /* @see IFormatHandler#isThisType(String) */ 
     399  public boolean isThisType(String name) { 
     400    return reader.isThisType(name); 
     401  } 
     402 
     403  /* @see IFormatHandler#isThisType(String, boolean) */ 
     404  public boolean isThisType(String name, boolean open) { 
     405    return reader.isThisType(name, open); 
     406  } 
     407 
     408  /* @see IFormatHandler#getFormat() */ 
     409  public String getFormat() { 
     410    return reader.getFormat(); 
     411  } 
     412 
     413  /* @see IFormatHandler#getSuffixes() */ 
     414  public String[] getSuffixes() { 
     415    return reader.getSuffixes(); 
     416  } 
     417 
     418  /* @see IFormatHandler#getFileFilters() */ 
     419  public FileFilter[] getFileFilters() { 
     420    return reader.getFileFilters(); 
     421  } 
     422 
     423  /* @see IFormatHandler#getFileChooser() */ 
     424  public JFileChooser getFileChooser() { 
     425    return reader.getFileChooser(); 
     426  } 
     427 
     428  /* @see IFormatHandler#mapId(String, String) */ 
     429  public void mapId(String id, String filename) { 
     430    System.err.println("FileStitcher.mapId: unimplemented"); // CTR TODO 
     431  } 
     432 
     433  /* @see IFormatHandler#getMappedId(String) */ 
     434  public String getMappedId(String id) { 
     435    System.err.println("FileStitcher.getMappedId: unimplemented"); // CTR TODO 
     436    return null; 
     437  } 
     438 
    207439  // -- Helper methods -- 
    208440 
    209441  /** Initializes the given file. */ 
    210442  protected void initFile(String id) throws FormatException, IOException { 
    211     numImages = 0; 
    212     dimensions = new int[5]; 
    213     validSeries = getSeries(id); 
    214  
    215     // get the matching files 
    216     if (patternIds) { 
    217       // id is a file pattern 
    218       fp = new FilePattern(id); 
    219     } 
    220     else { 
     443    currentId = id; 
     444    if (!patternIds) { 
    221445      // id is a file path; find the containing pattern 
    222       fp = new FilePattern(new File(id)); 
    223     } 
    224  
     446      id = FilePattern.findPattern(new File(id)); 
     447    } 
     448    fp = new FilePattern(id); 
     449 
     450    // verify that file pattern is valid and matches existing files 
    225451    String msg = " Please rename your files or disable file stitching."; 
    226452    if (!fp.isValid()) { 
    227453      throw new FormatException("Invalid " + 
    228         (patternIds ? "file pattern" : "filename") + " (" + id + "): " + 
    229         fp.getErrorMessage() + msg); 
    230     } 
    231  
     454        (patternIds ? "file pattern" : "filename") + 
     455        " (" + currentId + "): " + fp.getErrorMessage() + msg); 
     456    } 
    232457    files = fp.getFiles(); 
    233458    if (files == null) { 
     
    235460        fp.getPattern() + "). " + msg); 
    236461    } 
    237  
    238     imageCounts = new int[files.length]; 
     462    for (int i=0; i<files.length; i++) { 
     463      if (!new File(files[i]).exists()) { 
     464        throw new FormatException("File #" + i + 
     465          " (" + files[i] + ") does not exist."); 
     466      } 
     467    } 
    239468 
    240469    // determine reader type for these files; assume all are the same type 
     
    248477    classes.add(r.getClass()); 
    249478 
     479    // construct list of readers for all files 
    250480    readers = new IFormatReader[files.length]; 
    251     if (multipleReaders) { 
    252       // instantiate a reader object of the proper type for each file 
    253       readers[0] = reader; 
    254       for (int i=1; i<readers.length; i++) { 
    255         try { 
    256           r = null; 
    257           for (int j=classes.size()-1; j>=0; j--) { 
    258             Class c = (Class) classes.elementAt(j); 
    259             if (r == null) r = (IFormatReader) c.newInstance(); 
    260             else { 
    261               r = (IFormatReader) c.getConstructor( 
    262                 new Class[] {c}).newInstance(new Object[] {r}); 
    263             } 
    264           } 
    265           readers[i] = (IFormatReader) r; 
    266         } 
    267         catch (InstantiationException exc) { exc.printStackTrace(); } 
    268         catch (IllegalAccessException exc) { exc.printStackTrace(); } 
    269         catch (NoSuchMethodException exc) { exc.printStackTrace(); } 
    270         catch (InvocationTargetException exc) { exc.printStackTrace(); } 
    271       } 
    272     } 
    273     else Arrays.fill(readers, reader); 
    274  
    275     // determine the total number of images and build a list of dimensions 
    276     // for each file 
    277  
    278     int[][] dims = new int[files.length][5]; 
    279  
    280     for (int i=0; i<files.length; i++) { 
    281       imageCounts[i] = readers[i].getImageCount(files[i]); 
    282       numImages += imageCounts[i]; 
    283       dims[i][0] = readers[i].getSizeX(files[i]); 
    284       dims[i][1] = readers[i].getSizeY(files[i]); 
    285       dims[i][2] = readers[i].getSizeZ(files[i]); 
    286       dims[i][3] = readers[i].getSizeC(files[i]); 
    287       dims[i][4] = readers[i].getSizeT(files[i]); 
    288     } 
    289  
    290     // determine how many varying dimensions there are 
    291  
    292     for (int i=1; i<dims.length; i++) { 
    293       varyZ = dims[i][2] != dims[i-1][2]; 
    294       varyC = dims[i][3] != dims[i-1][3]; 
    295       varyT = dims[i][4] != dims[i-1][4]; 
    296     } 
    297  
    298     // always set the width and height to the maximum values 
    299  
    300     for (int i=0; i<dims.length; i++) { 
    301       if (dims[i][0] > dimensions[0]) dimensions[0] = dims[i][0]; 
    302       if (dims[i][1] > dimensions[1]) dimensions[1] = dims[i][1]; 
    303     } 
    304  
    305     if (varyZ || varyC || varyT) { 
    306       int max = 0; 
    307       int maxIndex = 0; 
    308       for (int i=0; i<dims.length; i++) { 
    309         if (dims[i][2] > max) { 
    310           max = dims[i][2]; 
    311           maxIndex = i; 
    312         } 
    313       } 
    314  
    315       dimensions[2] = dims[maxIndex][2]; 
    316     } 
    317     else { 
    318       dimensions[2] = dims[0][2]; 
    319       dimensions[3] = dims[0][3]; 
    320       dimensions[4] = dims[0][4]; 
    321     } 
    322     setDimensions(id, dims); 
    323  
    324     MetadataStore s = reader.getMetadataStore(id); 
    325     s.setPixels(new Integer(dimensions[0]), new Integer(dimensions[1]), 
    326       new Integer(dimensions[2]), new Integer(dimensions[3]), 
    327       new Integer(dimensions[4]), null, null, null, null); 
    328     setMetadataStore(s); 
    329   } 
    330  
    331   /** 
    332    * Set the X, Y, Z, C, and T dimensions; uses some special heuristics on the 
    333    * filename patterns to determine how Z, C and T should be set. 
    334    * 
    335    * @param dims - the dimensions of each file in the dataset 
    336    */ 
    337   private void setDimensions(String id, int[][] dims) 
    338     throws FormatException, IOException 
    339   { 
    340     // first set X and Y 
    341     // this is relatively easy - we can just take the maximum value 
    342  
    343     int maxX = 0; 
    344     int maxY = 0; 
    345  
    346     for (int i=0; i<dims.length; i++) { 
    347       if (dims[i][0] > maxX) { 
    348         maxX = dims[i][0]; 
    349       } 
    350       if (dims[i][1] > maxY) { 
    351         maxY = dims[i][1]; 
    352       } 
    353     } 
    354  
    355     for (int i=0; i<dimensions.length; i++) { 
    356       if (dimensions[i] == 0) dimensions[i]++; 
    357     } 
    358  
    359     // now the tricky part - setting Z, C and T 
    360  
    361     // first we'll get a list of the prefix blocks 
    362  
    363     String[] prefixes = fp.getPrefixes(); 
    364     int[] counts = fp.getCount(); 
    365  
    366     int zSize = 1; 
    367     int cSize = 1; 
    368     int tSize = 1; 
    369  
    370     String ordering = ""; 
    371  
    372     for (int j=0; j<counts.length; j++) { 
    373       // which dimension is this? 
    374  
    375       int zndx = -1; 
    376       int cndx = -1; 
    377       int tndx = -1; 
    378  
    379       String p = prefixes[j].toLowerCase(); 
    380       for (int k=0; k<Z.length; k++) { 
    381         if (p.indexOf(Z[k]) >= 0) zndx = k; 
    382       } 
    383  
    384       if (counts[j] <= 4) { 
    385         for (int k=0; k<C.length; k++) { 
    386           if (p.indexOf(C[k]) >= 0) cndx = k; 
    387         } 
    388       } 
    389  
    390       for (int k=0; k<T.length; k++) { 
    391         if (p.indexOf(T[k]) >= 0) tndx = k; 
    392       } 
    393  
    394       if (zndx >= 0 || cndx >= 0 || tndx >= 0) { 
    395         // the largest of these three is the dimension we will choose 
    396         int zpos = zndx < 0 ? -1 : p.indexOf(Z[zndx]); 
    397         int cpos = cndx < 0 ? -1 : p.indexOf(C[cndx]); 
    398         int tpos = tndx < 0 ? -1 : p.indexOf(T[tndx]); 
    399  
    400         int max = zpos; 
    401         if (cpos > max) max = cpos; 
    402         if (tpos > max) max = tpos; 
    403  
    404         if (max == zpos) { 
    405           ordering += "Z"; 
    406           zSize = counts[j]; 
    407         } 
    408         else if (max == cpos) { 
    409           if (cSize == 1 && !isRGB(id)) { 
    410             ordering += "C"; 
    411             cSize = counts[j]; 
    412           } 
     481    readers[0] = reader; 
     482    for (int i=1; i<readers.length; i++) { 
     483      // use crazy reflection to instantiate a reader of the proper type 
     484      try { 
     485        r = null; 
     486        for (int j=classes.size()-1; j>=0; j--) { 
     487          Class c = (Class) classes.elementAt(j); 
     488          if (r == null) r = (IFormatReader) c.newInstance(); 
    413489          else { 
    414             if (zSize == 1) { 
    415               ordering += "Z"; 
    416               zSize = counts[j]; 
    417             } 
    418             else if (tSize == 1) { 
    419               ordering += "T"; 
    420               tSize = counts[j]; 
    421             } 
    422             else cSize *= counts[j]; 
     490            r = (IFormatReader) c.getConstructor( 
     491              new Class[] {c}).newInstance(new Object[] {r}); 
    423492          } 
    424493        } 
    425         else { 
    426           ordering += "T"; 
    427           tSize = counts[j]; 
    428         } 
     494        readers[i] = (IFormatReader) r; 
    429495      } 
     496      catch (InstantiationException exc) { exc.printStackTrace(); } 
     497      catch (IllegalAccessException exc) { exc.printStackTrace(); } 
     498      catch (NoSuchMethodException exc) { exc.printStackTrace(); } 
     499      catch (InvocationTargetException exc) { exc.printStackTrace(); } 
     500    } 
     501    String f0 = files[0]; 
     502 
     503    // analyze first file; assume each file has the same parameters 
     504    width = reader.getSizeX(f0); 
     505    height = reader.getSizeY(f0); 
     506    imagesPerFile = reader.getImageCount(f0); 
     507    sizeZ = reader.getSizeZ(f0); 
     508    sizeC = reader.getSizeC(f0); 
     509    sizeT = reader.getSizeT(f0); 
     510    int pixelType = reader.getPixelType(f0); 
     511    boolean little = reader.isLittleEndian(f0); 
     512    order = reader.getDimensionOrder(f0); 
     513    boolean certain = reader.isOrderCertain(f0); 
     514 
     515    // guess at dimensions corresponding to file numbering 
     516    ag = new AxisGuesser(fp, order, sizeZ, sizeT, sizeC, certain); 
     517 
     518    // order may need to be adjusted 
     519    order = ag.getAdjustedOrder(); 
     520    reader.swapDimensions(f0, order); 
     521    sizeZ = reader.getSizeZ(f0); 
     522    sizeC = reader.getSizeC(f0); 
     523    sizeT = reader.getSizeT(f0); 
     524 
     525    // compute total axis lengths 
     526    int[] count = fp.getCount(); 
     527    int[] axes = ag.getAxisTypes(); 
     528    int numZ = ag.getAxisCountZ(); 
     529    int numC = ag.getAxisCountC(); 
     530    int numT = ag.getAxisCountT(); 
     531    totalImages = files.length * imagesPerFile; 
     532    totalSizeZ = sizeZ; 
     533    totalSizeC = sizeC; 
     534    totalSizeT = sizeT; 
     535    lenZ = new int[numZ + 1]; 
     536    lenC = new int[numC + 1]; 
     537    lenT = new int[numT + 1]; 
     538    lenZ[0] = sizeZ; 
     539    lenC[0] = sizeC; 
     540    lenT[0] = sizeT; 
     541    int z = 1, c = 1, t = 1; 
     542    for (int i=0; i<axes.length; i++) { 
     543      switch (axes[i]) { 
     544        case AxisGuesser.Z_AXIS: 
     545          totalSizeZ *= count[i]; 
     546          lenZ[z++] = count[i]; 
     547          break; 
     548        case AxisGuesser.C_AXIS: 
     549          totalSizeC *= count[i]; 
     550          lenC[c++] = count[i]; 
     551          break; 
     552        case AxisGuesser.T_AXIS: 
     553          totalSizeT *= count[i]; 
     554          lenT[t++] = count[i]; 
     555          break; 
     556        default: 
     557          throw new FormatException("Unknown axis type for axis #" + 
     558            i + ": " + axes[i]); 
     559      } 
     560    } 
     561 
     562    // populate metadata store 
     563    MetadataStore s = reader.getMetadataStore(f0); 
     564    s.setPixels(new Integer(width), new Integer(height), 
     565      new Integer(totalSizeZ), new Integer(totalSizeC), 
     566      new Integer(totalSizeT), new Integer(pixelType), 
     567      new Boolean(!little), order, null); 
     568    setMetadataStore(s); 
     569  } 
     570 
     571  /** 
     572   * Gets the file index, and image index into that file, 
     573   * corresponding to the given global image index. 
     574   * 
     575   * @return An array of size 2, dimensioned {file index, image index}. 
     576   */ 
     577  protected int[] computeIndices(String id, int no) 
     578    throws FormatException, IOException 
     579  { 
     580    if (!id.equals(currentId)) initFile(id); 
     581 
     582    int[] axes = ag.getAxisTypes(); 
     583    int[] count = fp.getCount(); 
     584 
     585    // get Z, C and T positions 
     586    int[] zct = getZCTCoords(id, no); 
     587    int[] posZ = rasterToPosition(lenZ, zct[0]); 
     588    int[] posC = rasterToPosition(lenC, zct[1]); 
     589    int[] posT = rasterToPosition(lenT, zct[2]); 
     590 
     591    // convert Z, C and T position lists into file index and image index 
     592    int[] pos = new int[axes.length]; 
     593    int z = 1, c = 1, t = 1; 
     594    for (int i=0; i<axes.length; i++) { 
     595      if (axes[i] == AxisGuesser.Z_AXIS) pos[i] = posZ[z++]; 
     596      else if (axes[i] == AxisGuesser.C_AXIS) pos[i] = posC[c++]; 
     597      else if (axes[i] == AxisGuesser.T_AXIS) pos[i] = posT[t++]; 
    430598      else { 
    431         // our simple check failed, so let's try some more complex stuff 
    432  
    433         // if the count is 2 or 3, it's probably a C size 
    434         if (counts[j] == 2 || counts[j] == 3) { 
    435           if (!varyZ && !varyC && !varyT) { 
    436             if (counts[j] != 1) { 
    437               // we already set this dimension 
    438               if (zSize == 1) { 
    439                 zSize = cSize; 
    440                 ordering += "Z"; 
    441               } 
    442               else if (tSize == 1) { 
    443                 tSize = cSize; 
    444                 ordering += "T"; 
    445               } 
    446             } 
    447  
    448             if (ordering.indexOf("C") < 0) ordering += "C"; 
    449             cSize = counts[j]; 
    450           } 
    451         } 
    452         else { 
    453           // the most likely choice is whichever dimension is currently set to 1 
    454  
    455           if (dimensions[2] == 1) { 
    456             ordering += "Z"; 
    457             zSize = counts[j]; 
    458           } 
    459           else if (dimensions[4] == 1) { 
    460             ordering += "T"; 
    461             tSize = counts[j]; 
    462           } 
    463         } 
     599        throw new FormatException("Unknown axis type for axis #" + 
     600          i + ": " + axes[i]); 
    464601      } 
    465602    } 
    466  
    467     // reset the dimensions, preserving internal sizes 
    468  
    469     dimensions[3] *= cSize; 
    470  
    471     if (zSize > 1 && dimensions[2] > 1) { 
    472       if (dimensions[4] == 1) { 
    473         dimensions[4] = dimensions[2]; 
    474         dimensions[2] = zSize; 
     603    int fno = positionToRaster(count, pos); 
     604    int ino = FormatReader.getIndex(order, sizeZ, sizeC, sizeT, 
     605      imagesPerFile, isRGB(id), posZ[0], posC[0], posT[0]); 
     606 
     607    // configure the reader, in case we haven't done this one yet 
     608    readers[fno].setChannelStatCalculationStatus(enableChannelStatCalculation); 
     609    readers[fno].setSeries(files[fno], reader.getSeries(files[0])); 
     610    readers[fno].setIgnoreColorTable(ignoreColorTable); 
     611    readers[fno].swapDimensions(files[fno], order); 
     612 
     613    return new int[] {fno, ino}; 
     614  } 
     615 
     616  /** 
     617   * Gets a list of readers to include in relation to the given C position. 
     618   * @return Array with indices corresponding to the list of readers, and 
     619   *   values indicating the internal channel index to use for that reader. 
     620   */ 
     621  protected int[] getIncludeList(String id, int theC) 
     622    throws FormatException, IOException 
     623  { 
     624    int[] include = new int[readers.length]; 
     625    Arrays.fill(include, -1); 
     626    for (int t=0; t<sizeT; t++) { 
     627      for (int z=0; z<sizeZ; z++) { 
     628        int no = getIndex(id, z, theC, t); 
     629        int[] q = computeIndices(id, no); 
     630        int fno = q[0], ino = q[1]; 
     631        include[fno] = ino; 
    475632      } 
    476       else dimensions[2] *= zSize; 
    477     } 
    478     else dimensions[2] *= zSize; 
    479  
    480     if (tSize > 1 && dimensions[4] > 1) { 
    481       if (dimensions[2] == 1) { 
    482         dimensions[2] = dimensions[4]; 
    483         dimensions[4] = tSize; 
    484       } 
    485       else dimensions[4] *= tSize; 
    486     } 
    487     else dimensions[4] *= tSize; 
    488  
    489     // make sure ordering is right 
    490     String begin = ""; 
    491     String readerOrder = reader.getDimensionOrder(id); 
    492     for (int j=0; j<readerOrder.length(); j++) { 
    493       if (ordering.indexOf(readerOrder.substring(j, j+1)) < 0) { 
    494         begin += readerOrder.substring(j, j+1); 
    495       } 
    496     } 
    497  
    498     ordering = begin + ordering; 
    499     order = ordering.substring(0, 5); 
    500   } 
    501  
    502   /** Determine which file to open, if we want the specified image. */ 
    503   private String findFile(int no) { 
    504     boolean found = false; 
    505     String file = files[0]; 
    506     int ndx = 1; // index into the array of file names 
    507     while (!found) { 
    508       if (no < imageCounts[ndx - 1]) { 
    509         found = true; 
    510       } 
    511       else { 
    512         no -= imageCounts[ndx - 1]; 
    513         file = files[ndx]; 
    514         current = ndx; 
    515         ndx++; 
    516       } 
    517     } 
    518     number = no; 
    519     return file; 
     633    } 
     634    return include; 
     635  } 
     636 
     637  // -- Utility methods -- 
     638 
     639  /** 
     640   * Computes a unique 1-D index corresponding to the multidimensional 
     641   * position given in the pos array, using the specified lengths array 
     642   * as the maximum value at each positional dimension. 
     643   */ 
     644  public static int positionToRaster(int[] lengths, int[] pos) { 
     645    int[] offsets = new int[lengths.length]; 
     646    if (offsets.length > 0) offsets[0] = 1; 
     647    for (int i=1; i<offsets.length; i++) { 
     648      offsets[i] = offsets[i - 1] * lengths[i - 1]; 
     649    } 
     650    int raster = 0; 
     651    for (int i=0; i<pos.length; i++) raster += offsets[i] * pos[i]; 
     652    return raster; 
     653  } 
     654 
     655  /** 
     656   * Computes a unique 3-D position corresponding to the given raster 
     657   * value, using the specified lengths array as the maximum value at 
     658   * each positional dimension. 
     659   */ 
     660  public static int[] rasterToPosition(int[] lengths, int raster) { 
     661    int[] offsets = new int[lengths.length]; 
     662    if (offsets.length > 0) offsets[0] = 1; 
     663    for (int i=1; i<offsets.length; i++) { 
     664      offsets[i] = offsets[i - 1] * lengths[i - 1]; 
     665    } 
     666    int[] pos = new int[lengths.length]; 
     667    for (int i=0; i<pos.length; i++) { 
     668      int q = i < pos.length - 1 ? raster % offsets[i + 1] : raster; 
     669      pos[i] = q / offsets[i]; 
     670      raster -= q; 
     671    } 
     672    return pos; 
     673  } 
     674 
     675  /** 
     676   * Computes the maximum raster value of a positional array with 
     677   * the given maximum values. 
     678   */ 
     679  public static int getRasterLength(int[] lengths) { 
     680    int len = 1; 
     681    for (int i=0; i<lengths.length; i++) len *= lengths[i]; 
     682    return len; 
    520683  } 
    521684 
  • trunk/loci/formats/FormatReader.java

    r1750 r1783  
    103103 
    104104  /** Whether or not to ignore color tables, if present. */ 
    105   protected boolean ignoreColorTable; 
     105  protected boolean ignoreColorTable = false; 
    106106 
    107107  /** 
     
    577577    } 
    578578 
    579     if (stitch) reader = new FileStitcher(reader); 
     579    if (stitch) { 
     580      reader = new FileStitcher(reader, true); 
     581      id = FilePattern.findPattern(new File(map == null ? id : map)); 
     582    } 
    580583    if (separate) reader = new ChannelSeparator(reader); 
    581584    if (merge) reader = new ChannelMerger(reader); 
     
    586589    System.out.println(); 
    587590    System.out.println("Reading core metadata"); 
    588     if (stitch) { 
    589       String p = FilePattern.findPattern(new File(map == null ? id : map)); 
    590       System.out.println("File pattern = " + p); 
    591     } 
    592     else System.out.println("Filename = " + id); 
     591    System.out.println((stitch ? "File pattern" : "Filename") + " = " + id); 
    593592    if (map != null) System.out.println("Mapped filename = " + map); 
    594593    int seriesCount = reader.getSeriesCount(id); 
Note: See TracChangeset for help on using the changeset viewer.