Page 1 of 1

events and timestamps in lsm files

PostPosted: Wed Mar 16, 2011 7:26 pm
by dwight
I'm trying to use bfconvert to convert my LSM files into OME-XML. Unfortunately, all the data I need is not present in the XML. During my experiment I apply electrical stimulation (marked by events in LSM) and sometimes pause acquisition, so it is necessary for me to retrieve data about events and timestamps from the LSM file. In my python code, that I've been using so far, it's relatively easy for me to read the data at OffsetEvenList and OffsetTimeStamps locations in the LSM. I see that in OMEXMLMetadata class I might be able to access timestamp information, but how to go about finding event info? The strange thing is that showinf command actually displays all the event data, but I'm not sure how to access it.

Thanks

Re: events and timestamps in lsm files

PostPosted: Mon Mar 21, 2011 9:52 pm
by mlinkert
Hi,

I'm trying to use bfconvert to convert my LSM files into OME-XML. Unfortunately, all the data I need is not present in the XML. During my experiment I apply electrical stimulation (marked by events in LSM) and sometimes pause acquisition, so it is necessary for me to retrieve data about events and timestamps from the LSM file. In my python code, that I've been using so far, it's relatively easy for me to read the data at OffsetEvenList and OffsetTimeStamps locations in the LSM. I see that in OMEXMLMetadata class I might be able to access timestamp information, but how to go about finding event info? The strange thing is that showinf command actually displays all the event data, but I'm not sure how to access it.


All of the metadata that you see with the showinf command will be preserved if you convert the file to OME-TIFF, but if there is no corresponding place for it in the OME-XML schema it will be stored in the XMLAnnotation elements under the top-level StructuredAnnotations element. For example, if you see this key/value pair in the output from showinf:

Code: Select all
Recording #1 Special Scan Mode: FocusStep


then the corresponding piece of OME-XML would be:

Code: Select all
<XMLAnnotation ID="Annotation:0">
         <Value>
            <OriginalMetadata xmlns="openmicroscopy.org/OriginalMetadata">
               <Key>Recording #1 Special Scan Mode</Key>
               <Value>FocusStep</Value>
            </OriginalMetadata>
         </Value>
  </XMLAnnotation>


Note that you may need to update to the latest trunk build of Bio-Formats in order for the metadata to be preserved correctly, as there was a (recently fixed) bug that prevented some of the metadata from being stored in XMLAnnotations.

You can retrieve all of the XMLAnnotations from an OMEXMLMetadata object as follows:

Code: Select all
//metadata is an instance of MetadataRetrieve (e.g. OMEXMLMetadata)
int numAnnotations = metadata.getXMLAnnotationCount();
for (int i=0; i<numAnnotations; i++) {
  String xml = metadata.getXMLAnnotationValue(i);
}


You can then parse the 'xml' Strings to find the key and value.

Hopefully that helps, but please do let us know if you have any further questions.

Regards,
-Melissa

Re: events and timestamps in lsm files

PostPosted: Wed Mar 23, 2011 3:53 pm
by dwight
Thanks for the detailed reply! :) I'll try to see if I can manage to extract the metadata I need from the XML. This should work for events embedded in LSM files, I hope. However, for timestamps I'm not as optimistic. I was looking around in the ZeissLSMReader class and it seems that only timestamps indicating frames are extracted from the LSM. This is problematic for me because I use linescan images and it is necessary for me to know the timestamp of each line. Right now all but the first are ignored by the reader. I understand, of course, that extracting and retaining thousands of timestamps in the XML might not be necessary for most users. I've been trying to append the extra timestamps in the timestamp vector (make it a vector of timestamp vectors instead of it being a vector of image stack timestamps). Hopefully this way I'll manage to squeeze out all I need from the LSMs.

Re: events and timestamps in lsm files

PostPosted: Fri Mar 25, 2011 1:55 pm
by mlinkert
Hi,

However, for timestamps I'm not as optimistic. I was looking around in the ZeissLSMReader class and it seems that only timestamps indicating frames are extracted from the LSM. This is problematic for me because I use linescan images and it is necessary for me to know the timestamp of each line. Right now all but the first are ignored by the reader. I understand, of course, that extracting and retaining thousands of timestamps in the XML might not be necessary for most users. I've been trying to append the extra timestamps in the timestamp vector (make it a vector of timestamp vectors instead of it being a vector of image stack timestamps). Hopefully this way I'll manage to squeeze out all I need from the LSMs.


I've just committed a fix to ZeissLSMReader that will hopefully solve that problem:

http://git.openmicroscopy.org/?p=biofor ... 880e8e4d82

The latest trunk build of Bio-Formats also contains that fix. If that does not solve the problem or if you have changes to ZeissLSMReader that you would like included in Bio-Formats' Git repository, please just let us know.

Regards,
-Melissa

Re: events and timestamps in lsm files

PostPosted: Tue Mar 29, 2011 8:36 pm
by dwight
I was pleasantly surprised to see from my today's git pull that you had made changes to the timestamp handling. I had already ventured into the unkown by myself and made necessary changes to my local version. The change that you have made makes me wonder if this change is compatible with LSM stacks where people probably want recording times of stacks rather than individual lines in the stack. But I haven't checked you new code with such an LSM so it might just work fine after all.
In case you might be interested I'll include below the diff from the changes I made, to get ZeissLSMReader to work like I need it to. Basically I did two things:
1) timestamps are saved in a Vector<Vector<Double>> so that each stack image would have its own timestamps (don't have stacks though so don't know if it actually works). Also, updated the timestamp retrieval code to extract the stamp from the appropriate place.
2) After I had done this it became obvious that 10000 timestamps worth of XML annotation tags takes quite a few megabytes and made processing quite slow to boot. So in order to avoid this, for metadata I grouped 250 timestamps together into a string and save it as a single annotation( I would have put more but there seems to be a limit to how much characters a tag can hold). Makes things more compact and faster. Of course, it's kind of a hack, but for my purposes it's sufficient.

The diff itself is as follows:
Code: Select all
diff --git a/components/bio-formats/src/loci/formats/in/ZeissLSMReader.java b/components/bio-formats/src/loci/formats/in/Zeiss
index f02ffb3..0a0aaf4 100644
--- a/components/bio-formats/src/loci/formats/in/ZeissLSMReader.java
+++ b/components/bio-formats/src/loci/formats/in/ZeissLSMReader.java
@@ -153,7 +153,7 @@ public class ZeissLSMReader extends FormatReader {

   private double pixelSizeX, pixelSizeY, pixelSizeZ;
   private byte[][][] lut = null;
-  private Vector<Double> timestamps;
+  private Vector<Vector<Double>> timestamps;
   private int validChannels;

   private String[] lsmFilenames;
@@ -392,7 +392,7 @@ public class ZeissLSMReader extends FormatReader {
       throw new FormatException("LSM files were not found.");
     }

-    timestamps = new Vector<Double>();
+    timestamps = new Vector<Vector<Double>>();
     imageNames = new Vector<String>();
     xCoordinates = new Vector<Double>();
     yCoordinates = new Vector<Double>();
@@ -1015,12 +1015,44 @@ public class ZeissLSMReader extends FormatReader {
       }

       if (timeStampOffset != 0) {
-        in.seek(timeStampOffset + 8);
+//        in.seek(timeStampOffset + 8);
+        in.seek(timeStampOffset);
+        int timeStampsSize = in.readInt();
+        int timeStampsCount = in.readInt();
         for (int i=0; i<getSizeT(); i++) {
-          double stamp = in.readDouble();
-          addSeriesMeta("TimeStamp" + i, stamp);
-          timestamps.add(new Double(stamp));
+            timestamps.add(new Vector<Double>());
+            int stampsPerAnnotation = 250;
+            int timestampsSaved=0;
+            for(int j=0; j<timeStampsCount;j++){
+              if(j>0 && j%stampsPerAnnotation==0){
+                String stampsString = "";
+                for(int k=0; k<stampsPerAnnotation;k++){
+                    if(k>0){
+                        stampsString+=" ";
+                    }
+                    stampsString += timestamps.get(i).get((j/stampsPerAnnotation-1)*stampsPerAnnotation + k);
+                }
+                addSeriesMeta("TimeStamp" + j/stampsPerAnnotation, stampsString);
+               
+                timestampsSaved += stampsPerAnnotation;
+              }
+              double stamp = in.readDouble();
+              timestamps.get(i).add(new Double(stamp));
+            }
+            if(timestampsSaved<timeStampsCount){
+                String stampsString = "";
+                for(int k=timestampsSaved; k<timeStampsCount; k++){
+                    if(k>0){
+                        stampsString+=" ";
+                    }
+                    stampsString += timestamps.get(i).get(k);
+                }
+                int last = timestampsSaved/stampsPerAnnotation + 1;
+                addSeriesMeta("TimeStamp" + last, stampsString);
+
+            }
         }
+
       }

       if (eventListOffset != 0) {
@@ -1174,20 +1206,20 @@ public class ZeissLSMReader extends FormatReader {

       double firstStamp = 0;
       if (timestamps.size() > 0) {
-        firstStamp = timestamps.get(0).doubleValue();
+        firstStamp = timestamps.get(0).get(0).doubleValue();
       }

       for (int i=0; i<getImageCount(); i++) {
         int[] zct = FormatTools.getZCTCoords(this, i);

         if (zct[2] < timestamps.size()) {
-          double thisStamp = timestamps.get(zct[2]).doubleValue();
+          double thisStamp = timestamps.get(zct[2]).get(0).doubleValue();
           store.setPlaneDeltaT(thisStamp - firstStamp, series, i);
           int index = zct[2] + 1;
           double nextStamp = index < timestamps.size() ?
-            timestamps.get(index).doubleValue() : thisStamp;
+            timestamps.get(index).get(0).doubleValue() : thisStamp;
           if (i == getSizeT() - 1 && zct[2] > 0) {
-            thisStamp = timestamps.get(zct[2] - 1).doubleValue();
+            thisStamp = timestamps.get(zct[2] - 1).get(0).doubleValue();
           }
           store.setPlaneExposureTime(nextStamp - thisStamp, series, i);
         }
@@ -1197,6 +1229,7 @@ public class ZeissLSMReader extends FormatReader {
           store.setPlanePositionZ(zCoordinates.get(series), series, i);
         }


Re: events and timestamps in lsm files

PostPosted: Wed Apr 06, 2011 2:14 am
by mlinkert
The change that you have made makes me wonder if this change is compatible with LSM stacks where people probably want recording times of stacks rather than individual lines in the stack. But I haven't checked you new code with such an LSM so it might just work fine after all.


I did test against that exact type of LSM, and it seems to work just fine. If you encounter any problems, though, please do let us know.

Basically I did two things:

*snip*
2) After I had done this it became obvious that 10000 timestamps worth of XML annotation tags takes quite a few megabytes and made processing quite slow to boot. So in order to avoid this, for metadata I grouped 250 timestamps together into a string and save it as a single annotation( I would have put more but there seems to be a limit to how much characters a tag can hold). Makes things more compact and faster. Of course, it's kind of a hack, but for my purposes it's sufficient.


If that works for you, then that's great. We are aware that large numbers of XMLAnnotation elements can be a bit cumbersome to work with, but have not yet come up with a good general purpose solution.

-Melissa