ZMQ pub / sub для передачи изображений base64

Передо мной стоит задача: использовать сокет zmq для отправки и получения строки base64 (которая сгенерирована из изображений размером 800x600). В настоящее время я использую подключение pub / sub для выполнения этой задачи. Но похоже, что сообщение велико, так что сокет не может передать его немедленно, а более поздние сообщения застревают в сетевом буфере. Хотя я не хочу терять так много сообщений, я должен ограничить значение HWM, чтобы сокет работал правильно. Итак, у меня есть несколько вопросов:

  1. Есть ли еще одна эффективная библиотека / способ выполнить мою задачу? Или мне следует использовать другой тип подключения, который предоставляет zmq (маршрутизатор / дилер и запрос / ответ)?
  2. Чтобы передать изображение (которое обрабатывается OpenCV), есть ли подход, который я могу использовать для минимизации размера отправляемого изображения, кроме преобразования в формат base64?
  3. Если мне нужно продолжать использовать соединение zmq pub / sub, как я могу ограничить время для хранения старых сообщений, а не их количество, например, на 3 минуты?

Вот мой код на Python для сокета:

Издатель

import numpy as np
import zmq
import base64
context = zmq.Context()
footage_socket = context.socket(zmq.PUB)
footage_socket.setsockopt(zmq.SNDHWM, 1)
footage_socket.connect(<tcp address>)

def send_func(frame, camera_link):
   height, width, _ = frame.shape
   frame = np.ascontiguousarray(frame)
   base64_img = base64.b64encode(frame)
   data = {"camera_link":camera_link,'base64_img':base64_img, "img_width":width, "img_height":height}
   footage_socket.send_json(data)

Подписчик

footage_socket = context.socket(zmq.SUB)
footage_socket.bind(<tcp address>)
footage_socket.setsockopt(zmq.RCVHWM, 1)
def rcv_func(): 
    while True:
        print("run socket")
        try:
            framex = footage_socket.recv_string()
            data = json.loads(framex)
            frame = data['base64_img']
            img = np.frombuffer(base64.b64decode(frame), np.uint8)
            img = img.reshape(int(frame_height), int(frame_width), 3)

        except Exception as e:
            print(e)

person nOpe    schedule 22.12.2019    source источник
comment
Зачем нужен base64? Почему не просто байты? docs.scipy.org/doc/numpy/reference/ сгенерировано /   -  person Joe    schedule 22.12.2019
comment
Извините, но в последнее время мы пробовали только этот метод. Я попробую ваше предложение   -  person nOpe    schedule 23.12.2019
comment
Хорошо, дайте мне знать, как это происходит.   -  person Joe    schedule 23.12.2019
comment
Я не уверен, насколько важны для вас метаданные (высота, ширина и т. Д.). Вы также можете попробовать pickle массив numpy.   -  person Joe    schedule 23.12.2019
comment
Я видел, что если я использую функцию python sys.getsizeof() с массивом numpy, она возвращает значение меньше, чем со строкой base64. Но я не уверен, как размер сообщения влияет на скорость поля отправки и получения.   -  person nOpe    schedule 23.12.2019


Ответы (1)


Прежде чем мы начнем, позвольте мне сделать несколько заметок:

- избегайте повторной упаковки данных в JSON, если бы это было просто для простоты кодирования. Данные, повторно сериализованные в формате JSON, «растут» в размерах, не предоставляя вам ни единой дополнительной ценности для сверхбыстрой и энергоэффективной потоковой обработки. Профессиональные системы «прибегают» к JSON-формату только в том случае, если у них есть достаточно времени и почти неограниченные резервные вычислительные мощности ЦП, они тратят впустую на повторную упаковку ценных данных в еще один ящик данных. -внутри-другой-ящик-данных. Там, где это возможно, они могут оплатить все затраты и неэффективность - в этом случае вы не получите ничего взамен на потраченные тактовые частоты процессора, более чем вдвое увеличьте объем оперативной памяти, необходимый для повторной упаковки, а также необходимость передачи еще больших данных

- проверьте, действительно ли камера предоставляет данные изображения, которые «заслуживают» того, чтобы стать 8-байтовыми / 64-битными » deep ", а если нет, то у вас есть первое замечательное бесплатное сокращение изображений и данных

Использование sys.getsizeof() может вас удивить:

>>> aa = np.ones( 1000 )
>>> sys.getsizeof(  aa )
8096 <---------------------------- 8096 [B] object here "contains"
>>> (lambda array2TEST: array2TEST.itemsize * array2TEST.size )( aa )
8000 <---------------------------- 8000 [B] of data
>>> bb = aa.view()     # a similar effect happen in smart VECTORISED computing
>>> sys.getsizeof( bb )
96 <------------------------------   96 [B] object here "contains"
>>> (lambda array2TEST: array2TEST.itemsize * array2TEST.size )( bb )
8000 <---------------------------- 8000 [B] of data
>>> bb.flags
  C_CONTIGUOUS    : True
  F_CONTIGUOUS    : True
  OWNDATA         : False <-------------------------------||||||||||
  WRITEABLE       : True
  ALIGNED         : True
  WRITEBACKIFCOPY : False
  UPDATEIFCOPY    : False
  >>> bb.dtype
  dtype('float64') <--------------    8 [B] per image-pixel even for {1|0} B/W

В: есть подход, который я могу использовать для уменьшения размера отправляемого изображения ...?

Да, уже были потрачены миллионы [man * years] НИОКР, посвященных решению этой проблемы, и по-прежнему разрабатываются лучшие из классовых методов для ее решения.

Наилучшие результаты, как каждый, возможно, уже ожидал самостоятельно, необходимы в крайних случаях - для транспортировки спутниковых изображений издалека, далеко в глубоком космосе, обратно домой - например, когда JAXA была на втором месте миссия сближения с астероидом, на этот раз посещение астероида Рюгу.

Ваш код «как есть» создает кадры изображения 800x600 с пока неуказанными частотой кадров и глубиной цвета. Краткое представление показывает, сколько данных можно легко сгенерировать за указанные -3 минуты-, если к процессу не обращаться с большим вниманием и должным вниманием:

>>> (lambda a2T: a2T.itemsize * a2T.size )( np.ones( ( 800, 600, 3 ) ) ) / 1E6
11.52 <---- each 800x600-RGB-FRAME handled/processed this way takes ~ 11.5 [MB]
                    @~30 fps                                        ~345.6 [MB/s]
                                                                    ~ 62.2 [GB/3min]

Решение? Вдохновляйтесь ноу-хау The Best in the Class:

Здесь у вас есть ограниченная мощность (как с точки зрения энергии, так и с точки зрения обработки - не забывайте, что процессоры "внутри" этого спутника уже были произведены более 5-7 лет назад, прежде чем Запуск проекта - никто серьезный не посмеет отправить миссию с яркими и горячими новыми, но непроверенными чипами COTS), ограниченная оперативная память (опять же, ограничения мощности плюс веса, так как количество топлива необходимого для взлета и полета «туда» растет с каждым граммом «полезной нагрузки») и, наконец, что не менее важно - это самый ограничивающий фактор - у вас есть очень ограниченные средства R / F-COMM - такой "loooooooong" -wire (требуется почти полдня, чтобы получить первый бит от "туда" обратно "здесь" + то же самое, если вы попытаетесь ACK / NACK от "здесь", отвечая на любой удаленный запрос или запрос повторной отправки после обнаружения ошибки). Текущая эффективная скорость передачи данных телеметрии DSN составляет около 6,4 ~ 9,6 кбит / с (да, не более 7000 бит / с).

Здесь самые яркие умы вложили все искусство человеческого интеллекта, чтобы это произошло:

  • конечные средства сжатия изображений - никогда не отправляйте немного, если это действительно жизненно важно и необходимо
  • Добавлены окончательные средства перекодированных данных изображения самокоррекции ошибок - если что-то стоит добавить, обнаружения ошибок нет (вам придется подождать почти день, чтобы его снова "повторно передали", надеюсь, без другой ошибки). Здесь нам нужны средства (ограниченные - см. Затраты на отправку одного бита выше, так что это должно быть очень экономичное дополнение) самокоррекции, которая действительно может исправить некоторые ограниченные ошибки передачи сигналов / данных, которые могут появляться и появляются во время передачи сигнала R / F-COMM из дальнего космоса домой. В случае более крупных ошибок вам придется подождать несколько дней, чтобы перенастроить восстановление ошибок данных изображения, которое было решено другой попыткой отправить более крупный пакет, который не мог быть восстановлен из «поврежденных» данных с помощью возможностей, встроенных во встроенную систему. -в самокоррекции ошибок.

С чего начать?

Если в вашем сценарии использования нет значительного количества "запасной" доступной мощности ЦП (действительно необходимо, чтобы "бесплатно" ресурсы ЦП + ОЗУ для выполнения любого такого расширенного транскодирования данных изображения и повторной обработки с исправлением ошибок, как в масштабе (объем дополнительных данных для перекодирование и повторная обработка - обе имеют большие размеры - на порядки больше, чем размер одного кадра изображения) и за время (скорость дополнительной обработки ЦП) ) нет никакого волшебного трюка для максимального сжатия данных изображения, и на этом ваша история заканчивается.

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

  • python - это экосистема, которую легко создать прототипом, и если вам нужно увеличить пропускную способность (см. выше), это, скорее всего (более 30 лет опыта заставляет меня очень уверенно говорить это, даже если вы втянуть дополнительные стероиды, например, перейти на cython + C-extension для того, чтобы сделать весь цирк действительно немного, но только немного быстрее, с огромными дополнительными затратами на необходимость (приобретение нового навыка, если еще не на борту - имея дорогостоящую продолжительность обучения и рост заработной платы для тех, кто обладает высокой квалификацией) перепроектируйте и перефакторизуйте вашу до сих пор хорошо прототипированную кодовую базу) будет первым препятствием для продолжающегося шоу

  • OpenCV может и предоставит вам некоторые элементарные инструменты для работы с изображениями, с которых можно начать

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

  • ZeroMQ - наименее проблемная часть: она масштабируется как с точки зрения производительности, так и обладает уникальными возможностями пропускной способности с малой задержкой. Без каких-либо подробностей можно забыть о PUB/SUB, если только вы не будете предотвращать и избегать обработки списков подписок вообще (затраты на это могут вызвать огромные побочные эффекты для {central-node | сетевые потоки данных + все удаленные узлы} -перегрузки, не имеющие практического эффекта для предполагаемой быстрой обработки конвейерных данных изображения нужного размера.


В: Если мне нужно продолжать использовать соединение zmq pub / sub, как я могу ограничить время хранения старых сообщений, а не их количество, например, 3 минутами?

ZeroMQ - это умный инструмент, но нужно понимать его возможности - ZeroCopy поможет вам сохранить профиль с низким объемом оперативной памяти в производственной среде, но если вы планируете хранить -3 минуты потоковой передачи изображений , вам потребуются огромные объемы оперативной памяти и мощности процессора, и все это также сильно зависит от фактического количества равноправных узлов .recv().

ZeroMQ - это система без брокера, поэтому вы на самом деле не «храните» сообщения, но .send()-метод просто сообщает инфраструктуре ZeroMQ, что предоставленные данные могут быть отправлены бесплатно, когда инфраструктура ZeroMQ видит возможность отправьте их назначенному одноранговому получателю (будь то локально, через Атлантический океан или через спутниковую связь). Это означает, что правильная конфигурация ZeroMQ является обязательной, если вы планируете, чтобы передающая / принимающая сторона была готова поставить / передать / получить / исключить из очереди ~ 3 минуты даже самых сжатых данных изображения. поток (ы), потенциально обеспечивающий кратные этому потоку, в случае, если 1: многосторонняя связь появляется в производстве.

Правильный анализ и продуманные дизайнерские решения - единственный шанс для вашего проекта выдержать все эти требования, учитывая, что CPU, RAM и транспортные средства априори ограничены.

person user3666197    schedule 23.12.2019