How to Check if an Image Contour is Convex or Not in OpenCV Python

πŸ’‘ Problem Formulation: When working with image processing in OpenCV Python, identifying the convexity of contours can be crucial for shape analysis and object detection. Given an image with an arbitrary shape detected as a contour, the task is to determine whether this contour is convex, wherein no indentations are present, or concave, indicating the presence of indentations. The desired output is a simple True (if convex) or False (if not convex).

Method 1: Using cv2.isContourConvex()

The cv2.isContourConvex() method in OpenCV provides a straightforward way to determine if a contour is convex. It takes a single contour as an argument and returns a boolean value indicating the convexity of the contour. This function is part of the OpenCV library and comes in handy for quick convexity checks.

Here’s an example:

import cv2

# Read an image
image = cv2.imread('path_to_image.jpg')

# Convert it to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# Find contours
contours, _ = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# Check if the first contour is convex
is_convex = cv2.isContourConvex(contours[0])

print(is_convex)

The output is either True or False depending on the convexity of the contour.

This code snippet loads an image, converts it to grayscale, and then finds the contours in the image. The cv2.isContourConvex() method is applied to the first contour to check for convexity, and the result is printed out.

Method 2: Analyzing the Contour’s Defects

Another method to determine a contour’s convexity is by analyzing its convexity defects using the cv2.convexHull() and cv2.convexityDefects() functions in OpenCV. If a contour has no convexity defects, it’s considered to be convex.

Here’s an example:

import cv2

# Read image
image = cv2.imread('path_to_image.jpg')

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

# Find contours
contours, _ = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# Find the convex hull of the contour
hull = cv2.convexHull(contours[0], returnPoints=False)

# Find convexity defects
defects = cv2.convexityDefects(contours[0], hull)

# Check if there are any defects
is_convex = defects is None

print(is_convex)

The output will again be True if the contour is convex, otherwise False.

After finding the contours and the convex hull of the first contour, we use the cv2.convexityDefects() to identify any convexity defects. If there are no defects found, then the contour is deemed convex.

Method 3: Checking Angle between Contour Points

Convex contours will have all internal angles less than or equal to 180 degrees. This method involves iterating through contour points and checking the angles formed by every three consecutive points.

Here’s an example:

import cv2
import numpy as np

# Read image
image = cv2.imread('path_to_image.jpg')

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

# Find contours
contours, _ = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contour = contours[0]

# Assume contour is convex initially
is_convex = True 

for i in range(len(contour)):
    # Take three points at a time
    pt1 = contour[i][0]
    pt2 = contour[(i + 1) % len(contour)][0]
    pt3 = contour[(i + 2) % len(contour)][0]
    
    # Calculate the angle
    angle = np.abs(np.arctan2(pt3[1]-pt2[1], pt3[0]-pt2[0]) - np.arctan2(pt1[1]-pt2[1], pt1[0]-pt2[0]))
    
    # If the angle is greater than 180 degrees, it's not convex.
    if np.degrees(angle) > 180:
        is_convex = False
        break

print(is_convex)

The output will be a boolean value indicating the convexity of the contour.

This code snippet calculates the angles using the arctangent function. If any angle exceeds 180 degrees, the loop breaks and determines that the contour is not convex.

Method 4: Approximating Contour and Comparing with Original

A more approximate method might be to simplify the contour with cv2.approxPolyDP() and then check if the simplified contour has the same number of points as the original. If it does, the original contour is likely convex.

Here’s an example:

import cv2

# Read image
image = cv2.imread('path_to_image.jpg')

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

# Find contours
contours, _ = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contour = contours[0]

# Approximate the contour
epsilon = 0.01*cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, epsilon, True)

# Check if the approximated contour has the same number of points
is_convex = len(approx) == len(contour)

print(is_convex)

The output is a boolean value denoting whether the contour is convex.

By approximating the contour, we simplify its shape. If the number of points remains unchanged, it suggests that the contour did not have any indentations to begin with and is likely convex.

Bonus One-Liner Method 5: Convexity through Shape Matching

For a quick one-liner, you can compare the contour to a convex hull and check for a match using cv2.matchShapes(). If the result is close to zero, the shapes are similar, indicating the contour is convex.

Here’s an example:

import cv2

# Read image
image = cv2.imread('path_to_image.jpg')

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

# Find contours and convex hull
contours, _ = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
hull = cv2.convexHull(contours[0])

# One-liner to check for convexity
is_convex = cv2.matchShapes(contours[0], hull, 1, 0.0) < 1e-3

print(is_convex)

The output will be True if the contour is convex, otherwise False.

This efficient one-liner code snippet uses shape matching to compare the original contour with its convex hull. If the matching value is very small, it indicates that the two shapes are very similar, hence the original contour is convex.

Summary/Discussion

  • Method 1: Using cv2.isContourConvex(). It’s a direct and clear method provided by OpenCV. Strengths: efficient and easy to use. Weaknesses: less flexible if further analysis is required.
  • Method 2: Analyzing the contour’s defects. Strengths: provides additional information about the contour’s structure. Weaknesses: a bit more complex than the direct method.
  • Method 3: Checking the angle between contour points. Strengths: it gives a deeper understanding of the shape’s geometry. Weaknesses: computationally expensive for large contours.
  • Method 4: Approximating contour and comparing with the original. Strengths: good for quick estimates. Weaknesses: might not be accurate, particularly for complex shapes.
  • Method 5: Convexity through shape matching. Strengths: quick one-liner check. Weaknesses: might return false positives if the matchShapes threshold is not well-adjusted.