Plotting Color Histograms of an Image in OpenCV with Python

πŸ’‘ Problem Formulation: When working with images in computer vision tasks using Python, one often needs to understand the color distribution of the images. Specifically, this article tackles how to create histograms for the different color channels (red, green, and blue) of an image using OpenCV, a popular computer vision library. The input is a colored image in a standard format (e.g., JPG, PNG), and the desired output is a set of histograms representing the frequency distribution of pixel intensity for each color channel.

Method 1: Plotting Histograms Using cv2.calcHist

This method leverages the function cv2.calcHist to calculate the histogram of image channels. OpenCV’s calcHist allows for flexible histogram computation by specifying the image, channels, mask, histo size, and ranges. This is ideal for single-channel histograms and can be extended to multi-channel histograms by repeating the process for each channel and using matplotlib to plot them.

Here’s an example:

import cv2
from matplotlib import pyplot as plt

# Load the image
image = cv2.imread('example.jpg')

# Convert to RGB
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

# Calculate the histograms for each channel
color = ('r', 'g', 'b')
for i, col in enumerate(color):
    histr = cv2.calcHist([image], [i], None, [256], [0, 256])
    plt.plot(histr, color=col)
    plt.xlim([0, 256])

plt.show()

In this code, we read an image, convert it from BGR to RGB color space, and calculate histograms for each color channel. The results are plotted using matplotlib, showing each channel’s histogram in its respective color.

Method 2: Using cv2.split and numpy

By splitting the image into its respective channels with cv2.split and using the numpy library for histogram computation, this method provides an alternative way to access pixel data and visualize color distributions. It is straightforward and leverages familiar numpy operations, which may be comfortable for users accustomed to numpy’s API.

Here’s an example:

import cv2
import numpy as np
from matplotlib import pyplot as plt

# Load the image
image = cv2.imread('example.jpg')

# Split into channels
channels = cv2.split(image)

colors = ('b','g','r')
for (channel, col) in zip(channels, colors):
    hist = np.histogram(channel, bins=256, range=[0,256])[0]
    plt.plot(hist, color=col) 

plt.xlim([0, 256])
plt.show()

The code splits the image into its BGR components, calculates the histogram for each using numpy’s histogram function, and then plots them with matplotlib. This approach provides a clear mapping between the code structure and the resulting histograms.

Method 3: Utilizing matplotlib’s in-built Histogram Function

This method simplifies the process by using matplotlib’s in-built hist function. By flattening each color channel, we can quickly generate histograms without the need for additional OpenCV histogram calculation functions. This is a more compact and pythonic way of generating histograms for those familiar with matplotlib.

Here’s an example:

import cv2
from matplotlib import pyplot as plt

# Load the image in grayscale
image = cv2.imread('example.jpg', 0)

colors = ('b','g','r')
for i, col in enumerate(colors):
    plt.hist(image[:,:,i].ravel(), 256, [0,256], color=col)

plt.show()

By reading the image and utilizing matplotlib’s hist function, we directly plot the histograms of each channel. The image array is sliced to access each channel, which is then flattened and passed to hist.

Method 4: Advanced Multi-Channel Histogram with cv2.calcHist

For more control over histogram plotting, especially when dealing with multiple image channels, cv2.calcHist can again be utilized. Here we will demonstrate layering histograms for a sleeker visualization, using transparency to simultaneously depict multiple color distributions.

Here’s an example:

import cv2
from matplotlib import pyplot as plt

# Read the image
image = cv2.imread('example.jpg')

# Calculating histograms for all channels
for i, col in enumerate(['b', 'g', 'r']):
    histogram = cv2.calcHist([image], [i], None, [256], [0,256])
    plt.plot(histogram, color=col, alpha=0.5)

plt.xlim([0, 256])
plt.show()

This snippet demonstrates computing histograms for each color channel using cv2.calcHist. By adjusting the alpha value in the plot function, we allow the histograms to overlap with semi-transparency, making it easy to compare color channels.

Bonus One-Liner Method 5: Quick Histograms with cv2 and matplotlib Inline

For a swift and minimalistic one-liner approach, the combination of cv2 to read image channels and matplotlib to directly plot histograms is unbeatable. Perfect for quick analysis without fussing over detailed configurations.

Here’s an example:

[plt.hist(cv2.imread('example.jpg')[:,:,i].ravel(), 256, [0,256], color=col) for i, col in enumerate(['b', 'g', 'r'])]
plt.xlim([0, 256])
plt.show()

This compressed code is a list comprehension that simultaneously reads each image channel and plots its histogram. It’s a quick way to visualize all channel distributions in only two lines.

Summary/Discussion

  • Method 1: cv2.calcHist: Versatile and precise. Ideal for custom histogram computation but requires several steps for multi-channel images.
  • Method 2: Using cv2.split and numpy: Simple, if handling channels separately, using numpy’s intuitive API. However, not as direct as using matplotlib’s hist function alone.
  • Method 3: matplotlib’s in-built Histogram Function: Direct and convenient for those comfortable with matplotlib, but less customizable compared to cv2.calcHist.
  • Method 4: Advanced Multi-Channel Histogram: Offers granularity and better visualization control, especially with transparency. However, it can become complex with large-scale image sets.
  • Bonus Method 5: One-Liner: Extremely concise, suitable for quick looks and small-scale analysis. Lacks detailed customization and may not be ideal for all situations.