Оптимизация производительности сшивания изображений в реальном времени Python OpenCV (n = 5) - PullRequest
0 голосов
/ 10 января 2019

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

Я придерживаюсь подхода этого репозитория github :

Начиная с центрального изображения, вы сначала сшиваете влево, а затем сшиваете оставшиеся изображения вправо.

Код этого репозитория работает, но мучительно медленно. Мне удалось значительно улучшить его производительность (фактор 300), но все равно требуется 0,25 секунды, чтобы сшить панораму из пяти изображений (на Macbook Pro 2015 года).

Медленная часть: применение каждого результата cv2.warpPerspective(...) к изображениям, сшитым до этой точки. В настоящее время я делаю это, используя альфа-канал и смешивая два изображения, вдохновленные этим SO ответом . Именно это смешивание замедляет сшивание.

(псевдо) код:

def blend_transparent(background, foreground):
    overlay_img = foreground[:, :, :3]  # Grab the BRG planes 
    overlay_mask = foreground[:, :, 3:]  # And the alpha plane

    # Again calculate the inverse mask
    background_mask = 255 - overlay_mask

    # Turn the masks into three channel, so we can use them as weights
    overlay_mask = cv2.cvtColor(overlay_mask, cv2.COLOR_GRAY2BGR)
    background_mask = cv2.cvtColor(background_mask, cv2.COLOR_GRAY2BGR)

    # Create a masked out background image, and masked out overlay
    # We convert the images to floating point in range 0.0 - 1.0
    background_part = (background * (1 / 255.0)) * (background_mask * (1 / 255.0))
    overlay_part = (overlay_img * (1 / 255.0)) * (overlay_mask * (1 / 255.0))

    # And finally just add them together, and rescale it back to an 8bit integer image
    return np.uint8(
        cv2.addWeighted(background_part, 255.0, overlay_part, 255.0, 0.0)
    )


for image in right_images:
    warped_image = cv2.warpPerspective(image, ...)
    mask = np.zeros(
        (warped_image.shape[0], warped_image.shape[1], 4), 
        dtype="uint8"
    )
    mask[0 : previously_stitched.shape[0], 0 : previously_stitched.shape[1]] = previously_stitched
    mask_rgb = mask[:, :, :3]  # Grab the BRG planes
    previously_stitched = blend_transparent(mask_rgb, warped_image)

Итак, мой вопрос : есть ли способ более эффективно применить деформированное изображение к существующей панораме?

Мой полный рабочий код находится в этом хранилище .

Отказ от ответственности: я веб-разработчик, и мои знания в области компьютерного зрения очень ограничены.

1 Ответ

0 голосов
/ 10 января 2019

Альфа-канал полезен, когда ваше изображение имеет прозрачность, но здесь вы вручную добавляете альфа-канал путем преобразования. Этот канал можно использовать для хранения вычислений, но я думаю, что вы потеряете производительность. Я предлагаю следующую функцию для blend_transparent:

def blend_transparent(self, background, foreground):
    # Split out the transparency mask from the colour info
    overlay_img = foreground[:, :, :3]  # Grab the BRG planes

    res = background

    only_right = np.nonzero((np.sum(overlay_img, 2) != 0) * (np.sum(background,2) == 0))
    left_and_right = np.nonzero((np.sum(overlay_img, 2) != 0) * (np.sum(background,2) != 0))

    res[only_right] = overlay_img[only_right]
    res[left_and_right] = res[left_and_right]*0.5 + overlay_img[left_and_right]*0.5
    return res

Здесь вы устанавливаете в результате значение правого пикселя изображения, если в данный момент значение не установлено. Если значение уже установлено, то вы вычисляете среднее значение слева и справа. Время вычислений делится на коэффициент 1,6.

Поскольку ваша проекция заморожена, нет необходимости каждый раз вычислять индексы only_right и left_and_right, мы можем вычислить их один раз и сохранить их. Сделайте это, и вы должны разделить время вычислений в 4 раза.

...