Menu

#36 floating point TIFF read incorrectly

open
None
5
2021-08-04
2013-08-08
No

The attached image is displayed incorrectly by GraphicsMagick. The image is a floating point precision TIFF. Some of the image values are negative while the positive values go beyond 77. Using the Magick++ I get the same (incorrect) values that GM displays.

I will attach on a separate comment the display.

1 Attachments

Discussion

  • Carnë Draug

    Carnë Draug - 2013-08-08

    I was unable to attach more than one file to the bug report so here's the rest.

    This screenshoot shows the incorrect GM display on the left, next to the correct display of FIJI (using the LOCI bio-formats importer). It has been reported that Matlab also displays the image correctly.

    The terminal on the background shows the build options of GraphicsMagick being used to display. It was built with quantum depth 32.

     
  • Bob Friesenhahn

    Bob Friesenhahn - 2013-08-08

    The TIFF file incorrectly includes tags which specify that the minimum and maximum sample value are both zero. GM uses a rather simplistic reading approach. If the tags are available, it will use them for offset and scaling. If they are missing or are zero, then it is using a data range of 0.0-1.0 (which it is using for this image).

    Some other integer-based software reads the image once to determine the actual numeric ranges, and then reads it again to acquire the actual image. Or the software is inherently floating point and can read the image directly into floating point, evaluate it, and then display it nicely.

    GM offers a number of 'defines' which can be used to adjust how float TIFF is read:

    -define tiff:max-sample-value=<value></value>

    -define tiff:min-sample-value=<value></value>

    It is true that this is not fully user-friendly but it does offer the user some control over how the image is presented. Images which use extreme dynamic range are often best used over a small part of that range since otherwise the image appears completely black or white.

    With a Q32 build, and with reasonable knowledge of the images, conservative defaults can be used for all the images which assures that input data is not lost although the values read do not span the full integer range of what the Q32 build can support.

    A utility such as libtiff's 'tiffset' could be used to set the min and max sample values in the files so that they are read "correctly" by integer software like GraphicsMagick.

     
    • Nick J.

      Nick J. - 2021-08-04

      looking through the old GNU Octave bug that kicked off this GM bug report. there was a later comment made that i thought would be worth including in the record over here:

      I don't think GM's behavior of scaling the image is correct. The min/max sample value are not required tags, and if they are set, they do not mean the image cannot have pixel values outside the corrsponding range.
      From the TIFF specification about MaxSampleValue:
      "This field is not to be used to affect the visual appearance of an image when it is
      displayed or printed. Nor should this field affect the interpretation of any other
      field; it is used only for statistical purposes.
      Default is 2**(BitsPerSample) - 1."
      If an image is floating point, Octave should return an array of the single-precision floating point values unmodified. This is how Matlab behaves.
      I'm not sure if GM can be modified to work this way, or if we need to handle loading floating-point TIFFs specially (i.e. use libtiff directly).

       
      • Bob Friesenhahn

        Bob Friesenhahn - 2021-08-04

        On Wed, 4 Aug 2021, Nick J. wrote:

        I don't think GM's behavior of scaling the image is correct. The min/max sample value are not required tags, and if they are set, they do not mean the image cannot have pixel values outside the corrsponding range.
        From the TIFF specification about MaxSampleValue:
        "This field is not to be used to affect the visual appearance of an image when it is
        displayed or printed. Nor should this field affect the interpretation of any other
        field; it is used only for statistical purposes.
        Default is 2**(BitsPerSample) - 1."
        If an image is floating point, Octave should return an array of the single-precision floating point values unmodified. This is how Matlab behaves.
        I'm not sure if GM can be modified to work this way, or if we need to handle loading floating-point TIFFs specially (i.e. use libtiff directly).

        The problem is that GraphicsMagick uses only integer values
        internally. So the float needs to be scaled to an integer range and
        so min/max are needed. The TIFF specification suggestion to use a
        value based on BitsPerSample does not seem terribly helpful for float
        values.

        If Octave can do better internally, then using libtiff directly for
        floating-point TIFFs is reasonable.

        Bob

        Bob Friesenhahn
        bfriesen@simple.dallas.tx.us, http://www.simplesystems.org/users/bfriesen/
        GraphicsMagick Maintainer, http://www.GraphicsMagick.org/
        Public Key, http://www.simplesystems.org/users/bfriesen/public-key.txt

         
  • Bob Friesenhahn

    Bob Friesenhahn - 2013-08-08

    As a basis for testing (floating range -100 to 100), try this:

    gm convert -define tiff:min-sample-value='-100' -define tiff:max-sample-value='100' LiveXYZ-279-4-X0Y0.tif -verbose info:-

    Bob

     
  • Carnë Draug

    Carnë Draug - 2013-08-08

    But I am trying to use Magick++ to read the image into an octave value. It will then be returned to the users as a multi-dimensional matrix for further processing. Any image may come through, I have no knowledge of them.

    Is there anyway to get floating point precision values from GM? Or even if not, is there any way to get the maximum and minimum values and then request the whole range in the depth that GM was built with?

     
  • Bob Friesenhahn

    Bob Friesenhahn - 2013-08-09

    At the moment, only the trial and error method is available. If you were to know in advance that it was a float TIFF, then you could try very wide scaling first, obtain the high/low integer limits, and then scale appropriately to get the widest use of range using the equivalent floating limits.

    If the TIFF was properly tagged, then GraphicsMagick should do a reasonable read in the first place. Note that "properly tagged" is a matter of some debate.

    With relatively minor modification, GraphicsMagick would be able to obtain the min/max floating values when the image was read, even if the image it returns is not ideal. Then the min/max floating values could be used to re-read the image again to maximize the range and eliminate any truncation.

     
  • Carnë Draug

    Carnë Draug - 2013-08-09

    Could you give me some pointers to where I should look to implement this?

     
  • Bob Friesenhahn

    Bob Friesenhahn - 2013-08-09

    TIFF uses the import routines in magick/import.c. In particular, all imported float data goes through the ImportFloat[*]Quantum macros. The ImportPixelAreaInfo structure is optionally passed into the various Import[*]QuantumType routines. Currently the only data that this collects is the number of bytes which were imported. The structure could be extended to also include min/max float values. Unfortunately, extending this structure breaks the ABI and the structure is normally allocated on the stack. I did not think in advance to allocate spare space in the structure for future use.

    Taking ImportRGBQuantumType() as an example, each case handling FloatQuantumSampleType would need code added to optionally tally the min/max value. The key challenge is where to store this data. Breaking the ABI is bad even if this structure is rarely used outside of GraphicsMagick. If the data can be stored as image attributes then the ABI is not broken but doing so is messy because currently these functions are low-level and don't pass the Image pointer.

    The procedure would require reading the whole image twice for float images. This could be done within the TIFF coder itself by adding an optional pre-reading loop which reads/parses all the scanlines/tiles and then reads the final values into the Image. Please note that there are formats other than TIFF which store floating point values (e.g. FITS) and might benefit from special treatment. The MAT coder already does pre-reading of the float values in order to know the range, but does this in a MAT-specific way.

     
  • Bob Friesenhahn

    Bob Friesenhahn - 2013-08-09

    Please note that it may be beneficial to maintain per-channel scaling values. The current TIFF defines don't provide for that. Floating formats are not necessarily intended for humans to view since they may be raw sensor data. Perfectly fitting/scaling each channel may be beneficial in some cases.

     
  • Bob Friesenhahn

    Bob Friesenhahn - 2013-10-19
    • assigned_to: Bob Friesenhahn
     
  • Bob Friesenhahn

    Bob Friesenhahn - 2014-01-05

    Ticket moved from /p/graphicsmagick/bugs/241/

    Can't be converted:

    • _milestone: v1.0_(example)
     
  • Bob Friesenhahn

    Bob Friesenhahn - 2014-01-05

    GraphicsMagick does not currently do auto-scaling of floating point values for TIFF so this is moved to the feature request bucket.

     

Log in to post a comment.

MongoDB Logo MongoDB