Computer Vision Techniques

Computer_Vision_001 _ Color Detection with OpenCV

codeaddict 2024. 12. 26. 00:18

In this post, we will learn how to use the HSV (Hue, Saturation, Value) color model for detecting yellow color in an image. We will walk through each step, including importing libraries, loading an image, converting the image to HSV color space, creating a mask for yellow color, finding contours, and drawing bounding boxes around the yellow regions. By the end of this post, you’ll understand how to use HSV for color detection and how to apply it with OpenCV to detect yellow color in images.


Step 1: Install and Import Required Libraries

To get started, we need to import the libraries that will help us process images and display results. The three libraries we need are:

  • OpenCV (cv2): For image processing tasks like reading, displaying, and manipulating images.
  • NumPy (np): For handling arrays, which are used to represent images.
  • Matplotlib (plt): For displaying images in a more user-friendly way.

Let’s begin by importing these libraries:

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

Explanation:

  • cv2 is the main library for computer vision tasks.
  • numpy helps us work with images as arrays.
  • matplotlib.pyplot is used for displaying images in the jupyter notebook.

Step 2: What is HSV and Why Do We Use It?

Before we dive into the code, let’s first understand HSV (Hue, Saturation, Value), which we will use to detect yellow color in the image.

HSV Breakdown:

  • Hue: Represents the color type (e.g., red, blue, green). It is represented as an angle on a color wheel (0° to 360°).
  • Saturation: Indicates the intensity or vividness of the color. A fully saturated color is bright and pure, while less saturated colors are faded or grayish.
  • Value: Represents the brightness or lightness of the color. A value of 0 is completely dark (black), and a value of 255 is completely bright (white).

In the RGB color model (Red, Green, Blue), colors are created by combining different amounts of red, green, and blue light. However, this model is not ideal for color detection because the same color might look different under various lighting conditions. The HSV model separates color information (hue) from brightness and intensity, which makes it easier to detect colors like yellow, red, or green, especially under varying light conditions.


Step 3: Load an Image

Next, let’s load an image that we will use to detect yellow color. Replace 'your_image.jpg' with the path to your image.

image_path = 'vvv.jpg'  # Replace with your image path
image = cv2.imread(image_path)

# Display the original image
plt.figure(figsize=(6,6))
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.title("Original Image")
plt.axis('off')
plt.show()

Explanation:

  • cv2.imread(image_path) loads the image from the specified path.
  • cv2.cvtColor(image, cv2.COLOR_BGR2RGB) converts the image from BGR (Blue, Green, Red) to RGB for proper display using matplotlib.
  • plt.imshow() displays the image.

Output:
The original image will be displayed.

Step 4: Convert the Image to HSV

Now, we’ll convert the image from the BGR color space (the default color space in OpenCV) to HSV color space.

hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

# Display the HSV image
plt.figure(figsize=(6,6))
plt.imshow(cv2.cvtColor(hsv_image, cv2.COLOR_BGR2RGB))
plt.title("HSV Image")
plt.axis('off')
plt.show()

Explanation:

  • cv2.cvtColor(image, cv2.COLOR_BGR2HSV) converts the image from BGR to HSV color space. This will make it easier to isolate the yellow color.
  • plt.imshow() displays the image in the HSV color space.

Output:
You will see an image with colors now represented in the HSV model.

Step 5: Define the HSV Range for Yellow Color

Next, we’ll define the HSV range that corresponds to the yellow color. Yellow typically has a hue between 20° and 30°.

yellow_lower = np.array([20, 100, 100])  # Lower boundary for yellow in HSV
yellow_upper = np.array([30, 255, 255])  # Upper boundary for yellow in HSV

Explanation:

  • The lower range for yellow starts at 20° for hue, with saturation and value set to 100 (moderate intensity and brightness).
  • The upper range for yellow ends at 30° for hue, with saturation and value set to 255 (maximum intensity and brightness).

Step 6: Create a Mask for Yellow Color

We will now create a mask that highlights all yellow areas in the image. The mask will be a binary image where yellow areas are white (255), and non-yellow areas are black (0).

mask = cv2.inRange(hsv_image, yellow_lower, yellow_upper)

# Display the mask
plt.figure(figsize=(6,6))
plt.imshow(mask, cmap='gray')
plt.title("Yellow Mask")
plt.axis('off')
plt.show()

Explanation:

  • cv2.inRange(hsv_image, yellow_lower, yellow_upper) generates a mask where pixels within the defined yellow range are white (255), and others are black (0).
  • plt.imshow(mask, cmap='gray') displays the mask in grayscale.

Output:
A black-and-white image where the white areas represent detected yellow regions.

Step 7: Find Contours and Draw Bounding Boxes

We will now find the contours of the yellow areas in the mask.

contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Draw the contours on the original image (before bounding boxes)
output_image_contours = image.copy()
cv2.drawContours(output_image_contours, contours, -1, (255, 0, 0), 3) 

# Display the image with contours
plt.figure(figsize=(6,6))
plt.imshow(cv2.cvtColor(output_image_contours, cv2.COLOR_BGR2RGB))
plt.title("Contours of Yellow Areas")
plt.axis('off')
plt.show()

Explanation:

  • cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) finds the contours (outlines) of the yellow regions.

Parameters:

  1. mask: This is the binary image (black and white image) where the white areas represent yellow regions, and the black areas are everything else. The mask was created earlier using cv2.inRange() to filter out yellow areas in the HSV image.
  2. cv2.RETR_EXTERNAL: This flag specifies the retrieval mode. RETR_EXTERNAL means we only retrieve the outermost contours, ignoring any nested contours within them. This is useful if we only care about detecting larger, isolated yellow regions.
  3. cv2.CHAIN_APPROX_SIMPLE: This flag specifies the contour approximation method. CHAIN_APPROX_SIMPLE reduces the number of points that define the contour by approximating them to fewer points, thus simplifying the contour representation. This helps in reducing computational complexity.

Output:

  • contours: This is a list of contours, where each contour is represented by a list of points (vertices) that outline the detected yellow regions.
  • _: This is a placeholder for the second return value, which is the hierarchy of contours (not used in this case).

 

cv2.drawContours(output_image_contours, contours, -1, (255, 0, 0), 3):

  • This function is used to draw the contours found in the previous step on the image.
  • output_image_contours: The image where the contours will be drawn.
  • contours: The list of contours that we want to draw on the image.
  • -1: This indicates that we want to draw all the contours (if you specify a particular contour index, only that one would be drawn).
  • (255, 0, 0): The color of the contours. Here, it's set to blue (in BGR format), which will be used to draw the contours on the image.
  • 3: The thickness of the contour lines.

 

Result:

  • This step draws all the detected contours (outlines of yellow regions) on the image using a blue color and a thickness of 3 pixels.

Output:

 

 


Step 8: Displaying the Image with Contours

Finally, let’s display the processed image with yellow areas detected. We only draw boxes around large enough contours (area > 500 pixels).

output_image = image.copy()
for contour in contours:
    # Get the bounding box for each contour
    x, y, w, h = cv2.boundingRect(contour)
    
    # Draw the bounding box
    if cv2.contourArea(contour) > 500:  # Filter small areas
        cv2.rectangle(output_image, (x, y), (x + w, y + h), (0, 255, 0), 2)  # Green box

# Display the image with bounding boxes
plt.figure(figsize=(6,6))
plt.imshow(cv2.cvtColor(output_image, cv2.COLOR_BGR2RGB))
plt.title("Yellow Detection with Bounding Boxes")
plt.axis('off')
plt.show()

Output:


Now, let’s wrap up the tutorial by creating a function that accepts an image as input and detects yellow color, drawing bounding boxes around the yellow areas. This will make the code reusable and more organized.

Here’s the complete function-based solution:

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

def detect_yellow_color(image_path):
    """
    This function takes an image file path, detects yellow color areas using HSV color space,
    and returns the image with bounding boxes drawn around the detected yellow areas.
    """
    # Load the image
    image = cv2.imread(image_path)

    # Convert the image to HSV color space
    hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

    # Define the HSV range for yellow color
    yellow_lower = np.array([20, 100, 100])  # Lower bound for yellow color
    yellow_upper = np.array([30, 255, 255])  # Upper bound for yellow color

    # Create a mask to isolate yellow color
    mask = cv2.inRange(hsv_image, yellow_lower, yellow_upper)

    # Find contours of the yellow areas
    contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # Create a copy of the original image to draw bounding boxes on
    output_image = image.copy()

    # Loop through each contour and draw a bounding box around the detected yellow areas
    for contour in contours:
        x, y, w, h = cv2.boundingRect(contour)
        if cv2.contourArea(contour) > 500:  # Filter out small contours
            cv2.rectangle(output_image, (x, y), (x + w, y + h), (0, 255, 0), 2)  # Draw green bounding box

    # Convert the output image to RGB for display with matplotlib
    output_image_rgb = cv2.cvtColor(output_image, cv2.COLOR_BGR2RGB)

    # Display the original and processed images side by side
    plt.figure(figsize=(12, 6))

    # Display original image
    plt.subplot(1, 2, 1)
    plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
    plt.title("Original Image")
    plt.axis('off')

    # Display processed image with yellow color detection
    plt.subplot(1, 2, 2)
    plt.imshow(output_image_rgb)
    plt.title("Yellow Color Detection with Bounding Boxes")
    plt.axis('off')

    # Show the plots
    plt.show()

    return output_image

# Example usage
image_path = 'vvv.jpg'  # Replace with your image path
output_image = detect_yellow_color(image_path)

 

 

Conclusion

In this tutorial, we’ve learned how to detect yellow color in an image using the HSV color model. By converting the image to HSV, defining the yellow color range, creating a mask, and finding contours, we successfully isolated and highlighted yellow areas with bounding boxes. This approach is powerful for color detection tasks in computer vision.