Now that we've explored the concepts behind fundamental image processing techniques like adjusting brightness and contrast, applying geometric transformations, and smoothing images, it's time to put this knowledge into practice. This hands-on section will guide you through implementing these operations using Python and the OpenCV library. We'll assume you have your Python environment set up with OpenCV installed, as covered in Chapter 1.
First, let's ensure we have the necessary libraries imported and a sample image to work with. If you don't have a sample image readily available, you can easily find one online (search for "royalty-free images") or use a standard test image like the "Lena" or "Peppers" image, often available in computer vision datasets or easily downloadable. Save your chosen image to the same directory as your Python script or notebook.
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Load an image in color
# Replace 'your_image.jpg' with the path to your image file
image_path = 'your_image.jpg'
image = cv2.imread(image_path)
# Check if the image was loaded successfully
if image is None:
print(f"Error: Could not load image from {image_path}")
# You might want to exit or raise an error here
else:
# OpenCV loads images in BGR format by default.
# Matplotlib expects RGB. Let's convert for display purposes.
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# Display the original image using Matplotlib
plt.figure(figsize=(6, 6))
plt.imshow(image_rgb)
plt.title('Original Image')
plt.axis('off') # Hide axes ticks
plt.show()
Make sure to replace 'your_image.jpg'
with the actual path to your image file. Running this code should display your original image. If you encounter an error, double-check the file path and ensure OpenCV is installed correctly.
Remember that brightness is adjusted by adding a value to each pixel, and contrast by multiplying. Let's try this.
Brightness Adjustment: We'll increase the brightness by adding a constant value (e.g., 50) to each pixel. We need to be careful not to exceed the maximum pixel value (255). OpenCV handles this automatically with functions like cv2.add
.
# --- Brightness Adjustment ---
# Create a matrix of the same size as the image, filled with the brightness value
brightness_value = 50
brightness_matrix = np.ones(image.shape, dtype=image.dtype) * brightness_value
# Add the brightness matrix to the original image
# cv2.add performs saturation arithmetic (clips values at 0 and 255)
brighter_image = cv2.add(image, brightness_matrix)
# Convert BGR to RGB for display
brighter_image_rgb = cv2.cvtColor(brighter_image, cv2.COLOR_BGR2RGB)
# Display the brighter image
plt.figure(figsize=(6, 6))
plt.imshow(brighter_image_rgb)
plt.title(f'Brightness Increased by {brightness_value}')
plt.axis('off')
plt.show()
Contrast Adjustment: We'll increase the contrast by multiplying pixel values by a factor (e.g., 1.5). Again, cv2.multiply
helps manage potential overflow.
# --- Contrast Adjustment ---
contrast_factor = 1.5
# Note: cv2.multiply works similarly regarding saturation
# For contrast, ensure the factor is a float if needed
contrast_image = cv2.multiply(image, np.array([contrast_factor]))
# Clipping might be necessary manually if not using specific cv2 functions
# Or ensure the multiplication doesn't cause unexpected type changes
# A common way is convertScaleAbs which scales, calculates absolute values, and converts back to 8-bit
contrast_image_scaled = cv2.convertScaleAbs(image, alpha=contrast_factor, beta=0)
# Convert BGR to RGB for display
contrast_image_rgb = cv2.cvtColor(contrast_image_scaled, cv2.COLOR_BGR2RGB)
# Display the contrast-adjusted image
plt.figure(figsize=(6, 6))
plt.imshow(contrast_image_rgb)
plt.title(f'Contrast Increased (Factor: {contrast_factor})')
plt.axis('off')
plt.show()
Experiment with different brightness_value
(positive to increase, negative to decrease) and contrast_factor
(greater than 1 for more contrast, less than 1 for less) values to see their effects.
Now let's resize, rotate, and translate our image.
Scaling (Resizing): We can make the image larger or smaller using cv2.resize
.
# --- Scaling (Resizing) ---
# Get original dimensions
height, width = image.shape[:2]
# Define new dimensions (e.g., half the original size)
new_width = int(width * 0.5)
new_height = int(height * 0.5)
new_dimensions = (new_width, new_height)
# Resize the image - cv2.INTER_LINEAR is a common interpolation method
resized_image = cv2.resize(image, new_dimensions, interpolation=cv2.INTER_LINEAR)
# Convert BGR to RGB for display
resized_image_rgb = cv2.cvtColor(resized_image, cv2.COLOR_BGR2RGB)
# Display the resized image
plt.figure(figsize=(4, 4)) # Adjust figure size if needed
plt.imshow(resized_image_rgb)
plt.title(f'Resized to {new_width}x{new_height}')
plt.axis('off')
plt.show()
Try different scaling factors and interpolation methods like cv2.INTER_CUBIC
(often better quality for enlarging) or cv2.INTER_AREA
(often better for shrinking).
Rotation: To rotate the image, we first calculate a rotation matrix using cv2.getRotationMatrix2D
and then apply it using cv2.warpAffine
.
# --- Rotation ---
# Get image center
(cX, cY) = (width // 2, height // 2)
# Angle of rotation in degrees (positive for counter-clockwise)
angle = 45
# Scale factor during rotation (1.0 means same size)
scale = 1.0
# Calculate the rotation matrix
M_rotate = cv2.getRotationMatrix2D((cX, cY), angle, scale)
# Perform the rotation
rotated_image = cv2.warpAffine(image, M_rotate, (width, height))
# Convert BGR to RGB for display
rotated_image_rgb = cv2.cvtColor(rotated_image, cv2.COLOR_BGR2RGB)
# Display the rotated image
plt.figure(figsize=(6, 6))
plt.imshow(rotated_image_rgb)
plt.title(f'Rotated by {angle} Degrees')
plt.axis('off')
plt.show()
Translation (Shifting): Translation also uses cv2.warpAffine
, but with a different transformation matrix. We define how much to shift along the X and Y axes.
# --- Translation ---
# Define shift amounts (tx: horizontal, ty: vertical)
tx = 50 # Shift right by 50 pixels
ty = 25 # Shift down by 25 pixels
# Create the translation matrix M
# [[1, 0, tx],
# [0, 1, ty]]
M_translate = np.float32([[1, 0, tx], [0, 1, ty]])
# Apply the translation
# (width, height) defines the output image size
translated_image = cv2.warpAffine(image, M_translate, (width, height))
# Convert BGR to RGB for display
translated_image_rgb = cv2.cvtColor(translated_image, cv2.COLOR_BGR2RGB)
# Display the translated image
plt.figure(figsize=(6, 6))
plt.imshow(translated_image_rgb)
plt.title(f'Translated by ({tx}, {ty})')
plt.axis('off')
plt.show()
Notice how parts of the image might move out of the frame, and the newly exposed areas are filled with black.
Finally, let's apply basic smoothing filters to reduce noise.
Average Blurring: This filter replaces each pixel with the average of its neighbors within a defined kernel size.
# --- Average Blurring ---
# Define the kernel size (e.g., 5x5)
# Larger kernel size means more blurring
kernel_size_avg = (5, 5)
average_blurred = cv2.blur(image, kernel_size_avg)
# Convert BGR to RGB for display
average_blurred_rgb = cv2.cvtColor(average_blurred, cv2.COLOR_BGR2RGB)
# Display the average blurred image
plt.figure(figsize=(6, 6))
plt.imshow(average_blurred_rgb)
plt.title(f'Average Blurred ({kernel_size_avg[0]}x{kernel_size_avg[1]} Kernel)')
plt.axis('off')
plt.show()
Gaussian Blurring: This uses a Gaussian kernel, giving more weight to central pixels, often resulting in a more natural-looking blur.
# --- Gaussian Blurring ---
# Define kernel size (must be positive and odd)
kernel_size_gauss = (5, 5)
# SigmaX (standard deviation in X direction). If 0, it's calculated from kernel size.
sigmaX = 0
gaussian_blurred = cv2.GaussianBlur(image, kernel_size_gauss, sigmaX)
# Convert BGR to RGB for display
gaussian_blurred_rgb = cv2.cvtColor(gaussian_blurred, cv2.COLOR_BGR2RGB)
# Display the Gaussian blurred image
plt.figure(figsize=(6, 6))
plt.imshow(gaussian_blurred_rgb)
plt.title(f'Gaussian Blurred ({kernel_size_gauss[0]}x{kernel_size_gauss[1]} Kernel)')
plt.axis('off')
plt.show()
Compare the results of the Average and Gaussian filters. Gaussian blurring is generally preferred for noise reduction as it tends to preserve edges slightly better than simple averaging for the same amount of smoothing.
In this hands-on section, you've learned how to practically apply fundamental image processing techniques using OpenCV:
cv2.add
, cv2.multiply
).cv2.resize
), rotation (cv2.getRotationMatrix2D
, cv2.warpAffine
), and translation (cv2.warpAffine
with a translation matrix).cv2.blur
) and Gaussian blur (cv2.GaussianBlur
).These operations form the building blocks for many computer vision applications. They are often used as preprocessing steps to enhance images, normalize their appearance, or prepare them for feature extraction and analysis, which we will begin exploring in the next chapter. Keep experimenting with different parameters and images to solidify your understanding.
© 2025 ApX Machine Learning