9
$\begingroup$

I noticed that the following line,

Image[Table[x, {y, 1, 250}, {x, 30/256, 40/256, 0.02/256}], 
 Magnification -> 1]

results in the following image:

enter image description here

In the preceding image, there are 10 vertical bars, each a different shade of grey; based on the range I used in Table, this means that there are 256 shades of grey when going from black to white (ie, 8-bit depth per channel).

Similarly, this effect also shows up in full-color images.

Is there a way to make the colors produced by Image have less of this "staircase effect"? This related question asks about boosting the channel depth beyond 8-bits per RGB channel, but the highest-voted answer does not appear to computationally scale well when applied to image sizes of $3000\times3000$ or larger.

$\endgroup$
9
  • $\begingroup$ Ten grays taken from the range 30/256 to 40/256 are not distinguishable to most human eyes. What do you really want? $\endgroup$
    – m_goldberg
    Jul 5, 2014 at 1:57
  • $\begingroup$ @m_goldberg: Apologies, I guess I wasn't being clear. Basically what I would like would be a way to have Image display render an array of numbers with more than 256 shades per color channel of color resolution. I'm not sure if this is actually possible (I don't know much about graphics hardware and what its limitations are). $\endgroup$ Jul 5, 2014 at 2:05
  • 2
    $\begingroup$ @DumpsterDoofus You can represent more than 256 shades of grey. In fact by default Image uses floating point values for pixels which can represent a very large number of shades (see ImageType). However, Mathematica cannot display more than 256 shades of grey. (Certain programs on certain operating system can display 1024=2^10 shades if the hardware supports it---that means video card and screen, I think.) So the question: is your aim to represent more than 256 shades, or to display them? The first is easy, the second can be approximated by dithering. $\endgroup$
    – Szabolcs
    Jul 5, 2014 at 3:26
  • 1
    $\begingroup$ As @m_goldberg says, usually 256 shades are enough, as the screen (!) and eye can't distinguish more. But it can indeed happen on some screens that it's possible to see the posterization effect with only 256 shades and no dithering. I can sometimes see this on my screen, and if I look very very carefully at your image and keep moving the screen (or my head) left and right, then I can (barely) see posterization in your image too. But just barely. There must be some processing in the human eye that accentuates the difference when I move the screen, but not otherwise. $\endgroup$
    – Szabolcs
    Jul 5, 2014 at 3:30
  • 1
    $\begingroup$ @Szabolcs: My aim was to display them, in which case the dithering suggestion works great. Thanks! $\endgroup$ Jul 5, 2014 at 16:28

3 Answers 3

9
$\begingroup$

Its not true that a human can not see banding in 256 colors. Whether or not you do depends quite much on what the transfer curve of the monitor is and if its a low quality LCD with diminished color spectrum, like in many phones. Also human eyes are really well adapted to sensing just this kind of thing so while 256 colors in general is fine its not so good when you have straight fronts, Mach bands and all that.

You can use a trick commonly used in 3d rendering, make the color slightly inpure. What happens is the linear interpolation between the edges now cross boundaries at different points for different channels leaving you with more colors to discrete color values travel trough.

Another option is to jitter your sampling pattern a bit so that not all pixels reach the same value at once. This dithers the color causing a more natural spread since human eyes dont pay attention to individual pixels.

Listing 1: Noise pattern jittered per channel you could also jitter only gray

rGray[x_] := IntegerPart[256*(x + RandomReal[{-3.0/256, 3.0/256}])]
dColor[x_] := {rGray[x], rGray[x], rGray[x]}

Image[{
  Map[dColor, Range[0, 1, 0.02]],
  Map[dColor, Range[0, 1, 0.02]],
  Map[dColor, Range[0, 1, 0.02]]
  }, 
"Byte"]

Listing 1 is on purpose a bit exaggerated so that you can more easily see the effect.

result enlarged

Image 1: Result of the code the number of pixels is small and the effect exaggerated zoomed so its easier to spot every pixel and see the effect.

You could also use noise only on one of the color channels or just on the gray to alter the effect to more subtle and not so color noisy. Here's a more subtle real size example

gradient

Image 2: a wider gradient noise toned down and in right scale. Open the image to a separate tab so you can see it unscaled

Yo might do better with a pseudo stochastic pattern. Other things to do is do the computation gamma corrected etc etc.

$\endgroup$
3
  • $\begingroup$ Haha, in retrospect the use of random noise dithering should have been obvious, thanks! $\endgroup$ Jul 5, 2014 at 16:31
  • $\begingroup$ For example, using Image[Table[ x + RandomReal[{-1/256, 1/256} 0.2], {y, 1, 250}, {x, 30/256, 40/256, 0.02/256}], Magnification -> 1] just barely smooths away the bars. $\endgroup$ Jul 5, 2014 at 16:35
  • $\begingroup$ @DumpsterDoofus the dither isnt entirely centered you should probably use Image[Table[ x + RandomReal[{-1/256, 2/256} ], {y, 1, 250}, {x, 30/256, 40/256, 0.02/256}]] $\endgroup$
    – joojaa
    Jul 5, 2014 at 16:57
8
$\begingroup$

To get an easily distinguishable scale of grays, you could do

ArrayPlot[{Table[x, {x, 0, .9, .1}]}, AspectRatio -> .3]

scale-10

To get 256 shades of gray

ArrayPlot[{Table[x, {x, 1/256, 1, 1/256}]}, AspectRatio -> .3]

scale-256

To get 1024 shades of gray

ArrayPlot[{Table[x, {x, 1/1024, 1, 1/1024}]}, AspectRatio -> .3]

I exported this as a tiff (usual formats png and jpeg are 8-bit) and got

scale-1024

Can you see any difference between the 256-shade and the 1024-shade images? As reproduced here I don't see much if any difference. On my computer screen the 1024-shade image looks a little smoother.

I don't think web images can be more than 8-bits per channel, but I could be wrong about that. If I'm right, then the two gray gradients will display the same here no matter what I format I upload in.

$\endgroup$
6
  • $\begingroup$ Is ArrayPlot smoother than Image because the former is not rasterized? I tried ArrayPlot[{Table[x, {x, 30/256, 40/256, 0.02/256}]}, AspectRatio -> 0.3], and the banding is much less significant, even though there still is a certain amount of banding. $\endgroup$
    – seismatica
    Jul 5, 2014 at 2:59
  • $\begingroup$ @seismatica. Maybe, but I really don't know. $\endgroup$
    – m_goldberg
    Jul 5, 2014 at 3:40
  • 3
    $\begingroup$ add a bit hue to your black so its say slightly blue (Cool) or yellow (Warm) then inyerpolate that to white and you sudddenly have far more colors to play with. Pretty standard way to handle banding. or add a bit of noise. $\endgroup$
    – joojaa
    Jul 5, 2014 at 3:49
  • $\begingroup$ @joojaa that seems worty of working up as an answer. $\endgroup$
    – george2079
    Jul 5, 2014 at 12:46
  • $\begingroup$ @george2079 Done $\endgroup$
    – joojaa
    Jul 5, 2014 at 16:22
2
$\begingroup$
Column[Framed@Graphics[Raster[{Range@#/#},
      ColorFunction -> (Blend[{{0, White}, {1, Black}}, #] &)],
     AspectRatio -> 0.2,
     ImageSize -> 400] & /@
  {3^2, 3^3, 3^4, 3^5}]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.