[Python] Area of a closed contour on a plot using python openCV

Discussão em 'Python' iniciado por Stack, Junho 21, 2025.

  1. Stack

    Stack Membro Participativo

    I am attempting to find the area inside an arbitrarily-shaped closed curve plotted in python (example image below). So far, I have tried to use both the alphashape and polygon methods to acheive this, but both have failed. I am now attempting to use OpenCV and the floodfill method to count the number of pixels inside the curve and then I will later convert that to an area given the area that a single pixel encloses on the plot. Example image: testplot.jpg [​IMG]

    In order to do this, I am doing the following, which I adapted from another post about OpenCV.

    import cv2
    import numpy as np

    # Input image
    img = cv2.imread('testplot.jpg', cv2.IMREAD_GRAYSCALE)

    # Dilate to better detect contours
    temp = cv2.dilate(temp, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)))

    # Find largest contour
    cnts, _ = cv2.findContours(255-temp, cv2.RETR_TREE , cv2.CHAIN_APPROX_NONE) #255-img and cv2.RETR_TREE is to account for how cv2 expects the background to be black, not white, so I convert the background to black.
    largestCnt = [] #I expect this to yield the blue contour
    for cnt in cnts:
    if (len(cnt) > len(largestCnt)):
    largestCnt = cnt

    # Determine center of area of largest contour
    M = cv2.moments(largestCnt)
    x = int(M["m10"] / M["m00"])
    y = int(M["m01"] / M["m00"])

    # Initial mask for flood filling, should cover entire figure
    width, height = temp.shape
    mask = img2 = np.ones((width + 2, height + 2), np.uint8) * 255
    mask[1:width, 1:height] = 0

    # Generate intermediate image, draw largest contour onto it, flood fill this contour
    temp = np.zeros(temp.shape, np.uint8)
    temp = cv2.drawContours(temp, largestCnt, -1, 255, cv2.FILLED)
    _, temp, mask, _ = cv2.floodFill(temp, mask, (x, y), 255)
    temp = cv2.morphologyEx(temp, cv2.MORPH_OPEN, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)))

    area = cv2.countNonZero(temp) #Number of pixels encircled by blue line


    I expect from this to get to a place where I have the same image as above, but with the center of the contour filled in white and the background and original blue contour in black. I end up with this:

    result.jpg [​IMG]

    While this at first glance appears to have accurately turned the area inside the contour white, the white area is actually larger than the area inside the contour and so the result I get is overestimating the number of pixels inside it. Any input on this would be greatly appreciated. I am fairly new to OpenCV so I may have misunderstood something.

    EDIT: Thanks to a comment below, I made some edits and this is now my code, with edits noted:

    import cv2
    import numpy as np

    # EDITED INPUT IMAGE: Input image
    img = cv2.imread('testplot2.jpg', cv2.IMREAD_GRAYSCALE)

    # EDIT: threshold
    _, temp = cv2.threshold(img, 250, 255, cv2.THRESH_BINARY_INV)

    # EDIT, REMOVED: Dilate to better detect contours

    # Find largest contour
    cnts, _ = cv2.findContours(temp, cv2.RETR_EXTERNAL , cv2.CHAIN_APPROX_NONE)
    largestCnt = [] #I expect this to yield the blue contour
    for cnt in cnts:
    if (len(cnt) > len(largestCnt)):
    largestCnt = cnt

    # Determine center of area of largest contour
    M = cv2.moments(largestCnt)
    x = int(M["m10"] / M["m00"])
    y = int(M["m01"] / M["m00"])


    # Initial mask for flood filling, should cover entire figure
    width, height = temp.shape
    mask = img2 = np.ones((width + 2, height + 2), np.uint8) * 255
    mask[1:width, 1:height] = 0

    # Generate intermediate image, draw largest contour, flood filled
    temp = np.zeros(temp.shape, np.uint8)
    temp = cv2.drawContours(temp, largestCnt, -1, 255, cv2.FILLED)
    _, temp, mask, _ = cv2.floodFill(temp, mask, (x, y), 255)
    temp = cv2.morphologyEx(temp, cv2.MORPH_OPEN, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)))

    area = cv2.countNonZero(temp) #Number of pixels encircled by blue line


    I input a different image with the axes and the frame that python adds by default removed for ease. I get what I expect at the second step, so this image. However, in the enter image description here both the original contour and the area it encircles appear to have been made white, whereas I want the original contour to be black and only the area it encircles to be white. How might I acheive this?

    Continue reading...

Compartilhe esta Página