π‘ Problem Formulation: In computer vision, precisely quantifying the shape of objects within an image is a common task. This article addresses the challenge of computing the area and perimeter of image contours using OpenCV with Python. Imagine you have an image with a single prominent object β your goal is to calculate the size (area) and outline length (perimeter) of this object. The input would be the image and the output, numeric values representing the area and perimeter of the detected contour.
Method 1: FindContours and ContourArea
This method involves using the findContours()
function to detect contours in an image, followed by the contourArea()
function to compute the area of the contour. This approach is suitable for finding the area of distinct objects in binary images.
Here’s an example:
import cv2 # Read the image and convert to grayscale image = cv2.imread('object.png') gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Find contours contours, _ = cv2.findContours(gray_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # Calculate the area of the first contour area = cv2.contourArea(contours[0]) print("Area of the contour:", area)
Output: Area of the contour: 15000.5
In this code, findContours()
returns a list of contours found in the grayscale image. The contourArea()
function then computes the area of the first contour in that list, which is printed to the console.
Method 2: ApproxPolyDP and Contour Perimeter
With approxPolyDP()
, one can approximate the contour to a more manageable shape, and then use the arcLength()
function to compute the perimeter, which can be particularly useful when you need a smoother contour for perimeter calculation.
Here’s an example:
import cv2 # Read the image and convert to grayscale image = cv2.imread('object.png') gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Find contours contours, _ = cv2.findContours(gray_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # Approximate the contour and calculate the perimeter epsilon = 0.01 * cv2.arcLength(contours[0], True) approx_contour = cv2.approxPolyDP(contours[0], epsilon, True) perimeter = cv2.arcLength(approx_contour, True) print("Perimeter of the contour:", perimeter)
Output: Perimeter of the contour: 510.2
After detecting contours using findContours()
, the code uses approxPolyDP()
to simplify the contour shape. The arcLength()
function then computes the perimeter of this approximated contour.
Method 3: Bounding Rectangle Area and Perimeter
Using the bounding rectangle’s area and perimeter is a fast way to get an approximation of the contour’s dimensions. The boundingRect()
method can provide a non-rotated rectangle that encloses the contour.
Here’s an example:
import cv2 # Read the image and convert to grayscale image = cv2.imread('object.png') gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Find contours contours, _ = cv2.findContours(gray_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # Calculate the bounding rectangle, then compute area and perimeter x, y, w, h = cv2.boundingRect(contours[0]) area = w * h perimeter = 2 * (w + h) print("Bounding rectangle area:", area) print("Bounding rectangle perimeter:", perimeter)
Output: Bounding rectangle area: 16000
Bounding rectangle perimeter: 520
This snippet calculates the bounding rectangle for the contour using boundingRect()
. The area and perimeter are then calculated using the width and height of the rectangle.
Method 4: Fitting an Ellipse
If the object is circular or elliptical, fitting an ellipse with fitEllipse()
can provide a more accurate measurement. This function returns the rotated rectangle in which the ellipse is inscribed.
Here’s an example:
import cv2 # Read the image and convert to grayscale image = cv2.imread('object.png') gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Find contours contours, _ = cv2.findContours(gray_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # Fit an ellipse to the contour and calculate the area ellipse = cv2.fitEllipse(contours[0]) area = 3.14 * ellipse[1][0] * ellipse[1][1] / 4 # Approximating Pi for simplicity print("Area of the fitted ellipse:", area)
Output: Area of the fitted ellipse: 14526.5
fitEllipse()
is used on the detected contour to create an inscribed ellipse. The area of this ellipse is then approximated using the major and minor axes provided by fitEllipse()
.
Bonus One-Liner Method 5: Simplified Contour Area
For a quick and simplified calculation, directly applying the contourArea()
function on the contour detected by findContours()
can provide an immediate result.
Here’s an example:
import cv2 # Read the image and convert to grayscale, find contours and calculate area print("Simplified contour area:", cv2.contourArea(cv2.findContours(cv2.cvtColor(cv2.imread('object.png'), cv2.COLOR_BGR2GRAY), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0][0]))
Output: Simplified contour area: 15000.5
This one-liner demonstrates the power of Python’s concise syntax by chaining function calls to immediately output the area of the first contour detected.
Summary/Discussion
- Method 1: FindContours and ContourArea. Accurate for binary images with distinct objects. Cannot handle complex or overlapping shapes.
- Method 2: ApproxPolyDP and Contour Perimeter. Good for getting a smooth contour for perimeter calculations. May oversimplify the contour and lose detail.
- Method 3: Bounding Rectangle Area and Perimeter. Quick and easy, provides a rough estimate. Not suitable for non-rectangular objects.
- Method 4: Fitting an Ellipse. Best for elliptical or circular objects, gives a precise area. Not applicable to non-elliptical shapes.
- Bonus Method 5: Simplified Contour Area. Quick and easy for single use cases. Lacks precision and control over the contour selection.