How to split a contour into separate regions with OpenCV

Based on contributions by gamalalfauza.

OpenCV’s contour finder treats a single connected shape as one contour. If you need to treat two touching or overlapping parts of that shape as separate regions (for example, to measure their areas independently), you can split it by drawing a dividing line onto the mask before finding contours again. This how-to walks through the technique on a simple circle.

What you need

  • Python with OpenCV: pip install opencv-python
  • NumPy: pip install numpy

Steps

1. Create a binary image with your shape

You need a black-and-white (binary) image to trace a contour from. This example draws a filled circle on a black canvas and thresholds it.

import cv2
import numpy as np
import copy

# Generate a 640x640 black image
image = np.zeros((640, 640), dtype=np.uint8)

# Draw a filled circle
cv2.circle(image, (320, 320), 200, 255, -1)

# Apply a binary threshold to get a clean binary image
_, binary_image = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)

2. Find and draw the original contour

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

contour_image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)  # convert to BGR for color drawing
cv2.drawContours(contour_image, contours, -1, (0, 255, 0), 2)  # draw all contours in green

3. Split the contour by drawing a dividing line

Draw a black line across the shape to break it into two separate regions, then re-run the contour finder on the modified image. You need to choose the two endpoints of the dividing line yourself, based on where you want the split.

def split_contour(image):
    # Work on a copy so the original binary image isn't modified
    image_copy = copy.deepcopy(image)

    # Start and end point of the dividing line
    point1 = (0, 320)
    point2 = (640, 320)

    cv2.line(image_copy, point1, point2, (0, 0, 0), 3)

    split_contours, _ = cv2.findContours(image_copy, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    return split_contours

4. Process and display the split contours

split_contours = []
contours = split_contour(image)

if len(contours) == 2:  # keep only the expected two-way split
    area1 = cv2.contourArea(contours[0])
    area2 = cv2.contourArea(contours[1])
    area_diff = abs(area1 - area2)
    split_contours = contours

areas = [cv2.contourArea(contour) for contour in split_contours]
print(f"Areas of contours: {areas}")

# Draw the split contours in different colors on a fresh copy
contour_image_split = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
for i, contour in enumerate(split_contours):
    color = (int(np.random.randint(0, 256)), int(np.random.randint(0, 256)), int(np.random.randint(0, 256)))
    cv2.drawContours(contour_image_split, split_contours, i, color, 5)

cv2.imshow("Original image", image)
cv2.imshow("Contour image", contour_image)
cv2.imshow("Split image", contour_image_split)

cv2.waitKey(0)  # wait for a key press so the windows don't close immediately
cv2.destroyAllWindows()

Common mistakes

  • Assuming the split always produces exactly 2 contours: if the dividing line doesn’t fully cross the shape, or the shape has an irregular outline, findContours may return more or fewer regions than expected. The if len(contours) == 2: check above only accepts a clean two-way split; adjust it if you expect a different number of pieces.
  • Picking a dividing line that doesn’t fully span the shape: the line must cross the entire object, otherwise the two halves stay connected and you still get one contour.

Related


Rewritten and consolidated (Sept 2026) from the original student how-to’s: How to split a contour with python and OpenCV.