Beyond the Basics: Creating Custom Colormaps in OpenCV

Posted on Apr 11, 2022

Beyond the Basics: Creating Custom Colormaps in OpenCV

Have you ever found yourself staring at OpenCV’s standard colormaps thinking, “These just don’t quite capture what I need”? You’re not alone! While OpenCV provides several built-in colormaps that work well for many applications, there are times when you need something more personalized.

In this guide, I’ll walk you through creating your own custom colormaps using OpenCV’s Lookup Table (LUT) functionality. Whether you’re working on scientific visualization, remote sensing data, or just want your images to pop with your brand colors, this technique will give you the flexibility you need.

Understanding Lookup Tables in OpenCV

Think of a lookup table as a cheat sheet for pixel transformations. For every possible input value (0-255 for an 8-bit grayscale image), the LUT specifies exactly what the output should be. For colormaps, we’re essentially saying: “When you see pixel value 128, transform it to this specific RGB color.”

Creating Our Custom Colormap Function

Let’s build a function that will create a lookup table based on a dictionary of color mappings:

import cv2
import numpy as np
import collections

def cvlut(colordict):
    cmap = collections.OrderedDict()
    cmap = colordict
    crange = 0
    clist = list(cmap.items())
    r = []
    g = []
    b = []
    
    while(crange < 256):
        for i in range(len(clist)):
            if i != (len(clist) - 1):
                # Fill in the range between current color point and next color point
                for n in range(clist[i][0], clist[i + 1][0]):
                    r.append(clist[i][1][0])
                    g.append(clist[i][1][1])
                    b.append(clist[i][1][2])
                    crange += 1
            else:
                # Handle the final range (to 255)
                for n in range(clist[i][0], 256):
                    r.append(clist[i][1][0])
                    g.append(clist[i][1][1])
                    b.append(clist[i][1][2])
                    crange += 1

    # Create the actual lookup table
    lut = np.zeros((256, 1, 3), dtype=np.uint8)
    lut[:, 0, 0] = r  # Red channel
    lut[:, 0, 1] = g  # Green channel
    lut[:, 0, 2] = b  # Blue channel

    return lut

What’s happening here? Our function takes a dictionary that maps grayscale values to RGB colors. For each range in the grayscale spectrum, we assign specific RGB values. The function builds three lists (one for each color channel) and then combines them into a properly formatted lookup table that OpenCV can use.

Putting Our Custom Colormap to Work

Now let’s see how we can apply our newly created function:

# Define color transitions at specific grayscale values
colormap_dict = {
    0: [0, 0, 0],       # Black at grayscale 0
    111: [220, 8, 8],   # Red at grayscale 111
    128: [237, 252, 2], # Yellow at grayscale 128
    171: [8, 220, 85],  # Green at grayscale 171
    213: [0, 163, 32]   # Darker green at grayscale 213
}

# Create our custom LUT
custom_lut = cvlut(colormap_dict)

# Apply it to our grayscale image
colormap_img = cv2.LUT(gray2bgr_img, custom_lut)

The magic here is that we’re creating what’s called a “pseudocolor” or “false color” representation. We’re not changing any actual data in the image—just how it’s visualized. This technique is especially useful for highlighting features in scientific or medical imaging, satellite imagery, thermal scans, and more.

Pro Tip: Using External Colormap Files

While defining colors in your code works fine for simple cases, for more complex colormaps, I recommend creating a separate colormap file. Here’s what such a file might look like:

# custom_colormap.txt format: grayscale_value R G B
0   255 255 255
1   250 250 250
2   246 246 246
...
120 136 136 136
...
240 255 0   0
241 255 0   15
...
255 255 0   239

This approach makes it much easier to design detailed gradients or to reuse colormaps across different projects.

Complete Working Example

Here’s a full example you can try yourself:

import cv2
import numpy as np
import collections

def cvlut(colordict):
    cmap = collections.OrderedDict()
    cmap = colordict
    crange = 0
    clist = list(cmap.items())
    r = []
    g = []
    b = []
    
    while(crange < 256):
        for i in range(len(clist)):
            if i != (len(clist) - 1):
                for n in range(clist[i][0], clist[i + 1][0]):
                    r.append(clist[i][1][0])
                    g.append(clist[i][1][1])
                    b.append(clist[i][1][2])
                    crange += 1
            else:
                for n in range(clist[i][0], 256):
                    r.append(clist[i][1][0])
                    g.append(clist[i][1][1])
                    b.append(clist[i][1][2])
                    crange += 1

    lut = np.zeros((256, 1, 3), dtype=np.uint8)
    lut[:, 0, 0] = r
    lut[:, 0, 1] = g
    lut[:, 0, 2] = b

    return lut

if __name__=="__main__":
    # Load a grayscale image
    image = cv2.imread("path_to_your_image", cv2.IMREAD_GRAYSCALE)
    
    # Convert grayscale to BGR to ensure proper dimensions for color mapping
    gray2bgr_img = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)

    # Define our colormap with key grayscale points
    colormap_dict = {
        0: [0, 0, 0],       # Black
        111: [220, 8, 8],   # Red
        128: [237, 252, 2], # Yellow 
        171: [8, 220, 85],  # Green
        213: [0, 163, 32]   # Dark green
    }

    # Generate and apply our custom colormap
    custom_lut = cvlut(colormap_dict)
    colormap_img = cv2.LUT(gray2bgr_img, custom_lut)

    # Save the result
    cv2.imwrite('custom-colormap-result.jpg', colormap_img)
    
    # Display the result (optional)
    cv2.imshow("Original", image)
    cv2.imshow("Custom Colormap", colormap_img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

Practical Applications

This technique is incredibly useful for:

  • Remote sensing: Highlight vegetation, water, or urban areas in satellite imagery
  • Medical imaging: Emphasize specific structures in MRI or CT scans
  • Scientific visualization: Make patterns in your data more visible
  • Thermal imaging: Create intuitive hot-to-cold gradients
  • Brand consistency: Apply your organization’s color scheme to data visualizations

Next Steps to Explore

Once you’ve mastered the basics of custom colormaps, consider these advanced techniques:

  • Creating smooth transitions between color points using interpolation
  • Building interactive tools to adjust colormap parameters in real-time
  • Combining multiple colormaps for multi-channel data

Custom colormaps may seem like a small detail, but they can dramatically improve how effectively your visualizations communicate information. Give it a try on your next project!