Raspberry Pi 3 увеличивает FPS с помощью USB-камеры 720p

Я пишу код на питоне, чтобы открыть USB-камеру и захватить с нее кадр. Я использую свой код для http-потока. Для кодирования JPEG я использую библиотеку libturbojpeg. Для этого я использую 64-битную ОС.

product: Raspberry Pi 3 Model B Rev 1.2
serial: 00000000f9307746
width: 64 bits
capabilities: smp cp15_barrier setend swp

Делаю тесты с разными разрешениями.

Resolution   FPS   Time for encode
640 x 480     ~35       ~0.01
1280 x 720    ~17       ~0.028

И это мой код

import time
import os
import re
import uvc
from turbojpeg import TurboJPEG, TJPF_GRAY, TJSAMP_GRAY
jpeg = TurboJPEG("/opt/libjpeg-turbo/lib64/libturbojpeg.so")
camera = None

import numpy as np
from threading import Thread

class ProcessJPG(Thread):

    def __init__(self, data):
        self.jpeg_data = None
        self.data = data
        super(ProcessJPG, self).__init__()

    def run(self):
        self.jpeg_data = jpeg.encode((self.data))

    def get_frame(self):
        self.frame = camera.get_frame()

global camera
dev_list = uvc.device_list()
print("devices: ", dev_list)
camera = uvc.Capture(dev_list[1]['uid'])
camera.frame_size = camera.frame_sizes[2] // set 1280 x 720
camera.frame_rate = camera.frame_rates[0] // set 30 fps

class GetFrame(Thread):
    def __init__(self):
        self.frame = None
        super(GetFrame, self).__init__()
    def run(self):
        self.frame = camera.get_frame()

_fps = -1
count_to_fps = 0
_real_fps = 0
from time import time
_real_fps = ""
cfps_time = time()

while True:
    if camera:
        t = GetFrame()
        t.start()
        t.join()
        img = t.frame
        timestamp = img.timestamp
        img = img.img
        ret = 1
    t_start = time()
    t = ProcessJPG(img)
    t.start()
    t.join()
    jpg = t.jpeg_data
    t_end = time()
    print(t_end - t_start)
    count_to_fps += 1
    if count_to_fps >= _fps:
        t_to_fps = time() - cfps_time
        _real_fps = 1.0 / t_to_fps
        cfps_time = time()
        count_to_fps = 0
    print("FPS, ", _real_fps)

Строка кодировки: jpeg.encode((self.data))

У меня вопрос, это разрешение есть возможность увеличить фпс для 1280х720 (например, 30 кадров в секунду) или я должен использовать более мощное устройство? Когда я смотрю на htop, во время вычислений процессор не используется на 100%.

Обновлено: Форматы камеры:

[video4linux2,v4l2 @ 0xa705c0] Raw       :     yuyv422 :           YUYV 4:2:2 : 640x480 1280x720 960x544 800x448 640x360 424x240 352x288 320x240 800x600 176x144 160x120 1280x800
[video4linux2,v4l2 @ 0xa705c0] Compressed:       mjpeg :          Motion-JPEG : 640x480 1280x720 960x544 800x448 640x360 800x600 416x240 352x288 176x144 320x240 160x120

Raspberry Pi 3 увеличивает FPS с помощью USB-камеры 720p

Можете ли вы перечислить форматы, которые может захватывать камера? Возможно, вы сможете настроить его для возврата кадров, закодированных в формате Jpeg.

jamieguinan 23.04.2019 00:11

@jamieguinan Я проверяю этот и обновляю вопрос. Есть два формата: сырой и сжатый. Вопрос можно ли открыть камеру в сжатом режиме?

lukassz 23.04.2019 16:20

Это определенно возможно на уровне кода C — у меня есть Logitech C310, который может читать кадры mjpeg со скоростью 1280x720 при 25 кадрах в секунду на RPi2. Но я не знаю, как/если ваша библиотека Python предоставляет доступ для установки формата фрейма. Какую библиотеку вы используете для import uvc? Пробовали ли вы пропустить шаг ProcessJPG() и сделать что-то вроде print(dir(img))? Возможно, код выполняет избыточную распаковку -> сжатие.

jamieguinan 23.04.2019 17:34

Я использую привязку python для библиотеки libuvc, она называется pyuvc. Output of dir ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__pyx_vtable__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', 'avaible_modes', 'bandwidth_factor', 'close', 'controls', 'frame_mode', 'frame_rate', 'frame_rates', 'frame_size', 'frame_sizes', 'get_frame', 'get_frame_robust', 'name', 'stop_stream']

lukassz 24.04.2019 09:29

В исходнике вижу github.com/pupil-labs/pyuvc/blob/master/uvc.pyx#L530UVC_FRAME_FORMAT_COMPRESSED полный список github.com/pupil-labs/pyuvc/blob/…

lukassz 24.04.2019 09:51

Когда я сохраняю необработанный массив, он имеет ~ 2,5 МБ.

lukassz 24.04.2019 09:56

Я не могу отделаться от мысли, что t.start(), за которым сразу следует t.join(), совершенно бесполезна. Он запускает другой поток, а затем явно ничего не делает сам, ожидая его завершения, поэтому он вообще не вводит никакого параллелизма. Идея потоков заключается в том, что вы запускаете несколько потоков параллельно.

Mark Setchell 24.04.2019 21:51
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
7
989
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это возможно, и вам не нужно более мощное оборудование.

Из пювк README.md,

* Capture instance will always grab mjpeg conpressed frames from cameras.

Когда ваш код обращается к свойству .img, это вызывает jpeg2yuv (см. здесь и здесь). потом вы перекодируете с помощью jpeg_encode(). Попробуйте использовать frame.jpeg_buffer после захват и не трогать .img вообще.

Я взглянул на pyuvc на RPi2 с Логитек C310 и сделал упрощенный пример,

import uvc
import time

def main():
    dev_list = uvc.device_list()
    cap = uvc.Capture(dev_list[0]["uid"])
    cap.frame_mode = (1280, 720, 30)
    tlast = time.time()
    for x in range(100):
        frame = cap.get_frame_robust()
        jpeg = frame.jpeg_buffer
        print("%s (%d bytes)" % (type(jpeg), len(jpeg)))
        #img = frame.img
        tnow = time.time()
        print("%.3f" % (tnow - tlast))
        tlast = tnow
    cap = None

main()

Я получаю ~ 0,033 с на кадр, что составляет ~ 30 кадров в секунду при ~ 8% ЦП. Если я раскомментирую строку #img = frame.img, она увеличится до ~ 0,054 с / кадр или ~ 18 кадров в секунду при 99% ЦП (время декодирования ограничивает скорость захвата).

Где бы вы ни закончили декодирование кадров jpeg, вам, вероятно, придется вставить таблицы Хаффмана

jamieguinan 24.04.2019 20:53

Ok. Итак, когда я хочу отобразить jpeg_buffer, я должен преобразовать его в массив ant reshape?

lukassz 24.04.2019 22:18

Зависит от того, где и как вы это показываете. Если вы отправляете кадры через http, вы можете отправлять данные jbeg_buffer как есть, в потоках mjpeg обычно отсутствуют таблицы Хаффмана. Что будет на принимающей стороне, если позволите, я спрошу? Больше кода Python?

jamieguinan 24.04.2019 23:10

Когда я передаю frame.jpeg_buffer в браузер, он не отображается. Я пытаюсь преобразовать буфер jpeg в (720, 1280, 3), но получаю cannot reshape array of size 125576 into shape (720,1280,3). Например, как сохранить jpeg_buffer как один файл? Или если я транслирую frame.jpeg_buffer, как клиент может это отображать?

lukassz 24.04.2019 23:32

Главный вопрос, как легко сделать mjpeg2rgb?

lukassz 24.04.2019 23:49

Я не думаю, что JPEG можно изменить. Для BGR (достаточно близкого к RGB) вы можете просто получить доступ к свойству .bgr и не сжимать его повторно. Если вы обслуживаете через http, вам нужно добавить некоторые заголовки и multipart/x-mixed-replace прочее. Пример, которые вы могли бы адаптировать.

jamieguinan 25.04.2019 02:25

Спасибо. Я проверяю это. Да, frame.img возвращает yuv изображение, и этот формат имеет 3D-массив формы (720, 1280, 3). Так что лучший вариант — обслуживать jpge_buffer по сети, потому что он самый легкий?

lukassz 25.04.2019 08:55

Определенно. Это будет ~ 125 КБ / кадр вместо ~ 1,3 МБ / кадр. stackoverflow предлагает перенести это в чат, не стесняйтесь продолжать там.

jamieguinan 25.04.2019 15:34

Другие вопросы по теме