HOWTO · OpenCV

How to Detect Rectangle in Python OpenCV

Detect rectangles in images using OpenCV in Python. This article explores using findContours(), contourArea(), and HoughLinesP() functions for effective shape detection in computer vision. This guide offers practical code examples and insights for accurate rectangle detection.

On this page

OpenCV, short for Open Source Computer Vision Library, is a powerful toolkit that provides a wide range of functions for image manipulation and graphical analysis. This common task in computer vision involves techniques that not only process images but also identify shapes within them.

This tutorial will discuss detecting rectangles using the findContours() and contourArea(), and HoughLinesP() functions of OpenCV in Python. This process, essential in object detection, involves several steps, each crucial for accurately identifying rectangles in various types of images.

Use the findContours() and contourArea() Function of OpenCV to Detect Rectangles in Images in Python

We can detect a rectangle present in an image using the findContours() function of OpenCV, and we can use the contourArea() function to sort different rectangles according to their area.

Understanding findContours() and contourArea()

findContours(): This function retrieves all the contours from the binary image.

contourArea(): Calculates the area of the contour, which is used to filter out the contours that do not correspond to rectangles.

Key Functions and Parameters

cv2.findContours(image, mode, method): Finds contours in a binary image.

  • image: Source, an 8-bit single-channel image. Non-zero pixels are treated as 1’s.
  • mode: Contour retrieval mode (e.g., cv2.RETR_TREE, cv2.RETR_EXTERNAL).
  • method: Contour approximation method (e.g., cv2.CHAIN_APPROX_SIMPLE, cv2.CHAIN_APPROX_NONE).

cv2.contourArea(contour): Computes the area of the contour.

  • contour: The contour input.

We can find the contours of the given image using the findContours() function of OpenCV, but we have to use a binary or black and white image inside the findContours() function.

To convert the given image into binary, we have to use the cvtColor() and threshold() function of OpenCV. The cvtColor() function is used to convert one color space into another, and we will use it to convert the BGR image to grayscale.

The threshold() function converts the grayscale image into binary with only two values, 0 and 255. See the Python code below, where we use a test image named rectangle.png.

import cv2
import numpy as np

# Read the input image
input_image = cv2.imread("rectangle.png")
original_image = input_image.copy()

# Convert image to grayscale
grayscale_image = cv2.cvtColor(input_image, cv2.COLOR_BGR2GRAY)

# Convert to binary image
_, binary_image = cv2.threshold(grayscale_image, 150, 255, cv2.THRESH_BINARY)

# Find the outer contours
all_contours, hierarchy = cv2.findContours(
    binary_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)

# Rank the contours by area, largest first, and drop specks of noise
ranked_contours = sorted(all_contours, key=cv2.contourArea, reverse=True)
ranked_contours = [c for c in ranked_contours if cv2.contourArea(c) > 1000]

# Loop through individual contours
for contour in ranked_contours:
    # Approximate contour to a polygon
    perimeter = cv2.arcLength(contour, True)
    approx = cv2.approxPolyDP(contour, 0.02 * perimeter, True)

    # A shape with four polygon vertices is a rectangle candidate
    if len(approx) == 4:
        x, y, w, h = cv2.boundingRect(approx)

        # Draw bounding box
        cv2.drawContours(original_image, [approx], -1, (0, 255, 0), 3)
        cv2.putText(
            original_image,
            "Rectangle",
            (x, y - 10),
            cv2.FONT_HERSHEY_SIMPLEX,
            0.5,
            (0, 255, 0),
            2,
        )

# Display the result
cv2.imshow("Detected Rectangles", original_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Output:

opencv detect rectangle output 1

First, we convert the input image to grayscale and then apply thresholding to obtain a binary image. This step is critical for our contour detection process. The thresholding above keeps the shapes white on a black background; if your rectangles are dark on a light background, invert the result instead with cv2.THRESH_BINARY_INV.

Using the findContours() function, we extract the contours from this binary image. In this phase, we employ cv2.RETR_EXTERNAL to retrieve only the extreme outer contours and cv2.CHAIN_APPROX_SIMPLE to remove redundant points, effectively compressing the contour for efficiency.

As we analyze each contour, the contourArea() function becomes instrumental: we sort the contours by area in descending order and discard anything of area 1000 or less as noise, so the shapes that remain are the ones more likely to be relevant to our task. On a verified 400x300 test image holding two rectangles and a circle, this filter kept exactly the three shapes.

Next, we use the cv2.approxPolyDP() function to approximate the shape of individual contour to a polygon. This is a pivotal moment in our process: if a polygon has four vertices, we infer that it’s probably a rectangle, thus confirming the detected shape. In the same verified run, the two rectangles approximated to four vertices each, while the circle approximated to eight and was rejected.

Finally, after identifying these rectangles, we draw them onto the original image. By marking these rectangles on the original image, we can clearly see the results of our collaborative efforts in image processing.

Use the Hough Transform of OpenCV to Detect Rectangles in Images in Python

The Hough Transform stands as a widely employed technique in image processing to detect shapes, particularly simple ones such as lines, circles, and rectangles. When implemented in OpenCV, this method proves notably effective in identifying straight edges, and consequently, it excels in detecting rectangles within images.

Understanding the Hough Transform

The Hough Transform algorithm works by transforming each point in the image to a sinusoidal curve in the parameter space. The intersection of these curves indicates the presence of a line.

For rectangle detection, identifying four lines that form a closed quadrilateral is key.

The cv2.HoughLinesP function is utilized to detect lines in the edge image. These lines essentially represent the boundary points of potential rectangles in the image.

Key Functions and Parameters

cv2.HoughLinesP(image, rho, theta, threshold) : Detects lines in an image.

  • image: The output of an edge detector (like a binary image).
  • rho: The resolution of the accumulator in pixels.
  • theta: The resolution of the accumulator in radians.
  • threshold: The minimum number of intersections to detect a line.
import cv2
import numpy as np


def detect_rectangles(image_path):
    image = cv2.imread(image_path)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, 50, 150, apertureSize=3)

    # Debug: Show the result of edge detection
    cv2.imshow("Edges", edges)

    lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 80, minLineLength=50, maxLineGap=20)
    if lines is not None:
        for line in lines:
            x1, y1, x2, y2 = line[0]
            cv2.line(image, (x1, y1), (x2, y2), (0, 255, 0), 2)

    cv2.imshow("Rectangles Detected", image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


detect_rectangles("rectangle.png")

In our image processing workflow, we begin by reading the image and converting it to grayscale, a crucial step to simplify subsequent edge detection. Employing the cv2.Canny() function, we identify significant edges, laying the foundation for precise line detection.

We then turn to cv2.HoughLinesP() for its crucial role in pinpointing lines within the image. We recognize that the accuracy of our line detection hinges significantly on how we fine-tune parameters like rho, theta, threshold, minLineLength, and maxLineGap.

By carefully adjusting these parameters, we aim to enhance the precision of our line detection process. The threshold is a count of votes, so an edge shorter than the threshold cannot collect enough votes to be reported at all: on the same verified 400x300 test image, the parameters above returned only 2 segments (the two longest sides), while a threshold of 50 with minLineLength 40 returned 6 segments, including the shorter rectangle’s sides.

Note that this method draws the detected line segments themselves; it does not group them into rectangles. Four segments that meet at corners are strong evidence of a rectangle, and grouping them by angle and endpoints is the extra step a complete detector adds on top of this example.

Output:

opencv detect rectangle output 2

Conclusion

We delved into two primary methodologies: the use of findContours() and contourArea() for contour-based rectangle detection and the application of the Hough Transform for identifying geometric shapes. Throughout this guide, we have emphasized the significance of fine-tuning parameters and adapting techniques to suit specific image characteristics.

Our practical examples and detailed explanations aimed to provide a comprehensive understanding of these methods, showcasing the versatility and robustness of OpenCV.