2015-03-26 3 views
2

Я работал над использованием v4l2, чтобы захватить изображение камеры в OpenCV. Это работает очень хорошо; таким образом я могу захватить изображение в формате YUYV и с высоким разрешением (понимая, что частота кадров снизится). Я не мог сделать это с помощью реализации OpenCV. Функционально он отлично работает, но производительность может быть намного лучше. Поскольку это мой первый раз, используя v4l2 напрямую, это все еще немного расплывчато для меня. Я определял все соответствующие части и видел, что метод выбора v4l2 занимает чуть больше секунды. Когда я опускаю интервал времени, метод select занимает меньше времени, но деэккетинг занимает гораздо больше времени (а также второй). В других функциях камера инициализируется, поэтому устанавливаем правильный формат и т. Д. Я понимаю, что частота кадров будет низкой, без сжатия и высокого разрешения, но это слишком мало.Захват изображения камеры с v4l2 очень медленно

Ниже приведена функция захвата изображения. Я пропустил код, в котором буфер преобразуется в Mat (YUYV -> RGB), потому что я думаю, что сейчас это не актуально.

Кто-нибудь знает, как сделать захват изображений v4l2 намного быстрее? Может быть, есть части, которые я не должен выполнять каждый захват кадра?

Спасибо!

Mat Camera::capture_image() { 
Mat returnframe(10, 10, CV_8UC3); 
struct v4l2_buffer buf = {0}; 
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
buf.memory = V4L2_MEMORY_MMAP; 
buf.index = 0; 
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) { 
    perror("Query Buffer"); 
    return returnframe; 
} 

if (-1 == xioctl(fd, VIDIOC_STREAMON, &buf.type)) { 
    perror("Start Capture"); 
    return returnframe; 
} 

fd_set fds; 
FD_ZERO(&fds); 
FD_SET(fd, &fds); 
struct timeval tv = {0}; 
tv.tv_sec = 2; 
int r = select(fd + 1, &fds, NULL, NULL, &tv); 
if (-1 == r) { 
    perror("Waiting for Frame"); 
    return returnframe; 
} 

if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) { 
    perror("Retrieving Frame"); 
    return returnframe; 
} 

// здесь код для преобразования Mat

if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &buf.type)) { 
    perror("Stop Capture"); 
    return returnframe; 
} 

//copy Mat and free bigbuffer, to avoid memory leak 
Mat returnImg = dispimg.clone(); 
free(bigbuffer); 
return returnImg; 
} 
+0

вы * начиная захвата * для каждого кадра? это похоже на много подслушивает –

ответ

1

, кажется, что для каждого кадра вы вызываете VIDIOC_STREAMON и VIDIOC_STREAMOFF; это добавляет много накладных расходов (это почти как самопроизвольный пуск приложения для каждого кадра)

правильный путь будет:

  • открытое устройство (вызывается только один раз): в начале ваш захват-сессии (например, запуск программы), настройки вашего видео-устройства, чтобы начать потоковое по телефону VIDIOC_STREAMON

  • захвата кадров (вызывается несколько раз): для каждого кадра вы хотите, чтобы захватить, запросить кадр, только вызывать g DQBUF/QBUF (это довольно быстро, так как устройство будет непрерывно поток данных в очередь буфера); вам все равно нужно позвонить select, чтобы узнать, когда доступен новый кадр.

  • близко устройство (вызывается только один раз): как только вы закончите, остановите потоковое по телефону VIDIOC_STREAMOFF

+0

Спасибо за ваш ответ! Значит, я больше не использую функцию выбора? И вы имеете в виду, что мне нужно выбирать между DQBUF и QBUF, или вы имеете в виду, что я должен использовать оба варианта? – Rogier

+1

нет, вы все равно используете 'select' (знать, когда кадр готов), а' DQBUF' (* буфер детекции *) и 'QBUF' (* буфер очереди *) принадлежат вместе (вы используете * both *); Дело в том, что вы не должны называть 'STREAMON' в функции * capture frame *, но в функции * open device *. –

+0

Хорошо здорово. Это имеет большое значение! Означает ли порядок? Спасибо огромное! – Rogier