Я пишу код на питоне, чтобы открыть 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
@jamieguinan Я проверяю этот и обновляю вопрос. Есть два формата: сырой и сжатый. Вопрос можно ли открыть камеру в сжатом режиме?
Это определенно возможно на уровне кода C — у меня есть Logitech C310, который может читать кадры mjpeg со скоростью 1280x720 при 25 кадрах в секунду на RPi2. Но я не знаю, как/если ваша библиотека Python предоставляет доступ для установки формата фрейма. Какую библиотеку вы используете для import uvc
? Пробовали ли вы пропустить шаг ProcessJPG() и сделать что-то вроде print(dir(img))
? Возможно, код выполняет избыточную распаковку -> сжатие.
Я использую привязку 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']
В исходнике вижу github.com/pupil-labs/pyuvc/blob/master/uvc.pyx#L530UVC_FRAME_FORMAT_COMPRESSED
полный список github.com/pupil-labs/pyuvc/blob/…
Когда я сохраняю необработанный массив, он имеет ~ 2,5 МБ.
Я не могу отделаться от мысли, что t.start()
, за которым сразу следует t.join()
, совершенно бесполезна. Он запускает другой поток, а затем явно ничего не делает сам, ожидая его завершения, поэтому он вообще не вводит никакого параллелизма. Идея потоков заключается в том, что вы запускаете несколько потоков параллельно.
Это возможно, и вам не нужно более мощное оборудование.
Из пювк 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, вам, вероятно, придется вставить таблицы Хаффмана
Ok. Итак, когда я хочу отобразить jpeg_buffer, я должен преобразовать его в массив ant reshape?
Зависит от того, где и как вы это показываете. Если вы отправляете кадры через http, вы можете отправлять данные jbeg_buffer как есть, в потоках mjpeg обычно отсутствуют таблицы Хаффмана. Что будет на принимающей стороне, если позволите, я спрошу? Больше кода Python?
Когда я передаю frame.jpeg_buffer в браузер, он не отображается. Я пытаюсь преобразовать буфер jpeg в (720, 1280, 3), но получаю cannot reshape array of size 125576 into shape (720,1280,3)
. Например, как сохранить jpeg_buffer
как один файл? Или если я транслирую frame.jpeg_buffer
, как клиент может это отображать?
Главный вопрос, как легко сделать mjpeg2rgb
?
Я не думаю, что JPEG можно изменить. Для BGR (достаточно близкого к RGB) вы можете просто получить доступ к свойству .bgr
и не сжимать его повторно. Если вы обслуживаете через http, вам нужно добавить некоторые заголовки и multipart/x-mixed-replace
прочее. Пример, которые вы могли бы адаптировать.
Спасибо. Я проверяю это. Да, frame.img
возвращает yuv
изображение, и этот формат имеет 3D-массив формы (720, 1280, 3). Так что лучший вариант — обслуживать jpge_buffer
по сети, потому что он самый легкий?
Определенно. Это будет ~ 125 КБ / кадр вместо ~ 1,3 МБ / кадр. stackoverflow предлагает перенести это в чат, не стесняйтесь продолжать там.
Можете ли вы перечислить форматы, которые может захватывать камера? Возможно, вы сможете настроить его для возврата кадров, закодированных в формате Jpeg.