Быстрее передавать массив Numpy изображений в Python

#python #flask #image-processing #deep-learning #streaming

#python #flask #обработка изображений #глубокое обучение #потоковая передача

Вопрос:

В настоящее время я разработал простое веб-приложение с использованием фреймворка Flask. Основной язык, который я использую, — Python.

Я предполагаю, что у меня есть 2 основных файла, которые являются сервером Flask и клиентом Flask.

Сервер Flask инициализирует модель глубокого обучения (например, обнаружение объектов).

Клиент Flask будет извлекать кадры из источника камеры и отправлять их на сервер Flask, чтобы получить ограничивающие рамки объектов.

Мой вопрос здесь в том, слишком ли велики видеокадры (разрешение 4k). Для передачи кадров потребуется много времени. Время будет составлять 200 мс только для одного кадра.

Я хочу создать приложение реального времени на стороне клиента. Кто-нибудь знает хороший подход для передачи фреймов из этого приложения на Python в другое приложение на Python? Я считаю, что прогресс происходит только в локальной сети (на том же компьютере).

Ответ №1:

В Python 3.8 есть именно то, что вам нужно — разделяемая память. Вы можете создать блок общей памяти и получить к нему доступ из независимых процессов Python на том же компьютере. Я создал очень простой пример с одним кадром видео 4k UHD (3840×2160), разделяемым между двумя отдельными процессами Python. Итак, запустите этот ( shmemA.py ) в одном терминале, предпочтительно в IPython:

 #!/usr/bin/env python3

import numpy as np
from multiprocessing import shared_memory

# Define dimensions of 4k video
w, h = 3840, 2160

# Create a named SharedMemory object
shm = shared_memory.SharedMemory(create=True, name="SharedVideoBuffer", size=w*h*3)

# Create a Numpy array backed by that SharedMemory
im = np.ndarray((h,w,3), dtype=np.uint8, buffer=shm.buf)

# Fill that array such that the other process can see it
im[:] = 32
  

И после этого запускать это ( shmemB.py ) в отдельном терминале:

 #!/usr/bin/env python3

import numpy as np
from multiprocessing import shared_memory

# Define dimensions of 4k video
w, h = 3840, 2160

# Attach to existing SharedMemory created by our buddy
existing_shm = shared_memory.SharedMemory(name='SharedVideoBuffer')

# Create Numpy array backed by that SharedMemory
im = np.ndarray((h,w,3), dtype=np.uint8, buffer=existing_shm.buf)
  

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

 %timeit im[:]=56
776 µs ± 20.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
  

И вы можете видеть, что для передачи кадра 4K между процессами требуется 776 микросекунд, поэтому скорость передачи может превышать 1000 кадров в секунду.

В вашем сценарии вы могли бы рассмотреть возможность двойной буферизации (т. Е. пинг-понга) между двумя буферами, чтобы один процесс записывал второй, в то время как другой считывал первый. Таким образом, вы должны создать 2 буфера общей памяти (или один в два раза большего размера) и чередовать их. Вы могли бы использовать multiprocessing Queue между двумя процессами, чтобы сообщить читателю, какой буфер только что был заполнен.

Ключевые слова: Python, разделяемая память, SharedMemory, быстрый IPC, пинг-понг, двойная буферизация, быстрая передача изображений.

Комментарии:

1. Да, большое спасибо за ваше решение. Я обнаружил другой подход, который можно применить, — это файлы с отображением памяти в Python. Идея, лежащая в основе файла, отображаемого в память, очень проста. Во-первых, мы определяем виртуальный файл, устанавливаем одинаковый размер файла во фрейме. Процесс A (файл Python A) будет считывать кадры из источника видео и записывать в этот файл. Процесс B (другой файл B) перейдет к этому местоположению файла в памяти и считает байты. Весь процесс занимает более 20 миллисекунд. Я думаю, что ваше решение — самое быстрое из всех, что я видел. Это впечатляет — 1000 кадров в секунду для видео 4k.

2. Кстати, очередь многопроцессорной обработки похожа на очередь импорта из очереди? Я думаю, что эти очереди могут быть полезны, когда мы работаем с одним файлом? Если в отдельных файлах Python будут созданы 2 очереди, это будет рассматриваться как 2 разных объекта. Поправьте меня, если я ошибаюсь. Заранее благодарю вас. @Марк Сетчелл

3. Я думаю, вам пришлось бы запускать ваши 2 процесса из общего родительского для отправки многопроцессорной обработки. помещать сообщения в очередь между ними. Кто-нибудь, пожалуйста, напишите мне, если я ошибаюсь. Поэтому вы, вероятно, использовали бы сокет (или сообщение SYSV, zeromq или MQTT ) между ними для координации.