代码之家  ›  专栏  ›  技术社区  ›  Baron Yugovich

图像处理-填充空心圆

  •  2
  • Baron Yugovich  · 技术社区  · 6 年前

    我有一个黑白图像

    enter image description here

    Python ,更喜欢使用 skimage ?

    3 回复  |  直到 6 年前
        1
  •  3
  •   Tapio    6 年前

    做一个 morphological closing (explanation) 填补这些微小的空白,完成这些循环。那么 fill 生成的二进制图像。

    代码:

    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')
    

    Figure depicting the different morphological operations

    请注意分段垃圾桶是如何与右下方的对象融合的,中间对象下方的小斗篷已关闭。你可能想在这之后继续进行形态侵蚀或开放。

    编辑:长时间回复以下评论

    磁盘(4)正是我用来生成图像中的结果的示例。你需要自己找到一个合适的价值观。如果值太大,则会导致小对象与它们附近的较大对象(如图像右侧的簇)融合。它还可以缩小对象之间的间隙,无论您是否需要。值太小将导致算法无法完成圆,因此填充操作将失败。

    形态侵蚀会从物体的边界上抹去一个结构元素大小的区域。形态打开是关闭的逆操作,因此不扩张->侵蚀,而是侵蚀->扩张。开放的净效应是所有小于结构元素的对象和资本都将消失。如果在填充后进行,则大对象将保持相对不变。理想情况下,它应该删除许多由我在代码示例中使用的形态学关闭导致的分段伪影,这些伪影可能与您的应用程序相关,也可能与您无关。

        2
  •  5
  •   Andriy Makukha    6 年前

    你可以用sklimage的方法检测出圆圈 hough_circle hough_circle_peaks 然后把它们拉过来“填满”它们。

    # 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()
    

    结果:

    Detected circles

        3
  •  1
  •   Rob Audenaerde    6 年前

    我不知道 skimage 但如果你愿意 OpenCv ,我会对圆做一个Hough变换,然后把它们画出来。

    Hough变换是鲁棒的,如果圆上有一些小孔,那就没有问题了。

    类似于:

    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)
    

    查看更多信息: https://www.pyimagesearch.com/2014/07/21/detecting-circles-images-using-opencv-hough-circles/