Search code examples
pythonopencvoptimizationconvex-hull

How to optimize convex hull drawing?


I'm trying to archive drawing convex hull points based on area of cover (see first image below) in some input image (second image below). For this operation, I'm doing the following:

  1. Find the contours in first image.
  2. Find the contours in second image.
  3. For every contours area in first image, compare with all contours in second image and check if they are inside of contour in first image. If it's inside of contour area, append x, y coordinates of contour to list.
  4. Draw convex hull points in list.

My problem is that step 3 is taking too much time, because of comparing every contour in the second image. Is there any way to optimize this code ?

for coverContour in coverContours:
    try:
        points_ = []
        for pointsContour in pointsContours:

            ((x, y), r) = cv2.minEnclosingCircle(pointsContour)

            if (cv2.pointPolygonTest(coverContour, (int(x), int(y)), False)) == 1:
                point_list.append((int(x), int(y)))
                points_.append(Point(int(x), int(y)))

        draw_point = Point.convex_hull(points_, len(points_))
        for x in range(len(draw_point)-1):
            cv2.line(layer, (points_[draw_point[x]].x, points_[draw_point[x]].y),
                     (points_[draw_point[x+1]].x, points_[draw_point[x+1]].y), (255, 255, 255), line_thickness)

        cv2.line(layer, (points_[draw_point[len(draw_point)-1]].x, points_[draw_point[len(draw_point)-1]].y),
                 (points_[draw_point[0]].x, points_[draw_point[0]].y), (255, 255, 255), line_thickness)
    except:
        print('')

Cover image:

Cover Image

Input image:

Input Image

Final image:

final image


Solution

  • I haven't tested your code, since it's missing parts to run it out-of-the-box, so I don't know, how to quantify taking too much time here. The below mentioned approach takes around 50 ms on my machine (i7 3.60 GHz, 32 GB RAM). If that's worthy, please continue reading. ;-)

    That'd be my final output:

    Output

    1. Find all the "blob" contours from the first image.
    2. Iterate the "blob" contours, and draw each on a separate black background, cf. cv2.drawContours.
    3. Bitwise and (intersect) this image with the "details" from the second image.
    4. Find all "details" contours within that intersection.
    5. Simply concatenate all coordinates from the "details" contours, and call cv2.convexHull.
    6. Draw the convex hull on some output image.

    That'd be the full code:

    import cv2
    import numpy as np
    
    # Read input images
    blobs = cv2.imread('6Sh0t.png', cv2.IMREAD_GRAYSCALE)
    details = cv2.imread('RdKkN.png', cv2.IMREAD_GRAYSCALE)
    
    # Find blob contours w.r.t. the OpenCV version
    cnt_blobs = cv2.findContours(blobs, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    cnt_blobs = cnt_blobs[0] if len(cnt_blobs) == 2 else cnt_blobs[1]
    
    # Prepare output image
    output = np.zeros_like(blobs)
    
    # Iterate all blob contours
    for cnt in cnt_blobs:
    
        # Draw blob contour on empty, black background
        tmp = np.zeros_like(blobs)
        tmp = cv2.drawContours(tmp, [cnt], -1, 255, cv2.FILLED)
    
        # Bitwise and (intersection) blob contour with details
        tmp = cv2.bitwise_and(tmp, details)
    
        # Find details contours within intersection w.r.t. the OpenCV version
        cnts = cv2.findContours(tmp, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
        cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    
        # Concatenate all coordinates, and get convex hull
        cnts = np.concatenate(cnts, axis=0)
        cnts = cv2.convexHull(cnts)
    
        # Draw in output
        output = cv2.drawContours(output, [cnts], -1, 128, 3)
    
    # Output
    cv2.imshow('Output', output)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    ----------------------------------------
    System information
    ----------------------------------------
    Platform:      Windows-10-10.0.16299-SP0
    Python:        3.8.5
    NumPy:         1.19.5
    OpenCV:        4.5.1
    ----------------------------------------