Changeset 6842


Ignore:
Timestamp:
08/24/10 16:42:38 (9 years ago)
Author:
melissa
Message:

Added support for multi-position Zeiss LSM data. Closes #527.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/components/bio-formats/src/loci/formats/in/ZeissLSMReader.java

    r6786 r6842  
    167167  private String binning; 
    168168  private Vector<Double> xCoordinates, yCoordinates; 
     169  private int dimensionM, dimensionP; 
     170  private Hashtable<String, Integer> seriesCounts; 
    169171 
    170172  private int totalROIs = 0; 
     
    213215      xCoordinates = null; 
    214216      yCoordinates = null; 
     217      dimensionM = 0; 
     218      dimensionP = 0; 
     219      seriesCounts = null; 
    215220    } 
    216221  } 
     
    240245      return lsmFilenames; 
    241246    } 
    242     return new String[] {currentId, lsmFilenames[getSeries()]}; 
     247    return new String[] {currentId, getLSMFileFromSeries(getSeries())}; 
    243248  } 
    244249 
     
    293298    FormatTools.checkPlaneParameters(this, no, buf.length, x, y, w, h); 
    294299 
    295     in = new RandomAccessInputStream(lsmFilenames[getSeries()]); 
     300    in = new RandomAccessInputStream(getLSMFileFromSeries(getSeries())); 
    296301    in.order(!isLittleEndian()); 
    297302 
     
    315320      ImageTools.splitChannels(prevBuf, buf, c, getSizeC(), bpp, false, false); 
    316321    } 
    317     else tiffParser.getSamples(ifds.get(no), buf, x, y, w, h); 
     322    else { 
     323      tiffParser.getSamples(ifds.get(no), buf, x, y, w, h); 
     324    } 
    318325    in.close(); 
    319326    return buf; 
     
    347354    xCoordinates = new Vector<Double>(); 
    348355    yCoordinates = new Vector<Double>(); 
    349  
    350     core = new CoreMetadata[lsmFilenames.length]; 
     356    seriesCounts = new Hashtable<String, Integer>(); 
     357 
     358    int seriesCount = 0; 
     359 
     360    for (String filename : lsmFilenames) { 
     361      int extraSeries = getExtraSeries(filename); 
     362      seriesCounts.put(filename, extraSeries); 
     363      seriesCount += extraSeries; 
     364    } 
     365 
     366    core = new CoreMetadata[seriesCount]; 
    351367    ifdsList = new Vector<IFDList>(); 
    352368    ifdsList.setSize(core.length); 
    353     for (int i=0; i<core.length; i++) { 
    354       core[i] = new CoreMetadata(); 
    355       RandomAccessInputStream s = new RandomAccessInputStream(lsmFilenames[i]); 
    356       core[i].littleEndian = s.read() == TiffConstants.LITTLE; 
    357       s.order(isLittleEndian()); 
    358       s.seek(0); 
    359       // calling tp.getNonThumbnailIFDs() would give us the same IFDList, but 
    360       // assuming that every other IFD is a thumbnail reduces the parsing time 
    361       TiffParser tp = new TiffParser(s); 
     369 
     370    int realSeries = 0; 
     371    for (int i=0; i<lsmFilenames.length; i++) { 
     372      RandomAccessInputStream stream = 
     373        new RandomAccessInputStream(lsmFilenames[i]); 
     374      int count = seriesCounts.get(lsmFilenames[i]); 
     375      boolean littleEndian = stream.read() == TiffConstants.LITTLE; 
     376      stream.order(littleEndian); 
     377 
     378      TiffParser tp = new TiffParser(stream); 
    362379      long[] ifdOffsets = tp.getIFDOffsets(); 
    363       IFDList ifds = new IFDList(); 
    364       for (int offset=0; offset<ifdOffsets.length;) { 
    365         ifds.add(tp.getIFD(ifdOffsets[offset])); 
    366         if (ifds.get(0).containsKey(ZEISS_ID)) offset += 2; 
    367         else offset++; 
    368       } 
    369       ifdsList.set(i, ifds); 
    370       s.close(); 
     380      int ifdsPerSeries = (ifdOffsets.length / 2) / count; 
     381 
     382      int offset = 0; 
     383      Object zeissTag = null; 
     384      for (int s=0; s<count; s++, realSeries++) { 
     385        core[realSeries] = new CoreMetadata(); 
     386        core[realSeries].littleEndian = littleEndian; 
     387 
     388        IFDList ifds = new IFDList(); 
     389        while (ifds.size() < ifdsPerSeries) { 
     390          IFD ifd = tp.getIFD(ifdOffsets[offset]); 
     391          if (offset == 0) zeissTag = ifd.get(ZEISS_ID); 
     392          if (offset > 0 && ifds.size() == 0) { 
     393            ifd.putIFDValue(ZEISS_ID, zeissTag); 
     394          } 
     395          ifds.add(ifd); 
     396          if (zeissTag != null) offset += 2; 
     397          else offset++; 
     398        } 
     399        ifdsList.set(realSeries, ifds); 
     400      } 
     401      stream.close(); 
    371402    } 
    372403 
     
    384415 
    385416      // fix the offsets for > 4 GB files 
     417      RandomAccessInputStream s = 
     418        new RandomAccessInputStream(getLSMFileFromSeries(series)); 
    386419      for (int i=1; i<ifds.size(); i++) { 
    387420        long[] stripOffsets = ifds.get(i).getStripOffsets(); 
     
    409442        } 
    410443      } 
     444      s.close(); 
    411445 
    412446      initMetadata(series); 
    413447    } 
     448 
     449    for (int i=0; i<getSeriesCount(); i++) { 
     450      core[i].imageCount = core[i].sizeZ * core[i].sizeC * core[i].sizeT; 
     451    } 
     452 
    414453    MetadataTools.populatePixels(store, this, true); 
    415454    for (int series=0; series<ifdsList.size(); series++) { 
    416455      setSeries(series); 
    417       store.setImageName(imageNames.get(series), series); 
     456      if (series < imageNames.size()) { 
     457        store.setImageName(imageNames.get(series), series); 
     458      } 
    418459      store.setPixelsBinDataBigEndian(!isLittleEndian(), series, 0); 
    419460    } 
     
    444485  } 
    445486 
     487  private int getEffectiveSeries(int currentSeries) { 
     488    int seriesCount = 0; 
     489    for (int i=0; i<lsmFilenames.length; i++) { 
     490      Integer count = seriesCounts.get(lsmFilenames[i]); 
     491      if (count == null) count = 1; 
     492      seriesCount += count; 
     493      if (seriesCount > currentSeries) return i; 
     494    } 
     495    return -1; 
     496  } 
     497 
     498  private String getLSMFileFromSeries(int currentSeries) { 
     499    int effectiveSeries = getEffectiveSeries(currentSeries); 
     500    return effectiveSeries < 0 ? null : lsmFilenames[effectiveSeries]; 
     501  } 
     502 
     503  private int getExtraSeries(String file) throws FormatException, IOException { 
     504    in = new RandomAccessInputStream(file); 
     505    boolean littleEndian = in.read() == TiffConstants.LITTLE; 
     506    in.order(littleEndian); 
     507 
     508    tiffParser = new TiffParser(in); 
     509    IFD ifd = tiffParser.getFirstIFD(); 
     510    RandomAccessInputStream ras = getCZTag(ifd); 
     511    if (ras == null) return 1; 
     512    ras.order(littleEndian); 
     513 
     514    ras.seek(264); 
     515    dimensionP = ras.readInt(); 
     516    dimensionM = ras.readInt(); 
     517    ras.close(); 
     518 
     519    int nSeries = dimensionM * dimensionP; 
     520    return nSeries <= 0 ? 1 : nSeries; 
     521  } 
     522 
     523  private int getPosition(int currentSeries) { 
     524    int effectiveSeries = getEffectiveSeries(currentSeries); 
     525    int firstPosition = 0; 
     526    for (int i=0; i<effectiveSeries; i++) { 
     527      firstPosition += seriesCounts.get(lsmFilenames[i]); 
     528    } 
     529    return currentSeries - firstPosition; 
     530  } 
     531 
     532  private RandomAccessInputStream getCZTag(IFD ifd) 
     533    throws FormatException, IOException 
     534  { 
     535    // get TIF_CZ_LSMINFO structure 
     536    short[] s = ifd.getIFDShortArray(ZEISS_ID); 
     537    if (s == null) { 
     538      LOGGER.warn("Invalid Zeiss LSM file. Tag {} not found.", ZEISS_ID); 
     539      TiffReader reader = new TiffReader(); 
     540      reader.setId(getLSMFileFromSeries(series)); 
     541      core[getSeries()] = reader.getCoreMetadata()[0]; 
     542      reader.close(); 
     543      return null; 
     544    } 
     545    byte[] cz = new byte[s.length]; 
     546    for (int i=0; i<s.length; i++) { 
     547      cz[i] = (byte) s[i]; 
     548    } 
     549 
     550    RandomAccessInputStream ras = new RandomAccessInputStream(cz); 
     551    ras.order(isLittleEndian()); 
     552    return ras; 
     553  } 
     554 
    446555  protected void initMetadata(int series) throws FormatException, IOException { 
    447556    setSeries(series); 
     
    449558    IFD ifd = ifds.get(0); 
    450559 
    451     in = new RandomAccessInputStream(lsmFilenames[series]); 
     560    in = new RandomAccessInputStream(getLSMFileFromSeries(series)); 
    452561    in.order(isLittleEndian()); 
    453562 
     
    471580    MetadataStore store = makeFilterMetadata(); 
    472581 
    473     String imageName = lsmFilenames[series]; 
     582    int instrument = getEffectiveSeries(series); 
     583 
     584    String imageName = getLSMFileFromSeries(series); 
    474585    if (imageName.indexOf(".") != -1) { 
    475586      imageName = imageName.substring(0, imageName.lastIndexOf(".")); 
     
    479590        imageName.substring(imageName.lastIndexOf(File.separator) + 1); 
    480591    } 
     592    if (lsmFilenames.length != getSeriesCount()) { 
     593      imageName += " #" + (getPosition(series) + 1); 
     594    } 
    481595 
    482596    // link Instrument and Image 
    483597    store.setImageID(MetadataTools.createLSID("Image", series), series); 
    484     String instrumentID = MetadataTools.createLSID("Instrument", series); 
    485     store.setInstrumentID(instrumentID, series); 
     598    String instrumentID = MetadataTools.createLSID("Instrument", instrument); 
     599    store.setInstrumentID(instrumentID, instrument); 
    486600    store.setImageInstrumentRef(instrumentID, series); 
    487601 
    488     // get TIF_CZ_LSMINFO structure 
    489     short[] s = ifd.getIFDShortArray(ZEISS_ID); 
    490     if (s == null) { 
    491       LOGGER.warn("Invalid Zeiss LSM file. Tag {} not found.", ZEISS_ID); 
    492       TiffReader reader = new TiffReader(); 
    493       reader.setId(lsmFilenames[series]); 
    494       core[series] = reader.getCoreMetadata()[0]; 
    495       reader.close(); 
     602    RandomAccessInputStream ras = getCZTag(ifd); 
     603    if (ras == null) { 
    496604      imageNames.add(imageName); 
    497605      return; 
    498606    } 
    499     byte[] cz = new byte[s.length]; 
    500     for (int i=0; i<s.length; i++) { 
    501       cz[i] = (byte) s[i]; 
    502     } 
    503  
    504     RandomAccessInputStream ras = new RandomAccessInputStream(cz); 
    505     ras.order(isLittleEndian()); 
    506607 
    507608    ras.seek(16); 
     
    550651      addSeriesMeta("OriginZ", ras.readDouble()); 
    551652    } 
    552     else ras.seek(56); 
     653    else ras.seek(88); 
    553654 
    554655    int scanType = ras.readShort(); 
     
    646747    if (getSizeT() == 0) core[series].sizeT = getImageCount() / getSizeZ(); 
    647748 
    648     MetadataTools.setDefaultCreationDate(store, getCurrentFile(), series); 
    649     if (getSizeC() > 1) { 
    650       if (!splitPlanes) splitPlanes = isRGB(); 
    651       core[series].rgb = false; 
    652       if (splitPlanes) core[series].imageCount *= getSizeC(); 
    653     } 
    654  
    655     for (int c=0; c<getEffectiveSizeC(); c++) { 
    656       String lsid = MetadataTools.createLSID("Channel", series, c); 
    657       store.setChannelID(lsid, series, c); 
    658     } 
     749    long channelColorsOffset = 0; 
     750    long timeStampOffset = 0; 
     751    long eventListOffset = 0; 
     752    long scanInformationOffset = 0; 
    659753 
    660754    if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) { 
     
    686780      overlayOffsets[2] = ras.readInt(); 
    687781 
    688       long channelColorsOffset = ras.readInt(); 
     782      channelColorsOffset = ras.readInt(); 
    689783 
    690784      addSeriesMeta("TimeInterval", ras.readDouble()); 
    691785      ras.skipBytes(4); 
    692       long scanInformationOffset = ras.readInt(); 
     786      scanInformationOffset = ras.readInt(); 
    693787      ras.skipBytes(4); 
    694       long timeStampOffset = ras.readInt(); 
    695       long eventListOffset = ras.readInt(); 
     788      timeStampOffset = ras.readInt(); 
     789      eventListOffset = ras.readInt(); 
    696790      overlayOffsets[3] = ras.readInt(); 
    697791      overlayOffsets[4] = ras.readInt(); 
     
    720814 
    721815      int wavelengthOffset = ras.readInt(); 
    722       ras.skipBytes(56); 
    723       int dimensionP = ras.readInt(); 
    724       int dimensionM = ras.readInt(); 
    725  
     816      ras.skipBytes(64); 
     817    } 
     818    else ras.skipBytes(182); 
     819 
     820    MetadataTools.setDefaultCreationDate(store, getCurrentFile(), series); 
     821    if (getSizeC() > 1) { 
     822      if (!splitPlanes) splitPlanes = isRGB(); 
     823      core[series].rgb = false; 
     824      if (splitPlanes) core[series].imageCount *= getSizeC(); 
     825    } 
     826 
     827    for (int c=0; c<getEffectiveSizeC(); c++) { 
     828      String lsid = MetadataTools.createLSID("Channel", series, c); 
     829      store.setChannelID(lsid, series, c); 
     830    } 
     831 
     832    if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) { 
    726833      // NB: the Zeiss LSM 5.5 specification indicates that there should be 
    727834      //     15 32-bit integers here; however, there are actually 16 32-bit 
    728835      //     integers before the tile position offset. 
     836      //     We have confirmed with Zeiss that this is correct. 
    729837      ras.skipBytes(64); 
    730838 
     
    9361044        } 
    9371045        if (xCoordinates.size() > 0) { 
    938           int stage = i / (getImageCount() / xCoordinates.size()); 
     1046          double planesPerStage = 
     1047            (double) getImageCount() / xCoordinates.size(); 
     1048          int stage = (int) (i / planesPerStage); 
    9391049          store.setPlanePositionX(xCoordinates.get(stage), series, i); 
    9401050          store.setPlanePositionY(yCoordinates.get(stage), series, i); 
     
    9541064    } 
    9551065 
     1066    int instrument = getEffectiveSeries(series); 
     1067 
    9561068    // NB: block.acquire can be false.  If that is the case, Instrument data 
    9571069    // is the only thing that should be populated. 
    9581070    if (block instanceof Recording) { 
    9591071      Recording recording = (Recording) block; 
    960       String objectiveID = MetadataTools.createLSID("Objective", series, 0); 
     1072      String objectiveID = MetadataTools.createLSID("Objective", instrument, 0); 
    9611073      if (recording.acquire) { 
    9621074        store.setImageDescription(recording.description, series); 
     
    9661078      } 
    9671079      store.setObjectiveCorrection( 
    968         getCorrection(recording.correction), series, 0); 
    969       store.setObjectiveImmersion(getImmersion(recording.immersion), series, 0); 
     1080        getCorrection(recording.correction), instrument, 0); 
     1081      store.setObjectiveImmersion( 
     1082        getImmersion(recording.immersion), instrument, 0); 
    9701083      if (recording.magnification != null && recording.magnification > 0) { 
    9711084        store.setObjectiveNominalMagnification( 
    972           new PositiveInteger(recording.magnification), series, 0); 
    973       } 
    974       store.setObjectiveLensNA(recording.lensNA, series, 0); 
    975       store.setObjectiveIris(recording.iris, series, 0); 
    976       store.setObjectiveID(objectiveID, series, 0); 
     1085          new PositiveInteger(recording.magnification), instrument, 0); 
     1086      } 
     1087      store.setObjectiveLensNA(recording.lensNA, instrument, 0); 
     1088      store.setObjectiveIris(recording.iris, instrument, 0); 
     1089      store.setObjectiveID(objectiveID, instrument, 0); 
    9771090    } 
    9781091    else if (block instanceof Laser) { 
     
    9801093      if (laser.medium != null) { 
    9811094        store.setLaserLaserMedium(getLaserMedium(laser.medium), 
    982           series, nextLaser); 
     1095          instrument, nextLaser); 
    9831096      } 
    9841097      if (laser.type != null) { 
    985         store.setLaserType(getLaserType(laser.type), series, nextLaser); 
     1098        store.setLaserType(getLaserType(laser.type), instrument, nextLaser); 
    9861099      } 
    9871100      if (laser.model != null) { 
    988         store.setLaserModel(laser.model, series, nextLaser); 
     1101        store.setLaserModel(laser.model, instrument, nextLaser); 
    9891102      } 
    9901103      String lightSourceID = 
    991         MetadataTools.createLSID("LightSource", series, nextLaser); 
    992       store.setLaserID(lightSourceID, series, nextLaser); 
     1104        MetadataTools.createLSID("LightSource", instrument, nextLaser); 
     1105      store.setLaserID(lightSourceID, instrument, nextLaser); 
    9931106      nextLaser++; 
    9941107    } 
     
    10151128      } 
    10161129      if (channel.filter != null) { 
    1017         String id = MetadataTools.createLSID("Filter", series, nextFilter); 
     1130        String id = MetadataTools.createLSID("Filter", instrument, nextFilter); 
    10181131        if (channel.acquire && nextDetectChannel < getSizeC()) { 
    1019           store.setLightPathEmissionFilterRef(id, series, nextDetectChannel, 0); 
    1020         } 
    1021         store.setFilterID(id, series, nextFilter); 
    1022         store.setFilterModel(channel.filter, series, nextFilter); 
     1132          store.setLightPathEmissionFilterRef( 
     1133            id, instrument, nextDetectChannel, 0); 
     1134        } 
     1135        store.setFilterID(id, instrument, nextFilter); 
     1136        store.setFilterModel(channel.filter, instrument, nextFilter); 
    10231137 
    10241138        int space = channel.filter.indexOf(" "); 
     
    10281142          else if (type.equals("LP")) type = "LongPass"; 
    10291143 
    1030           store.setFilterType(getFilterType(type), series, nextFilter); 
     1144          store.setFilterType(getFilterType(type), instrument, nextFilter); 
    10311145 
    10321146          String transmittance = channel.filter.substring(space + 1).trim(); 
     
    10341148          try { 
    10351149            store.setTransmittanceRangeCutIn( 
    1036                 PositiveInteger.valueOf(v[0].trim()), series, nextFilter); 
     1150              PositiveInteger.valueOf(v[0].trim()), instrument, nextFilter); 
    10371151          } 
    10381152          catch (NumberFormatException e) { } 
     
    10401154            try { 
    10411155              store.setTransmittanceRangeCutOut( 
    1042                   PositiveInteger.valueOf(v[1].trim()), series, nextFilter); 
     1156                PositiveInteger.valueOf(v[1].trim()), instrument, nextFilter); 
    10431157            } 
    10441158            catch (NumberFormatException e) { } 
     
    10501164      if (channel.channelName != null) { 
    10511165        String detectorID = 
    1052           MetadataTools.createLSID("Detector", series, nextDetector); 
    1053         store.setDetectorID(detectorID, series, nextDetector); 
     1166          MetadataTools.createLSID("Detector", instrument, nextDetector); 
     1167        store.setDetectorID(detectorID, instrument, nextDetector); 
    10541168        if (channel.acquire && nextDetector < getSizeC()) { 
    10551169          store.setDetectorSettingsID(detectorID, series, nextDetector); 
     
    10591173      } 
    10601174      if (channel.amplificationGain != null) { 
    1061         store.setDetectorAmplificationGain(channel.amplificationGain, series, 
    1062           nextDetector); 
     1175        store.setDetectorAmplificationGain( 
     1176          channel.amplificationGain, instrument, nextDetector); 
    10631177      } 
    10641178      if (channel.gain != null) { 
    1065         store.setDetectorGain(channel.gain, series, nextDetector); 
    1066       } 
    1067       store.setDetectorType(getDetectorType("PMT"), series, nextDetector); 
    1068       store.setDetectorZoom(zoom, series, nextDetector); 
     1179        store.setDetectorGain(channel.gain, instrument, nextDetector); 
     1180      } 
     1181      store.setDetectorType(getDetectorType("PMT"), instrument, nextDetector); 
     1182      store.setDetectorZoom(zoom, instrument, nextDetector); 
    10691183      nextDetectChannel++; 
    10701184      nextDetector++; 
     
    10741188      if (beamSplitter.filterSet != null) { 
    10751189        if (beamSplitter.filter != null) { 
    1076           String id = 
    1077             MetadataTools.createLSID("Dichroic", series, nextDichroic); 
    1078           store.setDichroicID(id, series, nextDichroic); 
    1079           store.setDichroicModel(beamSplitter.filter, series, nextDichroic); 
     1190          String id = MetadataTools.createLSID( 
     1191            "Dichroic", instrument, nextDichroic); 
     1192          store.setDichroicID(id, instrument, nextDichroic); 
     1193          store.setDichroicModel(beamSplitter.filter, instrument, nextDichroic); 
    10801194          if (nextDichroicChannel < getEffectiveSizeC()) { 
    10811195            store.setLightPathDichroicRef(id, series, nextDichroicChannel); 
Note: See TracChangeset for help on using the changeset viewer.