What are the desired semantics of COLOR_256?

This is a follow-up to an earlier thread about the effects of
applying LUTs:

This is also essentially the same question I asked in this
older thread:

In my mind, this never really got resolved.

Applying LUTs sometimes produces unexpected and, at
times, apparently inconsistent behavior. Whether the behavior
of this or that version of ImageJ is correct or represents a
bug depends, of course, on what the correct behavior is
defined to be.

I would like to ask specifically about the meaning of the
COLOR_256 value of ImagePlus's type property. What
is COLOR_256 supposed to mean, and what is it supposed
to tell us about the behavior of such an image, and the
behavior of ImageJ when processing it?

(This is all in the context of 8-bit images whose type can
be eithe GRAY8 or COLOR_256.)

I ask because I can create (through legitimate, non-hackish
ImageJ manipulations) two otherwise identical images that
differ only in whether type is GRAY8 or COLOR_256.
Conceptually, how do two such images differ, and based on
this understanding, how should one expect further ImageJ
processing of such images to differ?

In short, what are the desired semantics of COLOR_256?

The following jython script illustrates this conundrum
and the seemingly vacuous distinction between GRAY8
and COLOR_256:

from ij import IJ

# show version
print 'ImageJ version:', IJ.getFullVersion()

# to keep script self-contained, create and save test images
imp = IJ.createImage ('ramp_gray', '8-bit ramp', 256, 256, 1)
IJ.saveAs (imp, 'PNG', 'ramp_gray.png')
imp.close()
imp = IJ.createImage ('ramp_color', '8-bit ramp', 256, 256, 1)
IJ.run (imp, 'Fire', '')
IJ.saveAs (imp, 'PNG', 'ramp_color.png')
imp.close()

# load gray image, change to color, and save
print 'open gray image ...'
imp = IJ.openImage ('ramp_gray.png')
imp.show()
print 'imp.getTitle() =', imp.getTitle()
print 'imp.getType =', imp.getType(), '(0 = GRAY8, 3 = COLOR_256)'
print 'imp.getFileInfo().fileType =', imp.getFileInfo().fileType, '(0 = GRAY8, 5 = COLOR8)'
print 'imp.getProcessor().isColorLut() =', imp.getProcessor().isColorLut()
print 'apply color LUT ...'
IJ.run (imp, 'Fire', '')
print 'imp.getTitle() =', imp.getTitle()
print 'imp.getType =', imp.getType(), '(0 = GRAY8, 3 = COLOR_256)'
print 'imp.getFileInfo().fileType =', imp.getFileInfo().fileType, '(0 = GRAY8, 5 = COLOR8)'
print 'imp.getProcessor().isColorLut() =', imp.getProcessor().isColorLut()
IJ.saveAs (imp, 'PNG', 'ramp_gray_mod.png')

# load color image, change to gray, and save
print 'open color image ...'
imp = IJ.openImage ('ramp_color.png')
imp.show()
print 'imp.getTitle() =', imp.getTitle()
print 'imp.getType =', imp.getType(), '(0 = GRAY8, 3 = COLOR_256)'
print 'imp.getFileInfo().fileType =', imp.getFileInfo().fileType, '(0 = GRAY8, 5 = COLOR8)'
print 'imp.getProcessor().isColorLut() =', imp.getProcessor().isColorLut()
print 'apply gray LUT ...'
IJ.run (imp, 'Grays', '')
print 'imp.getTitle() =', imp.getTitle()
print 'imp.getType =', imp.getType(), '(0 = GRAY8, 3 = COLOR_256)'
print 'imp.getFileInfo().fileType =', imp.getFileInfo().fileType, '(0 = GRAY8, 5 = COLOR8)'
print 'imp.getProcessor().isColorLut() =', imp.getProcessor().isColorLut()
IJ.saveAs (imp, 'PNG', 'ramp_color_mod.png')

Here is the output:

ImageJ version: 1.52r33
open gray image ...
imp.getTitle() = ramp_gray.png
imp.getType = 0 (0 = GRAY8, 3 = COLOR_256)
imp.getFileInfo().fileType = 0 (0 = GRAY8, 5 = COLOR8)
imp.getProcessor().isColorLut() = False
apply color LUT ...
imp.getTitle() = ramp_gray.png
imp.getType = 0 (0 = GRAY8, 3 = COLOR_256)
imp.getFileInfo().fileType = 5 (0 = GRAY8, 5 = COLOR8)
imp.getProcessor().isColorLut() = True
open color image ...
imp.getTitle() = ramp_color.png
imp.getType = 3 (0 = GRAY8, 3 = COLOR_256)
imp.getFileInfo().fileType = 5 (0 = GRAY8, 5 = COLOR8)
imp.getProcessor().isColorLut() = True
apply gray LUT ...
imp.getTitle() = ramp_color.png
imp.getType = 3 (0 = GRAY8, 3 = COLOR_256)
imp.getFileInfo().fileType = 5 (0 = GRAY8, 5 = COLOR8)
imp.getProcessor().isColorLut() = False

(I performed this test after updating ImageJ to the latest
daily build, ImageJ 1.52r33.)

Some comments:

Just to be clear, after modifying the images by applying the
LUTs the GRAY8 image (for which isColorLut() = True)
displays in color, and the COLOR_256 image (for which
isColorLut() = False) displays as a grayscale image.

To keep the script self-contained, I have it create its own
test images and save them to disk. But you could use
your own grayscale and color 8-bit images, or I could
have posted the test images to the forum.

Last, the grayscale COLOR_256 image, when saved to
disk (as “ramp_color_mod.png”), is identical to the
original grayscale GRAY8 image (“ramp_gray.png”), and
the color GRAY8 image is identical to the original
color COLOR_256 image. (When re-opening these images
from disk, these “unexpected” type values revert to
their expected values.)

So, again, what difference in meaning / behavior is
implied by COLOR_256, and if it is a meaningful /
important part of the image, why isn’t it preserved
when saving to disk?

Thanks, mm

1 Like

To test this, you should save as TIFF, as PNG will not retain all metadata of the image.

Hello Jan -

I redid my test changing everything to TIFF, and got a result that
leaves my original question unanswered, but doesn’t illustrate
the main point.

This is because (at least as far as my experiments* show)
opening any 8-bit TIFF image, color or grayscale, gives an
ImagePlus with a type of GRAY8. So, using TIFF format,
I’m not able to open a COLOR_256 image (even though it
displays in color). It opens as GRAY8 and when I convert it
to a grayscale image (by applying a grayscale LUT), it remains
GRAY8. So this is consistent with the issue I describe, but doesn’t
demonstrate all of it.

That is, because I can’t ever get a COLOR_256 TIFF image, I
can’t probe when or not the COLOR_256 / GRAY8 distinction
is preserved when saving to disk in TIFF format.

*) The clearest experiment is when I create an “RGB Color”
noise image (from scratch in ImageJ), and convert it to “8-bit
Color.” It has a type of COLOR_256. I save it as TIFF,
and reopen it, and now it shows a type of GRAY8.

(I don’t really know much about TIFF metadata, but poking
around, I don’t see anything that looks like it encodes GRAY8
vs. COLOR_256.)

Thanks, mm

1 Like

With the latest version of ImageJ (1.52r35), the only way to create a COLOR_256 image is by converting an RGB image into 8-bit color using the Image>Type>8-bit Color command. The ImageJ 1.52r34 daily build fixed a regression that caused COLOR_256 images saved as TIFF to reopen as GRAY8 and the ImageJ 1.52r35 daily build fixed a bug that caused 8-bit PNG images with LUTs to open as type COLOR_256 instead of GRAY8.

Hello Wayne -

I can confirm that the latest daily build (1.52r35) now includes
“8bitcolor=true” in the TIFF header / metadata when saving
COLOR_256 images as TIFF, and that both the daily build and
my stable version (1.52p) open such files as COLOR_256.

(This appears to be custom TIFF data specific to ImageJ. At
least I haven’t been able to find any 8-bit color TIFF images
in the wild that include this string or open as COLOR_256
with ImageJ.)

I can also confirm that 1.52r33 no longer opens color PNG
files as COLOR_256. (So, if I want to save a COLOR_256
image and reopen it as such, my understanding is that I can
only do so by saving it as a TIFF image.)

(But why?)

Thanks, mm