Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Histogram Plotting and stretching in Python
Histogram plotting and stretching is a powerful technique in image processing and data visualization that allows you to represent the distribution of pixel intensities and improve image contrast. This process enhances visibility by spreading pixel values across the full intensity range (0-255).
A histogram shows the frequency distribution of pixel intensities in an image. Histogram stretching (also called contrast stretching) improves image contrast by mapping the current range of pixel values to utilize the full available range.
Method 1: Using Built-in Functions
OpenCV and Matplotlib provide built-in functions for histogram equalization and plotting. Here's how to plot and stretch histograms using these libraries ?
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Load sample image (requires external image file)
img = cv2.imread('sample.jpg', cv2.IMREAD_COLOR)
# Split into RGB channels
blue, green, red = cv2.split(img)
# Plot histograms for each channel
plt.figure(figsize=(10, 4))
plt.hist(red.ravel(), bins=256, color='red', alpha=0.7, label='Red')
plt.hist(green.ravel(), bins=256, color='green', alpha=0.7, label='Green')
plt.hist(blue.ravel(), bins=256, color='blue', alpha=0.7, label='Blue')
plt.xlabel('Pixel Intensity')
plt.ylabel('Frequency')
plt.title('Original Image Histograms')
plt.legend()
plt.show()
# Apply histogram equalization to each channel
red_stretched = cv2.equalizeHist(red)
green_stretched = cv2.equalizeHist(green)
blue_stretched = cv2.equalizeHist(blue)
# Merge channels back together
img_stretched = cv2.merge((blue_stretched, green_stretched, red_stretched))
# Display original and stretched images side by side
plt.figure(figsize=(12, 5))
plt.subplot(121)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title('Original Image')
plt.axis('off')
plt.subplot(122)
plt.imshow(cv2.cvtColor(img_stretched, cv2.COLOR_BGR2RGB))
plt.title('Histogram Equalized Image')
plt.axis('off')
plt.show()
Method 2: Manual Implementation
For educational purposes, here's how to implement histogram calculation and linear stretching without built-in functions ?
import numpy as np
import matplotlib.pyplot as plt
# Create sample image data for demonstration
np.random.seed(42)
img = np.random.randint(50, 200, (100, 100, 3), dtype=np.uint8)
# Split into RGB channels manually
red = img[:,:,0]
green = img[:,:,1]
blue = img[:,:,2]
# Calculate histograms manually
def calculate_histogram(channel):
histogram = np.zeros(256, dtype=int)
height, width = channel.shape
for i in range(height):
for j in range(width):
pixel_value = channel[i, j]
histogram[pixel_value] += 1
return histogram
# Calculate histograms for each channel
hist_red = calculate_histogram(red)
hist_green = calculate_histogram(green)
hist_blue = calculate_histogram(blue)
# Plot histograms
plt.figure(figsize=(10, 4))
plt.plot(range(256), hist_red, color='red', alpha=0.7, label='Red')
plt.plot(range(256), hist_green, color='green', alpha=0.7, label='Green')
plt.plot(range(256), hist_blue, color='blue', alpha=0.7, label='Blue')
plt.xlabel('Pixel Intensity')
plt.ylabel('Frequency')
plt.title('Manual Histogram Calculation')
plt.legend()
plt.show()
print("Original intensity ranges:")
print(f"Red: {red.min()} - {red.max()}")
print(f"Green: {green.min()} - {green.max()}")
print(f"Blue: {blue.min()} - {blue.max()}")
Original intensity ranges: Red: 50 - 199 Green: 50 - 199 Blue: 50 - 199
Linear Contrast Stretching
# Manual linear stretching function
def linear_stretch(channel):
min_val = np.min(channel)
max_val = np.max(channel)
# Avoid division by zero
if max_val == min_val:
return channel
# Linear transformation: new_value = (old_value - min) * 255 / (max - min)
stretched = ((channel.astype(float) - min_val) * 255 / (max_val - min_val))
return stretched.astype(np.uint8)
# Apply stretching to each channel
red_stretched = linear_stretch(red)
green_stretched = linear_stretch(green)
blue_stretched = linear_stretch(blue)
# Create stretched image
img_stretched = np.stack([red_stretched, green_stretched, blue_stretched], axis=2)
print("Stretched intensity ranges:")
print(f"Red: {red_stretched.min()} - {red_stretched.max()}")
print(f"Green: {green_stretched.min()} - {green_stretched.max()}")
print(f"Blue: {blue_stretched.min()} - {blue_stretched.max()}")
# Display comparison
plt.figure(figsize=(12, 5))
plt.subplot(121)
plt.imshow(img)
plt.title('Original Image')
plt.axis('off')
plt.subplot(122)
plt.imshow(img_stretched)
plt.title('Linear Stretched Image')
plt.axis('off')
plt.show()
Stretched intensity ranges: Red: 0 - 255 Green: 0 - 255 Blue: 0 - 255
Key Differences
| Technique | Method | Result | Use Case |
|---|---|---|---|
| Histogram Equalization | cv2.equalizeHist() |
Uniform distribution | General contrast enhancement |
| Linear Stretching | Manual scaling | Maintains relative relationships | Preserving image characteristics |
Practical Applications
Histogram stretching is commonly used in:
- Medical imaging Enhancing X-ray and MRI contrast
- Satellite imagery Improving visibility of terrain features
- Photography Correcting underexposed or low-contrast images
- Computer vision Preprocessing for better feature detection
Conclusion
Histogram plotting reveals pixel intensity distributions, while stretching improves image contrast by utilizing the full intensity range. Use built-in functions like cv2.equalizeHist() for efficiency, or implement manual stretching when you need precise control over the transformation process.
