图像处理-填充空心圆

时间:2018-08-17 05:03:39

标签: python image-processing computer-vision scikit-image

我有一个像这样的二进制黑白图像

enter image description here

我想将那些白色圆圈填充为纯白色磁盘。如何在Python中做到这一点,最好使用skimage

3 个答案:

答案 0 :(得分:5)

您可以使用skimage的方法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() 检测圆,然后绘制圆以“填充”圆。

在下面的示例中,大多数代码针对最佳拟合圆执行“层次结构”计算,以避免绘制彼此内在的圆:

docker volume rm $(docker volume ls {{.ID}})

docker system prune

结果:

Detected circles

答案 1 :(得分:3)

做一个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

请注意分割垃圾如何融合到右下角的对象上,中间对象下部的小斗篷已关闭。在此之后,您可能要继续进行形态学侵蚀或开放。

编辑:对以下评论的回应很长

disk(4)只是我用来生成图像中所示结果的示例。您将需要自己找到一个合适的值。太大的值会导致小物体融合到靠近它们的大物体中,就像图像的右侧簇中那样。无论是否需要,它也将缩小对象之间的间隙。值太小将导致算法无法完成圆,因此填充操作将失败。

形态腐蚀会从物体的边界擦除一个结构元素大小的区域。形态学上的打开是闭合的逆运算,因此代替膨胀->腐蚀,它将腐蚀->膨胀。打开的最终效果是,所有小于结构元素的物体和斗篷都将消失。如果在填充后执行此操作,则大对象将保持相对不变。理想情况下,它应消除由于我在代码示例中使用的形态学关闭而导致的许多分段伪像,这些伪影可能取决于您的应用程序而与您无关。

答案 2 :(得分:1)

我不知道skimage,但是如果您使用OpenCv,我将对圆进行霍夫变换,然后将其绘制出来。

如果圆中有一些小孔没问题,则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/