Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loading a 4D tif #149

Closed
RpfR2000 opened this issue Feb 12, 2024 · 6 comments
Closed

Loading a 4D tif #149

RpfR2000 opened this issue Feb 12, 2024 · 6 comments

Comments

@RpfR2000
Copy link

I am struggling to load a 4D grayscale tif (coordinates would be (y,x,z,t)). When I use the load function, the resulting array is three dimensional, with z and t combined in a single dimension. I can reshape but that requires knowledge of the number of t's or z's beforehand, which is generally impractical. Do I need to use a different library in this case? Thanks!

@tlnagy tlnagy added question Further information is requested waiting on author labels Feb 13, 2024
@tlnagy
Copy link
Owner

tlnagy commented Feb 13, 2024

Hi 👋, TIFFs don't have the ability to store 4 dimensions natively so usually TIFF writers will store that information in some non-standard way, e.g. ImageJ writes it into the ImageDescription tag. I purposefully avoided adding this to TiffImages.jl as it is meant to load the data into Julia and then the powerful Julia array manipulation tools can take over. Regardless, it should be easy to get the z and t information out of the TIFF and then just reshape as you were doing.

However, it's hard for us to help you without more information about the TIFF. What program was used to write the TIFF? Can you provide the output of

using TiffImages
img = TiffImages.load("your img.tif")
first(ifds(img)) # prints out the tags in the first image plane

@RpfR2000
Copy link
Author

Hi, thanks! I figured it was something like that. I generated the tiff using ImageJ, converting it from a .nd2 file (output from Nikon Elements software) -- unrelated, but if you know of a Julia package for reading in .nd2 files, I would love to know about it. I've considered writing one myself, but taking a look at similar Python libraries, it seems extremely painful. Regardless, I get the following output when I run the code you suggested:

first(ifds(timeseries)) = IFD, with tags:
Tag(SUBFILETYPE, 0)
Tag(IMAGEWIDTH, 642)
Tag(IMAGELENGTH, 528)
Tag(BITSPERSAMPLE, 16)
Tag(COMPRESSION, COMPRESSION_NONE)
Tag(PHOTOMETRIC, 1)
Tag(IMAGEDESCRIPTION, "ImageJ=1.53t
images=...")
Tag(STRIPOFFSETS, 1489112)
Tag(SAMPLESPERPIXEL, 1)
Tag(STRIPBYTECOUNTS, 677952)
Tag(XRESOLUTION, 0x000f4240//0x00eac027)
Tag(YRESOLUTION, 0x000f4240//0x00eac027)
Tag(RESOLUTIONUNIT, 1)
Tag(COLORMAP, UInt16[0, 0, 256, 512, 768, ...])
Tag(SAMPLEFORMAT, 1)
Tag(IMAGEJ_METADATA_BYTECOUNTS, UInt32[20, 882300, 110, 110, 110, ...])
Tag(IMAGEJ_METADATA, UInt8[73, 74, 73, 74, 105, ...])

@tlnagy
Copy link
Owner

tlnagy commented Feb 14, 2024

Ah, ImageJ should write that info into the IMAGEDESCRIPTION tag, what's the output of

println(first(ifds(timeseries))[TiffImages.IMAGEDESCRIPTION])

unrelated, but if you know of a Julia package for reading in .nd2 files, I would love to know about it. I've considered writing one myself, but taking a look at similar Python libraries, it seems extremely painful.

I do not, sorry. I would imagine it would need to look like the wonderful NRRD package by Tim Holy https://github.com/JuliaIO/NRRD.jl

@RpfR2000
Copy link
Author

It's very nondescript: just Tag(IMAGEDESCRIPTION, "ImageJ=1.53t
images=...")

Presumably I need to expand the output somehow?

@tlnagy
Copy link
Owner

tlnagy commented Feb 14, 2024

Yes, sorry. It should be

println(first(ifds(timeseries))[TiffImages.IMAGEDESCRIPTION].data)

@RpfR2000
Copy link
Author

Thanks, yes I was able to get this to work with the following:

    height, width, zt = size(timeseries)
    ImageJ_metadata = first(ifds(timeseries))[TiffImages.IMAGEDESCRIPTION].data
    slice_loc = findfirst("slices=", ImageJ_metadata)
    frames_loc = findfirst("frames=", ImageJ_metadata)
    hyperstack_loc = findfirst("hyperstack=", ImageJ_metadata)
    slices = tryparse(Int, ImageJ_metadata[(slice_loc[7]+1):(frames_loc[1]-1)])
    frames = tryparse(Int, ImageJ_metadata[(frames_loc[7]+1):(hyperstack_loc[1]-1)])
    if slices == nothing
        error("Could not parse the number of slices from the metadata")
    end
    if frames == nothing
        error("Could not parse the number of frames from the metadata")
    end
    timeseries = reshape(timeseries, (height, width, slices, frames))
    @show size(timeseries)

@tlnagy tlnagy removed question Further information is requested waiting on author labels Feb 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants