Image histograms are graphical representations of the pixel intensity distribution in an image. They are essential tools in image processing for understanding and manipulating image characteristics.
A histogram is a graph showing the number of pixels in an image at each different intensity value. For an 8-bit grayscale image, there are 256 different possible intensities, and so the histogram will graphically display 256 numbers showing the distribution of pixels amongst those grayscale values.
OpenCV provides several methods to calculate histograms:
import cv2
import numpy as np
# Read image
img = cv2.imread('image.jpg', 0) # Read as grayscale
# Calculate histogram
hist = cv2.calcHist([img], [0], None, [256], [0, 256])Parameters of calcHist():
images: Source image(s) in square bracketschannels: Index of channel (grayscale: [0], color: [0], [1], or [2])mask: Mask image for calculating histogram of specific regionshistSize: Number of bins (usually [256])ranges: Range of pixel values [0, 256]
hist, bins = np.histogram(img.ravel(), 256, [0, 256])For color images, we can calculate histograms for each color channel:
# Read color image
img = cv2.imread('image.jpg')
# Calculate histograms for each channel
color = ('b', 'g', 'r')
for i, col in enumerate(color):
hist = cv2.calcHist([img], [i], None, [256], [0, 256])We can visualize histograms using Matplotlib:
import matplotlib.pyplot as plt
plt.hist(img.ravel(), 256, [0, 256])
plt.show()For color histograms:
for i, col in enumerate(color):
hist = cv2.calcHist([img], [i], None, [256], [0, 256])
plt.plot(hist, color=col)
plt.xlim([0, 256])
plt.show()Histogram equalization is a method to improve image contrast by effectively spreading out the most frequent intensity values:
# Equalize histogram
equ = cv2.equalizeHist(img)CLAHE (Contrast Limited Adaptive Histogram Equalization) operates on small regions in the image, providing better results than standard histogram equalization:
# Create CLAHE object
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
# Apply CLAHE
cl1 = clahe.apply(img)2D histograms can be used to show the relationship between two channels:
# Convert to HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Calculate 2D histogram
hist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])OpenCV provides several methods to compare histograms:
# Calculate histograms
hist1 = cv2.calcHist([img1], [0], None, [256], [0, 256])
hist2 = cv2.calcHist([img2], [0], None, [256], [0, 256])
# Normalize histograms
hist1 = cv2.normalize(hist1, hist1).flatten()
hist2 = cv2.normalize(hist2, hist2).flatten()
# Compare using different methods
d1 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL)
d2 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CHISQR)
d3 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_INTERSECT)
d4 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_BHATTACHARYYA)Histogram backprojection is a way of finding objects in an image using their histogram:
# Convert to HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
target_hsv = cv2.cvtColor(target, cv2.COLOR_BGR2HSV)
# Calculate histogram of target
roihist = cv2.calcHist([target_hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
# Normalize histogram
cv2.normalize(roihist, roihist, 0, 255, cv2.NORM_MINMAX)
# Calculate backprojection
dst = cv2.calcBackProject([hsv], [0, 1], roihist, [0, 180, 0, 256], 1)def enhance_image(image):
# Split the image into color channels
b, g, r = cv2.split(image)
# Apply CLAHE to each channel
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
b = clahe.apply(b)
g = clahe.apply(g)
r = clahe.apply(r)
# Merge the channels back
enhanced = cv2.merge([b, g, r])
return enhanceddef detect_object(image, target):
# Convert images to HSV
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
target_hsv = cv2.cvtColor(target, cv2.COLOR_BGR2HSV)
# Calculate target histogram
target_hist = cv2.calcHist([target_hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
cv2.normalize(target_hist, target_hist, 0, 255, cv2.NORM_MINMAX)
# Calculate back projection
back_proj = cv2.calcBackProject([hsv], [0, 1], target_hist, [0, 180, 0, 256], 1)
# Apply threshold
_, thresh = cv2.threshold(back_proj, 50, 255, cv2.THRESH_BINARY)
return threshdef match_images(image1, image2):
# Calculate histograms
hist1 = cv2.calcHist([image1], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])
hist2 = cv2.calcHist([image2], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])
# Normalize histograms
cv2.normalize(hist1, hist1, 0, 1, cv2.NORM_MINMAX)
cv2.normalize(hist2, hist2, 0, 1, cv2.NORM_MINMAX)
# Compare histograms
similarity = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL)
return similaritydef auto_threshold(image):
# Calculate histogram
hist = cv2.calcHist([image], [0], None, [256], [0, 256])
# Find peak values
peak1 = np.argmax(hist[:128])
peak2 = np.argmax(hist[128:]) + 128
# Calculate threshold as midpoint
threshold = (peak1 + peak2) // 2
# Apply threshold
_, binary = cv2.threshold(image, threshold, 255, cv2.THRESH_BINARY)
return binaryHistograms are powerful tools in image processing that can be used for:
- Understanding image characteristics
- Improving image contrast
- Object detection and tracking
- Image matching and comparison
- Automatic thresholding and segmentation
In the next tutorial, we'll explore video basics in OpenCV, including how to capture, process, and save video streams.