Более быстрая реализация картирования пикселей - PullRequest
1 голос
/ 02 апреля 2019

Этот метод очень медленный.Коротко и приятно, что он принимает словарь phase_color_labels, который отображает произвольное имя в список из 3 элементов, который соответствует значениям RGB, и он сопоставляет каждый пиксель входного изображения с любым значением пикселя, к которому оно ближе всего вphase_color_labels словарь.Я не выяснил, есть ли векторизованная версия этого, которая будет работать намного быстрее.

Переменная image - это просто массив numpy [H, W, Channels].

def map_pixels_to_discrete_values(image, phase_color_labels):
        """
        Takes an image with floating point pixel values and maps each pixel RGB value
        to a new value based on the closest Euclidean distance to one of the RGB sets
        in the phase_label input dictionary.
        """
        mapped_image = np.copy(image)
        for i in range(mapped_image.shape[0]):
            for j in range(mapped_image.shape[1]):
                min_distance = np.inf
                min_distance_label = None
                for phase_name, phase_color in phase_color_labels.items():
                    r = phase_color[0]
                    g = phase_color[1]
                    b = phase_color[2]
                    rgb_distance = (mapped_image[i, j, 0] - r)**2 + (mapped_image[i, j, 1] - g)**2 + (mapped_image[i, j, 2] - b)**2
                    if rgb_distance < min_distance:
                        min_distance = rgb_distance
                        min_distance_label = phase_name

                mapped_image[i, j, :] = phase_color_labels[min_distance_label]
        return mapped_image

1 Ответ

2 голосов
/ 02 апреля 2019

Чтобы быстро работать с Numpy, вы, как правило, хотите избегать циклов и вкладывать как можно больше работы в матричные операции Numpy.

Основная идея моего ответа:

  1. Получить цвета из phase_color_labels как ndarray, phase_colors.
  2. Использовать широковещание Numpy для вычисления «внешнего расстояния» - евклидова расстояния между каждым изображением в массивеи каждый цвет в phase_colors.
  3. Найдите индекс цвета с наименьшим расстоянием для каждого пикселя и используйте его в качестве индексов в phase_colors.
phase_colors = np.array([color for color in phase_color_labels.values()])

distances = np.sqrt(np.sum((image[:,:,np.newaxis,:] - phase_colors) ** 2, axis=3))
min_indices = distances.argmin(2)

mapped_image = phase_colors[min_indices]

Третья строка требует дополнительного объяснения.Во-первых, обратите внимание, что phase_names и phase_colors имеют форму (L, C), где L - количество меток, а C - количество каналов.

  • image[:,:,np.newaxis,:] вставокновая ось между второй и третьей осями, поэтому результирующий массив имеет форму (H, W, 1, C).
  • . При вычитании массива формы (L, C) из массива формы (H, W, 1, C), Numpy передает массивы в форму(H, W, L, C).Вы можете найти более подробную информацию о семантике вещания Numpy здесь .
  • Затем, взяв сумму вдоль оси 3, вы получите массив формы (H, W, L).
  • (Ни квадрат, ниПринятие эффекта квадратного корня в форме массива.)

В четвертой строке использование argmin на оси 2 затем уменьшает массив до формы (H, W), причем каждое значение является индексом изуменьшенная ось L - другими словами, индекс в phase_colors.


В качестве дополнительного улучшения, поскольку квадратный корень является монотонно возрастающей функцией, он не изменит, какое расстояние наименьшее, так что вы можете удалить его полностью.

Обратите внимание, что при больших image и phase_color_labels затраты на вещание могут быть значительными, что также может привести к проблемам с производительностью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...