JuliaImages / Images.jl

An image library for Julia
http://juliaimages.org/
Other
534 stars 143 forks source link

Interpreting floating point images #911

Closed NicholasWMRitchie closed 4 years ago

NicholasWMRitchie commented 4 years ago

I'm trying to a process a set of 32-bit float TIFF images that were created on a scale which nominally goes from 0.0 to 100.0 through because it is measurement data, the values actually go (slightly) below 0.0 and (slightly) above 100.0. (Essentially the data is written as a percentage with measurement variations.) As best I can tell, when the images are loaded by Images/FileIO, they are transformed to N0f32 which is a scaled UInt32. Values between 0.0 and 1.0 in the TIFF are maintained correctly however anything above 1.0 is truncated to 1.0 and below zero to 0.0.

Is there a way to perform a transform on the image data as it is being read in? For me, values below zero can be set to zero but I'd like to be able to divide input values by 100.0 or 1000.0 to maintain. Would this require a change to ImageMagick.jl since this seems to be where the read code is actually located?

timholy commented 4 years ago

It could either require a change to the Julia code in ImageMagick.jl or, since it's mostly a wrapper of the C library, it could be an error in libmagick itself. Key logic is in https://github.com/JuliaIO/ImageMagick.jl/blob/475bdf01f76942e7bdc7afc15a8733d0038c384c/src/ImageMagick.jl#L65-L123

Looks like we don't even check whether it could be floating-point, perhaps you can go visit https://www.imagemagick.org/api/magick-image.php and see if we can detect it properly?

NicholasWMRitchie commented 4 years ago

I'm looking through the MagickWand C API documentation for a method to determine how the data is stored (float vs int) but I'm not finding it. I think this may be due to the abstraction layer in ImageMagick. Internal storage format is a question you are not allowed to ask.

However, when you go to export the image data from ImageMagick to your data structure, using MagickExportImagePixels(...) you get to choose the format. At which point, the floating point values are reinterpreted on the [0,1] scale as a UInt8, UInt16 or UInt32 because that is what the ImageMagic.jl asks for.

All is not lost. MagickExportImagePixels(...) is capable of exporting to Float32 or Float64 but ImageMagic.load_( ) through the services of ImageMagick.exportimagepixels!(...) never asks. Nor can I find a method that would tell me that an image is natively in float format. The closest might be MagickGetImageRange which seems to provide extrema.

Something like MagickExportImagePixels(wand, 0, 0,cols, rows, "I", FloatPixel, pixels) might work. However, it isn't clear how ImageMagick will handle float values outside [0,1]. It says "Float and double types are expected to be normalized [0..1]" but this doesn't say whether this is enforced. (Float values do seem to be truncated when the data is transformed to integer return values.)

I'm thinking about cobbling together a crude, custom method using ImageMagick.jl to load the float images as a proof of principle.

NicholasWMRitchie commented 4 years ago

This minimal function loads the image as an Array{Float32}

function loadfloatimage(file, sz)
    p=Array{Float32}(undef, sz)
    wand = MagickWand()
    readimage(wand, file)
    resetiterator(wand)
    ImageMagick.nextimage(wand)
    ccall((:MagickExportImagePixels, libwand), Cint, (Ptr{Cvoid}, Cssize_t, Cssize_t, Csize_t, Csize_t, Ptr{UInt8}, Cint, Ptr{Cvoid}), wand, 0, 0, sz[1], sz[2], "I", ImageMagick.storagetype(Float32), p)
    return p
end

It has already been truncated to [0,1]. ☹️

timholy commented 4 years ago

If you happen to know the format then it should be pretty trivial (you can always reinterpret the returned image if you have to). But the whole point of a file format is to self-document how the bits in the file should be interpreted, so it's crazy to imagine this might not be available. Does identify -verbose <filename> give any hint that IM knows its floating-point?

timholy commented 4 years ago

Oh, nice work, but sad that ImageMagick gets in your way.

Perhaps you could try https://github.com/tlnagy/OMETIFF.jl or maybe https://github.com/vidriotech/ScanImageTiffReader.jl?

NicholasWMRitchie commented 4 years ago

@timholy Thanks for the suggestions. https://github.com/vidriotech/ScanImageTiffReader.jl is just the ticket. 😃