我们需要计算面积Voronoi图,而不是计算点Voronoi图。点Voronoi图不是一个可行的选择,因为涉及的图形形状相当复杂。
面积Voronoi图是一个合适的选项,并且可以通过点Voronoi图算法的适应版本来近似。
近似包括三个步骤。它不是从对象的中心坐标计算Voronoi图,而是使用每个对象轮廓上的点。除了期望的效果之外,这还将导致源自位于对象的相同轮廓上的点的对象的不必要的分割,其必须被校正。
1.计算图形轮廓上的点集
1.计算这些点的点Voronoi图
1.删除从同一图形上的点生成的Voronoi边
而1.和2.我们想知道如何才能确定哪些边是由同一图形上的点生成的,而不需要编写我们自己的Voronoi图实现?
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import Voronoi, voronoi_plot_2d
from skimage.filters import threshold_otsu
from skimage.measure import find_contours
def create_sample_img():
object_selectors = []
object_selectors.append((slice(50, 70), slice(100, 120)))
object_selectors.append((slice(30, 80), slice(20, 60)))
object_selectors.append((slice(10, 35), slice(80, 105)))
object_selectors.append((slice(10, 90), slice(140, 190)))
image = np.zeros((100,200))
for selector in object_selectors:
image[selector] = 1
return image
def imshow_contours(image, contours, ax):
ax.imshow(image, alpha=0.75)
for contour in contours:
ax.plot(contour[:, 1], contour[:, 0], linewidth=2)
return ax
def area_voronoi(binary_image, ):
downsampling = 3
contour_index_mask = [] # to be used to see from which contour a point originates form
contour_coordinates = []
contours_grouped = find_contours(binary_image, 0)
for contour_index, contours in enumerate(contours_grouped):
contour_coordinates.extend(contours[::downsampling])
contour_index_mask.extend([contour_index, ]*len(contours[::downsampling]))
contour_coordinates = [[coord[1], coord[0]] for coord in contour_coordinates]
vor = Voronoi(contour_coordinates)
# TODO remove edges that originate from the same contours
fig, ax = plt.subplots()
imshow_contours(image, contours_grouped, ax)
voronoi_plot_2d(vor, ax=ax)
plt.show()
image = create_sample_img()
binary_image = image > threshold_otsu(image)
area_voronoi(binary_image)
字符串
1条答案
按热度按时间qjp7pelc1#
请注意,在计算点的Voronoi图时,您应该了解每条边分隔哪两个点的信息。
接下来,您应该计算从中提取点的原始图像的标记(连通分量分析)。现在,对于每条边,您可以查找它将哪两个点分开,并且在标记的图像中,您可以看到这些点中的每一个属于哪个连通分量。如果连接的组件相等,则删除边。
从连接的零部件图像中,还可以立即导出每个连接零部件的面积。这为下一步提供了足够的信息,下一步将对两点之间的距离和两个连接组件的面积比应用特定阈值,以决定是保留还是删除边。
scipy.spatial.Voronoi
对象有一个属性vor.ridge_points
(一个NumPy数组),它告诉你哪两个点被边分开。因此,您可以在输入图像中查找这两个点的坐标,从而查找每个点所属的连通分量。还有一个属性
vor.ridge_vertices
(一个列表),稍后您需要知道如何绘制边缘。这个列表和上面的数组需要保持同步,当你删除一条边时,你必须删除ridge_points
数组中的行,以及ridge_vertices
列表中的相应元素。虽然删除代价很高,但也许可以保留一个逻辑数组,指示保留哪些边,丢弃哪些边?