Message Boards Message Boards

GROUPS:

Extract ROIs from TIF image

Posted 2 months ago
470 Views
|
3 Replies
|
4 Total Likes
|

Hello all,

I am working a lot with Mathematica and Fiji/ImageJ, and would like to extract data saved in the tif file. In Fiji, there is a possibility to save ROI information as an overlay in an image which can be displayed or saved via the ROI manager.

However, when I open the tif files in Mathematica, I cannot find the ROI data, also not in the other elements besides the image data. Maybe there is a different way to access the information?

What I tried was:

d0 = Import["01.tif", "Elements"]

{"Animation", "Author", "BitDepth", "CameraTopOrientation", \
"Channels", "ColorMap", "ColorProfileData", "ColorSpace", "Comments", \
"CopyrightNotice", "Data", "DateTime", "Device", \
"DeviceManufacturer", "Exif", "FlashUsed", "GeoPosition", \
"GPSDateTime", "Graphics", "GraphicsList", "Image", "Image3D", \
"ImageCount", "ImageCreationDate", "ImageEncoding", "ImageList", \
"ImageResolution", "ImageSize", "IPTC", "MakerNote", "RawData", \
"RawExif", "RawIPTC", "RawXMP", "RedEyeCorrection", "RowsPerStrip", \
"Summary", "SummarySlideView", "Thumbnail", "ThumbnailList", \
"TileSize", "XMP"}

What I import any of these elements individually, they do not contain the overlay information. Is Mathematica not able to extract the overlay information containing the ROIs?

Thanks!

Max

3 Replies
Posted 1 month ago

This is fine if you work only in ImageJ or Fiji, but unfortunately if you try to view your ROIs in other software it is highly unlikely to work properly, since the format is specific to ImageJ. The way around this is to use the Image ▸ Overlay ▸ Flatten command. This creates an RGB copy of the image in which the pixel values have been changed so that any ROIs or overlays will appear whenever you open the image elsewhere. Therefore you may well want to use this command when creating figures or presentations, but you do not want to subsequently apply your analysis to the image you have flattened – always use the original instead.

Source: https://petebankhead.gitbooks.io/imagej-intro/content/chapters/rois/rois.html

There is a larger issue how Mathematica interprets and represents image files. You can try to use Options function, but no guarantee that you will find your ROIS as data hidden under another tag.

This stack exchange page was useful in finding out how to maliciously insert a Shakespearean monologue where it doesn't belong, of course, in the Lena Pic (their moderators may have some work to do). While we're on the subject, here's an example of what not to do:

IDK

I stole this JPG from Jon McLoone's latest blog post before he could even turn it into an official Wolfram NFT (sorry, joke). Checking the metadata, we can suspect that it wasn't even made with Mathematica.

im1 = Import["~/Pictures/wolfram-open-source-hero.jpg"];
Export["~/Pictures/wosQ.jpg", im1];
im2 = Import["~/Pictures/wosQ.jpg"];
Options /@ {im1, im2}

Out[]={{ColorSpace -> "RGB", Interleaving -> True}, {ColorSpace -> "RGB", 
  ImageResolution -> {72, 72}, Interleaving -> True, 
  MetaInformation -> <|"Exif" -> <|"Software" -> 
       "Created with the Wolfram Language for Students - Personal Use \
Only : www.wolfram.com"|>|>}}

Why? It looks like Mathematica has a greedy image handling property, where it always writes ownership information on export. I don't know if this holds only for student versions? If you are hiding something important, beware it could be automatically erased.

im3 = Image[im2,  MetaInformation -> <|"Exif" -> <|"Software" -> "ImageMagick"|>|>];
Export["~/Pictures/wosQ2.jpg", im3];
im4 = Import["~/Pictures/wosQ2.jpg"];
Options[#] & /@ {im3, im4}

Out[]={{ColorSpace -> "RGB", ImageResolution -> {72, 72}, 
  Interleaving -> True, 
  MetaInformation -> <|"Exif" -> <|"Software" -> 
       "ImageMagick"|>|>}, {ColorSpace -> "RGB", 
  ImageResolution -> {72, 72}, Interleaving -> True, 
  MetaInformation -> <|"Exif" -> <|"Software" -> 
       "Created with the Wolfram Language for Students - Personal Use \
Only : www.wolfram.com", 
      "DateTime" -> 
       DateObject[{2021, 12, 3, 10, 11, 23.}, "Instant", 
        "Gregorian", -6.]|>|>}}

This is one reason Mathematica is not like open source, because some users (at least) don't have control over metadata. Sorry to go a little off-topic here, but a bigger question is whether all image handling needs to be reworked in the future.

If mathematica doesn't work for your problem, try using ImageMagick with verbose flag. If that doesn't reveal anything, another possibility is that the data itself has a hidden channel, see for example this other blog post by Jon McLoone.

Hi Brad,

thanks for your suggestions and the insight into the metadata manipulation of Mathematica :-) I do not have a student version but a regular license for academic use, but it also changes the meta information. Actually a lot more than in your example has changed in the meta information.

Although the idea with flattening the image that you cited does works, the results are not optimal. First, it generates the flattened image as it is displayed, which is not very pretty; e.g. the ROIs have some anti-aliasing artifacts. Also, the ROI definition in recent versions of ImageJ contains subpixel information. This information obviously is lost in the resulting image. A workaround that I found (and use now) is to export the ROI(s) through ImageJ's Overlay Manager, and then extract the information from the exported .roi files.

I found a well documented decoder for the .roi format here:

https://github.com/DylanMuir/ReadImageJROI/blob/master/ReadImageJROI.m

It is not too difficult to extract the relevant information.

In[1]:= d0 = 
  Import["E:\\Projects Freiburg\\Projects\\FITC Machine Learning\\ROI\
\\2-cell.roi", "Byte"];
Length[d0]

Out[2]= 10012

In[27]:= fc2 = 256 #[[1]] + #[[2]] &;
fc4 = 256^3 #[[1]] + 256^2 #[[2]] + 256 #[[3]] + #[[4]] &;
fc4r = ImportString[StringJoin@(FromCharacterCode /@ Reverse[#]), 
     "Real32"][[1]] &;

In[6]:= Print[StringJoin@(FromCharacterCode /@ d0[[1 ;; 4]])];
Print["Version: ", fc2@d0[[5 ;; 6]]];
Print["ROI type: ", d0[[7]]];
Print["Top: ", fc2@d0[[9 ;; 10]]];
Print["Left: ", fc2@d0[[11 ;; 12]]];
Print["Bottom: ", fc2@d0[[13 ;; 14]]];
Print["Right: ", fc2@d0[[15 ;; 16]]];
Print["NCoordinates: ", nc = fc2@d0[[17 ;; 18]]];
Print["x1,y1,x2,y2 (straight line) | x,y,width,height (double rect) | \
size (npoints): ", fc4r /@ Partition[d0[[19 ;; 34]], 4]];
Print["Other info: ", d0[[35 ;; 56]]];
Print["Position: ", fc2 /@ Partition[d0[[57 ;; 60]], 2]];
Print["Header 2 offset: ", nHeader2offset = fc4@d0[[61 ;; 64]]];
Print["Header 2 : "];
d0[[nHeader2offset + 1 ;; Length[d0]]]
Print["vnNameParams offset: ", 
  vnNameParamsoff = 
   fc4@d0[[nHeader2offset + 1 + 16 ;; nHeader2offset + 20]]];
Print["vnNameParams length: ", 
  vnNameParamslen = 
   fc4@d0[[nHeader2offset + 1 + 20 ;; nHeader2offset + 24]]];
Print["ROI Name: ", 
  StringJoin@(FromCharacterCode /@ 
     fc2 /@ Partition[
       d0[[vnNameParamsoff + 1 ;; 
         vnNameParamsoff + vnNameParamslen*2]], 2])];
poly1 = Transpose[
   Partition[fc2 /@ Partition[d0[[65 ;; 4 nc + 64]], 2], nc]];
poly = If[BitAnd[d0[[52]], 128] == 128, 
   poly2 = Transpose[
     Partition[fc4r /@ Partition[d0[[4 nc + 65 ;; 12 nc + 64]], 4], 
      nc]], poly1];
Graphics[{FaceForm[None], EdgeForm[Black], Polygon[poly]}]
Graphics[{FaceForm[None], EdgeForm[Black], 
  Polygon[Split[poly1][[All, 1]]]}]


Iout
Version: 227
ROI type: 7
Top: 79
Left: 296
Bottom: 134
Right: 335
NCoordinates: 823
x1,y1,x2,y2 (straight line) | x,y,width,height (double rect) | size (npoints): {0.,0.,0.,0.}
Other info: {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0}
Position: {0,0}
Header 2 offset: 9940
Header 2 : 
 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, \
    20, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
    99, 0, 101, 0, 108, 0, 108}
vnNameParams offset: 10004
vnNameParams length: 4
ROI Name: cell

enter image description here

enter image description here

Cheers,

Max

Posted 1 month ago

Hi Max,

I agree, flattening is a bad idea. Good for you figuring out how to make an extra file. In the future when storing data, it looks like every record will have metadata, which can point to other files such as "regions of interest", especially in biophysics, ha ha. Here's an example from Wolfram, one of the NFT images as per this thread. Notice there is much more metadata on chain or on the filesystem than on the image itself,

nft

Options[%]
Out[]={ColorSpace -> "RGB", Interleaving -> True}

I'm guessing from this output best practice is to ensure somewhere in transit extra metadata gets scrubbed one way or another. Just imagine how rich you will be when you can mint an NFT for every data point taken from your Lab!

Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract