猿问

找到像素区域质心的更快方法

对于一个游戏,我制作了一个由像素组成的区域地图,每个区域都有不同的颜色。从那里,我想在每个地区添加名字。


出于视觉目的,我想将名称放在该区域的质心上。因此,我使用 PIL 将图像转换为单个大矩阵。我建立了一个类来记录每个区域的质心数据,并收集在字典中。然后,我遍历像素来处理质心。这种方法非常慢,对于 2400 x 1100 的地图大约需要一分钟。


territory_map = numpy.array([

    [0, 0, 0, 1, 0, 0, 0],

    [0, 2, 2, 1, 0, 0, 0],

    [2, 2, 1, 1, 3, 3, 3],

    [2, 0, 0, 1, 3, 0, 0],

])


centroid_data = {}


class CentroidRecord(object):

    def __init__(self, x, y):

        super(CentroidRecord, self).__init__()

        self.x = float(x)

        self.y = float(y)

        self.volume = 1


    def add_mass(self, x, y):

        #           new_x = (old_x * old_volume + x) / (old_volume + 1),

        # therefore new_x = old_x + (x - old_x) / v,

        # for v = volume + 1.

        self.volume += 1

        self.x += (x - self.x) / self.volume

        self.y += (y - self.y) / self.volume



for y in range(territory_map.shape[0]):

    for x in range(territory_map.shape[1]):

        cell = territory_map[y][x]

        if cell == 0:

            continue

        if cell not in centroid_data:

            centroid_data[cell] = CentroidRecord(x, y)

        else:

            centroid_data[cell].add_mass(x, y)


for area in centroid_data:

    data = centroid_data[area]

    print(f"{area}: ({data.x}, {data.y})")

这应该打印以下内容:


1: (2.8, 1.6)

2: (0.8, 1.8)

3: (4.75, 2.25)

有没有更快的方法来做到这一点?


小唯快跑啊
浏览 230回答 1
1回答

噜噜哒

一种颜色的质心的每个坐标只是该颜色的所有点坐标的平均值。因此,我们可以使用一个dict推导:import numpy as npn_colours = territory_map.max(){i: tuple(c.mean() for c in np.where(territory_map.T == i))  for i in range(1, n_colours + 1)}输出:{1: (2.8, 1.6),  2: (0.8, 1.8),  3: (4.75, 2.25)}请注意,我们需要进行转置,因为行(y 坐标)在列(x 坐标)之前numpy。随机生成的数据所花费的时间:81.6 ms ± 5.36 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
随时随地看视频慕课网APP

相关分类

Python
我要回答