imageimage-processinggimppython-fubump-mapping

How to prevent Color Banding with GIMP?


Just doing a simple bump_map operation in python GIMP. But the result has color banding!

import os, glob, sys, time
from gimpfu import *

image = pdb.gimp_file_load(img_path, img_path, run_mode=RUN_NONINTERACTIVE)
gray = pdb.gimp_file_load(gray_path, gray_path, run_mode=RUN_NONINTERACTIVE)

pdb.plug_in_bump_map(image, image.active_layer, gray.active_layer, 
    135.0, 20.00, 30, 0, 0, 0.0, 0.0, 1, 0, 0)
pdb.file_png_save_defaults(image, image.active_layer, out_path, out_path)

If I remove the "plug_in_bump_map" operation, there is no color banding in my final result saved. If I apply a gaussian blur to the grayscale image, the color banding disappears in the final result, but leaves an undesirable blurriness, what should I do? All images are PNG.

example of banding example two


Solution

  • OK, so it's banding :)

    But if you look closely, the banding is already in your bump map, and is sort of unavoidable since you only have 256 levels in your PNG.

    Banding occurs when there is a significant change in value between two uniform areas with a somewhat linear border between them. So the two mitigations are

    The best way to fix the problem is at the source, so if openCV can compute on more that 256 levels, have it do so and export the bump map in some high-bit depth format (16-bit/channel PNG could be enough, otherwise TIFF).

    Otherwise if you have to start with an 8 bit bump map:

    1. Load in Gimp
    2. Convert to high-precision (32bit FP linear)
    3. If you look at the histogram at that point you still have only 256 values:

    Histogram Before

    1. You then add "dithering" with the RGB noise filter to spread the values to fill the gaps. This is best done with the Histogram dialog up, and cranking up the values until the "hair comb" structure nearly disappears:

    RGB noise settings Histogram Noise

    1. You can also use Spread noise to "shake the pixels" a bit (2-3px), so that transitions are less linear and so less visible:

    Spread noise

    1. You can then apply the bump mapping. You trade banding for a bit of graininess:

    Bump mapped

    1. You can reduce the graininess using Median blur without having to use values that make your image lose too much sharpness.

    Median blur

    It is also possible to replace steps 4 & 5 by a selective Gaussian blur.

    Edit: tried your 16bpc:

    1. Promote to 32bit FP linear
    2. Apply bump-map without pre-processing

    "native" result is already much better:

    Direct 16bpc bump-mapping

    It can be improved with:

    1. color selection of the "flats" color with a threshold of 0
    2. Selective Gaussian blur

    16Bps bump map+Selective Gaussian