Search code examples
pythonopencvimage-processingcomputer-vision

OpenCV contour width measurement at intervals


I wrote a OpenCV python script to identify the contour of an object in a microscope image.

Selected contour image example:

Selected contour image example

I need to meassure the width of the object at N intervals, where width is the distance between the right side to the left side of the contour in that interval, the line meassured is always horisontal.

this will later be repeated on about 30000 images.

Thsi is my latest attempt but it obviously not working

# Find contours in the inverse binary image
contours, _ = cv2.findContours(255 - binary_opened, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Choose the largest contour (assumes the blob is the largest connected component)
largest_contour = max(contours, key=cv2.contourArea)

# Divide the contour into 10 equal horizontal intervals
num_intervals = 10
interval_height = len(largest_contour) // num_intervals

# Create evenly spaced intervals along the y-axis
intervals_y = np.linspace(0, len(largest_contour), num_intervals + 1, dtype=int)

# Draw and display each interval on the original image
for i in range(num_intervals):
    start_idx = intervals_y[i]
    end_idx = intervals_y[i + 1]

    # Get points in the interval
    interval_points = largest_contour[start_idx:end_idx]

    # Draw the contour of the interval on the original image
    cv2.drawContours(image, [interval_points], -1, (0, 0, 255), 2)

I am new to openCV so any tip would be appreciated


Solution

  • I had a little attempt at this as follows:

    #!/usr/bin/env python3
    
    import cv2 as cv
    import numpy as np
    
    # Load image and extract width and height
    im = cv.imread('osjKP.jpg')
    h, w = im.shape[:2]
    
    # Convert to HSV to find all the green pixels
    HSV = cv.cvtColor(im, cv.COLOR_BGR2HSV)
    lo = np.array([50,200, 100])    # lower limit for green in HSV space
    hi = np.array([70,255, 255])    # upper limit for green in HSV space
    greens = cv.inRange(HSV, lo, hi)
    cv.imwrite('DEBUG-greens.png', greens)
    

    enter image description here

    # Floodfill with white from the centre
    _, result, _, _ = cv.floodFill(greens, None, (int(w/2), int(h/2)), 255)
    cv.imwrite('DEBUG-floodfilled.png', result)
    

    enter image description here

    # Count the non-zero pixels in each row, i.e. widths[0] is the width of the top row
    widths = np.count_nonzero(result, axis=1)
    print(widths)
    

    My assumption that it is safe to flood fill from the centre may not be correct for your other images (e.g. if the item you are measuring is narrow) so you may want to fill from the top-left and top-right corner and then invert, for example.


    If you only want the widths of every 20th row, change the last couple of lines to:

    # Count the non-zero pixels in each row
    N = 20
    widths = np.count_nonzero(result[::N,:], axis=1)
    print(widths)
    

    Output

    [ 918  902  907  899  896  904  911  894  912  913  897  884  912  916
      895  910  892  878  869  871  888  881  870  846  856  860  866  896
      876  873  878  880  881  889  892  898  900  917  931  954  966  976
      982  990  992 1030]