Image processing - fill in hollow circles

前端 未结 3 1050
你的背包
你的背包 2021-01-22 04:03

I have a binary black and white images that looks like this

I want to fill in those white circles to be solid white disks. How can I do this in Python

相关标签:
3条回答
  • 2021-01-22 04:29

    Do a morphological closing (explanation) to fill those tiny gaps, to complete the circles. Then fill the resulting binary image.

    Code :

    from skimage import io
    from skimage.morphology import binary_closing, disk
    import scipy.ndimage as nd
    import matplotlib.pyplot as plt
    
    # Read image, binarize
    I = io.imread("FillHoles.png")
    bwI =I[:,:,1] > 0
    
    fig=plt.figure(figsize=(24, 8))
    
    # Original image
    fig.add_subplot(1,3,1)
    plt.imshow(bwI, cmap='gray')
    
    # Dilate -> Erode. You might not want to use a disk in this case,
    # more asymmetric structuring elements might work better
    strel = disk(4)
    I_closed = binary_closing(bwI, strel)
    
    # Closed image
    fig.add_subplot(1,3,2)
    plt.imshow(I_closed, cmap='gray')
    
    I_closed_filled = nd.morphology.binary_fill_holes(I_closed)
    
    # Filled image
    fig.add_subplot(1,3,3)
    plt.imshow(I_closed_filled, cmap='gray')
    

    Result :

    Note how the segmentation trash has melded to your object on the lower right and the small cape on the lower part of the middle object has been closed. You might want to continue with an morphological erosion or opening after this.

    EDIT: Long response to comments below

    The disk(4) was just the example I used to produce the results seen in the image. You will need to find a suitable value yourself. Too big of a value will lead to small objects being melded into bigger objects near them, like on the right side cluster in the image. It will also close gaps between objects, whether you want it or not. Too small of a value will lead to the algorithm failing to complete the circles, so the filling operation will then fail.

    Morphological erosion will erase a structuring element sized zone from the borders of the objects. Morphological opening is the inverse operation of closing, so instead of dilate->erode it will do erode->dilate. The net effect of opening is that all objects and capes smaller than the structuring element will vanish. If you do it after filling then the large objects will stay relatively the same. Ideally it should remove a lot of the segmentation artifacts caused by the morphological closing I used in the code example, which might or might not be pertinent to you based on your application.

    0 讨论(0)
  • 2021-01-22 04:40

    You can detect circles with skimage's methods hough_circle and hough_circle_peaks and then draw over them to "fill" them.

    In the following example most of the code is doing "hierarchy" computation for the best fitting circles to avoid drawing circles which are one inside another:

    # skimage version 0.14.0
    
    import math
    import numpy as np
    import matplotlib.pyplot as plt
    
    from skimage import color
    from skimage.io import imread
    from skimage.transform import hough_circle, hough_circle_peaks
    from skimage.feature import canny
    from skimage.draw import circle
    from skimage.util import img_as_ubyte
    
    INPUT_IMAGE = 'circles.png' # input image name
    BEST_COUNT = 6              # how many circles to draw
    MIN_RADIUS = 20             # min radius should be bigger than noise
    MAX_RADIUS = 60             # max radius of circles to be detected (in pixels)
    LARGER_THRESH = 1.2         # circle is considered significantly larger than another one if its radius is at least so much bigger
    OVERLAP_THRESH = 0.1        # circles are considered overlapping if this part of the smaller circle is overlapping
    
    def circle_overlap_percent(centers_distance, radius1, radius2):
        '''
        Calculating the percentage area overlap between circles
        See Gist for comments:
            https://gist.github.com/amakukha/5019bfd4694304d85c617df0ca123854
        '''
        R, r = max(radius1, radius2), min(radius1, radius2)
        if centers_distance >= R + r:
            return 0.0
        elif R >= centers_distance + r:
            return 1.0
        R2, r2 = R**2, r**2
        x1 = (centers_distance**2 - R2 + r2 )/(2*centers_distance)
        x2 = abs(centers_distance - x1)
        y = math.sqrt(R2 - x1**2)
        a1 = R2 * math.atan2(y, x1) - x1*y
        if x1 <= centers_distance:
            a2 = r2 * math.atan2(y, x2) - x2*y
        else:
            a2 = math.pi * r2 - a2
        overlap_area = a1 + a2
        return overlap_area / (math.pi * r2)
    
    def circle_overlap(c1, c2):
        d = math.sqrt((c1[0]-c2[0])**2 + (c1[1]-c2[1])**2)
        return circle_overlap_percent(d, c1[2], c2[2])
    
    def inner_circle(cs, c, thresh):
        '''Is circle `c` is "inside" one of the `cs` circles?'''
        for dc in cs:
            # if new circle is larger than existing -> it's not inside
            if c[2] > dc[2]*LARGER_THRESH: continue
            # if new circle is smaller than existing one...
            if circle_overlap(dc, c)>thresh:
                # ...and there is a significant overlap -> it's inner circle
                return True
        return False
    
    # Load picture and detect edges
    image = imread(INPUT_IMAGE, 1)
    image = img_as_ubyte(image)
    edges = canny(image, sigma=3, low_threshold=10, high_threshold=50)
    
    # Detect circles of specific radii
    hough_radii = np.arange(MIN_RADIUS, MAX_RADIUS, 2)
    hough_res = hough_circle(edges, hough_radii)
    
    # Select the most prominent circles (in order from best to worst)
    accums, cx, cy, radii = hough_circle_peaks(hough_res, hough_radii)
    
    # Determine BEST_COUNT circles to be drawn
    drawn_circles = []
    for crcl in zip(cy, cx, radii):
        # Do not draw circles if they are mostly inside better fitting ones
        if not inner_circle(drawn_circles, crcl, OVERLAP_THRESH):
            # A good circle found: exclude smaller circles it covers
            i = 0
            while i<len(drawn_circles):
                if circle_overlap(crcl, drawn_circles[i]) > OVERLAP_THRESH:
                    t = drawn_circles.pop(i)
                else:
                    i += 1
            # Remember the new circle
            drawn_circles.append(crcl)
        # Stop after have found more circles than needed
        if len(drawn_circles)>BEST_COUNT:
            break
    
    drawn_circles = drawn_circles[:BEST_COUNT]
    
    # Actually draw circles
    colors  = [(250, 0, 0), (0, 250, 0), (0, 0, 250)]
    colors += [(200, 200, 0), (0, 200, 200), (200, 0, 200)]
    fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(10, 4))
    image = color.gray2rgb(image)
    for center_y, center_x, radius in drawn_circles:
        circy, circx = circle(center_y, center_x, radius, image.shape)
        color = colors.pop(0)
        image[circy, circx] = color
        colors.append(color)
    
    ax.imshow(image, cmap=plt.cm.gray)
    plt.show()
    

    Result:

    0 讨论(0)
  • 2021-01-22 04:43

    I don't know skimage but if you'd use OpenCv, I would do a Hough transform for circles, and then just draw them over.

    Hough Transform is robust, if there are some small holes in the circles that is no problem.

    Something like:

    circles = cv2.HoughCircles(gray, cv2.cv.CV_HOUGH_GRADIENT, 1.2, 100)
    
    # ensure at least some circles were found
    if circles is not None:
        # convert the (x, y) coordinates and radius of the circles to integers
        circles = np.round(circles[0, :]).astype("int")
    
        # loop over the (x, y) coordinates and radius of the circles
        # you can check size etc here.
        for (x, y, r) in circles:
            # draw the circle in the output image
            # you can fill here.
            cv2.circle(output, (x, y), r, (0, 255, 0), 4)
    
        # show the output image
        cv2.imshow("output", np.hstack([image, output]))
        cv2.waitKey(0)
    

    See more info here: https://www.pyimagesearch.com/2014/07/21/detecting-circles-images-using-opencv-hough-circles/

    0 讨论(0)
提交回复
热议问题