К содержимому
  1. Главная
  2. Документация
  3. USB-камеры UVC
  4. Доступ к камерам UVC через OpenCV, Python и GStreamer

Доступ к камерам UVC через OpenCV, Python и GStreamer

Документация Arducam · перевод arducam-russia.ru

Камеры Arducam UVC работают по стандарту UVC, поэтому драйверы не нужны и камеры сразу работают с приложениями для веб-камер. Но опытным пользователям для задач машинного зрения и ИИ может понадобиться собственный код на Python и OpenCV с расширенным управлением камерой. Ниже подробно описано, как открыть камеру Arducam UVC и управлять ею.

Windows

1. Захват видео с веб-камеры UVC в Windows через Media Foundation

1.1. Скачайте SimpleCapture.exe

Скачайте архив SimpleCapture-exe.zip с сайта CodeProject.

1.2. Распакуйте архив и запустите SimpleCapture.exe

Окно программы SimpleCapture

Выберите File → Choose device → USB → OK.

Выбор USB-камеры в SimpleCapture

Выберите один из вариантов в списке, как на рисунке, и нажмите OK.

Список форматов камеры в SimpleCapture

1.3. Захват видео

Захват видео с камеры UVC в SimpleCapture

2. Доступ к веб-камере UVC через OpenCV

Примеры кода есть на Stack Overflow и GeeksforGeeks.

ПримечаниеИспользуйте версию, показанную на рисунке ниже, и обновлённую версию OpenCV: со старыми версиями OpenCV камера может работать неправильно.
Версии Python и OpenCV

2.1. Как установить Python и OpenCV

python3 -m pip 安装 opencv-python

В команде из исходной документации вместо install ошибочно стоит «安装»; правильная команда — python3 -m pip install opencv-python.

2.2. Код на Python

import cv2
'''
apiPreference    preferred Capture API backends to use. 
Can be used to enforce a specific reader implementation 
if multiple are available: 
e.g. cv2.CAP_MSMF or cv2.CAP_DSHOW.
'''
# open video0
cap = cv2.VideoCapture(0, cv2.CAP_MSMF)
# set width and height
# cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
# cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
# set fps
# cap.set(cv2.CAP_PROP_FPS, 30)
while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()
    # Display the resulting frame
    cv2.imshow('frame', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

3. Доступ к нескольким веб-камерам UVC

3.1. Измените имя устройства и серийный номер

В отличие от Linux, в Windows при работе с несколькими камерами UVC их различают по имени устройства. Как изменить серийный номер камеры Arducam UVC, читайте в этом документе.

ПримечаниеУ разных камер UVC должны быть разные имена устройств и серийные номера.

После изменения:

Камеры UVC с разными именами устройств (1)
Камеры UVC с разными именами устройств (2)

3.2. Код на Python

from pymf import get_MF_devices
device_list = get_MF_devices()
for i, device_name in enumerate(device_list):
    print(f"opencv_index: {i}, device_name: {device_name}")
ПримечаниеНе устанавливайте pymf через pip: пакет pymf в pip — другой, не тот, что скачивается отдельно.

4. Устранение неполадок

4.1. Проверьте работу камеры

Прежде чем открывать камеру через OpenCV, проверьте, что она работает, в программе с графическим интерфейсом.

Способ 1 — проверьте камеру по инструкции.

Способ 2 — проверьте камеру с помощью файла .exe: где его скачать и как с ним работать, описано в этом разделе.

4.2. Не удаётся открыть камеру

Ошибка открытия камеры в OpenCV

Если у вас та же ошибка, сделайте следующее:

  1. Смените API (cv2.CAP_MSMF или cv2.CAP_DSHOW).
  2. Задайте более высокую частоту кадров.

4.3. Частота кадров не задаётся и слишком низкая

Низкая частота кадров с бэкендом cv2.CAP_DSHOW

С бэкендом cv2.CAP_DSHOW частота кадров может не задаваться и оставаться очень низкой. В этом случае используйте бэкенд cv2.CAP_MSMF.

Linux

1. Видеоузел, поддерживаемые разрешения и частота кадров

Перед тем как открыть камеру UVC, определите нужный видеоузел.

ls /dev/video*
Список видеоузлов /dev/video*

Обычно у камер с кодированием H.264 два или четыре видеоузла:

  • если узлов два, video0 выдаёт YUV, MJPEG и т. д., а video1 — H.264;
  • если узлов четыре, video0 выдаёт YUV, MJPEG и т. д., а video2 — H.264.

Посмотреть поддерживаемые форматы можно командой:

v4l2-ctl --list-formats -d 0 # 0 is video0

Ниже — пример для камеры UVC с четырьмя видеоузлами.

Форматы видеоузла камеры UVC (1)
Форматы видеоузла камеры UVC (2)

При необходимости проверьте разрешения и частоту кадров для каждого формата командой:

v4l2-ctl --list-formats-ext -d 0 # 0 is video0
Разрешения и частота кадров форматов камеры (1)
Разрешения и частота кадров форматов камеры (2)

2. Доступ к камере и управление через OpenCV

Откройте камеру через OpenCV на Python (OpenCV устанавливается через pip: pip install OpenCV-python).

import cv2

# open video0
cap = cv2.VideoCapture(0)

# The control range can be viewed through v4l2-ctl -L
cap.set(cv2.CAP_PROP_BRIGHTNESS, 64)
cap.set(cv2.CAP_PROP_CONTRAST, 0)

while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()
    # Display the resulting frame
    cv2.imshow('frame', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

Пример вывода v4l2-ctl -L.

Вывод команды v4l2-ctl -L с параметрами камеры

Ручная фокусировка камеры с автофокусом через OpenCV

Включить ручную фокусировку на камере с автофокусом можно двумя способами:

1. Значения задаются в коде

import cv2
import time
# open video0
cap = cv2.VideoCapture(0)
cap.grab()

cap.set(cv2.CAP_PROP_AUTOFOCUS, 1)
time.sleep(2)
cap.set(cv2.CAP_PROP_AUTOFOCUS, 0)
time.sleep(2)
cap.set(cv2.CAP_PROP_FOCUS, 123)


cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()
    # Display the resulting frame
    cv2.imshow('frame', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

2. Значения задаются через графический интерфейс

import cv2
import argparse
import configparser
from pathlib import Path
import time


parser = argparse.ArgumentParser()
parser.add_argument("-v", "--vid", default="0", help="Video sourse, default 0")
parser.add_argument(
    "-f", "--auto_focus", action="store_true", default=False, help="Turn on auto focus"
)
parser.add_argument(
    "-c",
    "--config",
    default="focus.ini",
    help="Focus config file, default focus.ini",
)
args = parser.parse_args()

try:
    vid = int(args.vid)
except ValueError:
    vid = args.vid

config_path = (Path(__file__).parent / Path(args.config)).resolve().absolute()
print("config file :", config_path)

config = configparser.ConfigParser()

config.read(config_path, encoding="utf-8")

cap = cv2.VideoCapture(vid)
cap.grab()
cap.set(cv2.CAP_PROP_AUTOFOCUS, 1)

if not args.auto_focus and config.has_section("Focus"):
    auto_focus = (
        config.getint("Focus", "auto_focus")
        if config.has_option("Focus", "auto_focus")
        else 1
    )
    focus = (
        config.getint("Focus", "focus")
        if config.has_option("Focus", "focus")
        else int(cap.get(cv2.CAP_PROP_FOCUS))
    )
else:
    auto_focus = 1
    focus = None
print("config auto_focus = %s" % auto_focus)
print("config focus = %s" % focus)
print("*" * 10)


if not auto_focus:
    cap.set(cv2.CAP_PROP_AUTOFOCUS, 0)

time.sleep(2)
if focus:
    cap.set(cv2.CAP_PROP_FOCUS, focus)

cv2.namedWindow("frame")


def set_auto_focus(x):
    cap.set(cv2.CAP_PROP_AUTOFOCUS, x)


cv2.createTrackbar(
    "0: OFF\r\n 1: ON\r\nauto_focus",
    "frame",
    int(cap.get(cv2.CAP_PROP_AUTOFOCUS)),
    1,
    set_auto_focus,
)


def set_focus(x):
    cap.set(cv2.CAP_PROP_FOCUS, x)


cv2.createTrackbar("focus", "frame", int(cap.get(cv2.CAP_PROP_FOCUS)), 1023, set_focus)

while cap.isOpened():
    # cap frame-by-frame
    ret, frame = cap.read()
    if not ret:
        break
    focus = int(cap.get(cv2.CAP_PROP_FOCUS))
    cv2.setTrackbarPos("focus", "frame", focus)

    af = int(cap.get(cv2.CAP_PROP_AUTOFOCUS))
    cv2.setTrackbarPos("0: OFF\r\n 1: ON\r\nauto_focus", "frame", af)

    cv2.imshow("frame", frame)

    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

# When everything done, release the cap
cap.release()
cv2.destroyAllWindows()

if not config.has_section("Focus"):
    config.add_section("Focus")

print("set auto_focus = 0")
config.set("Focus", "auto_focus", "0")

print("set focus = %s" % focus)
config.set("Focus", "focus", str(focus))

config.write(open(config_path, "w"))

3. Доступ к нескольким камерам UVC

Иногда нужно подключить несколько камер UVC одновременно, но их трудно различить. У каждой камеры Arducam UVC есть собственный серийный номер, не повторяющийся у других камер; по нему её можно распознать и управлять ею отдельно. Ниже — два способа узнать серийный номер.

3.1. Через видеоузел

sudo udevadm info --query=all /dev/video0 | grep 'VENDOR_ID\|MODEL_ID\|SERIAL_SHORT'
Серийный номер камеры в выводе udevadm

3.2. Через Python

Установите зависимости:

sudo pip3 install pyudev

Код:

import pyudev
def getSerialNumber(device = 0):
    context = pyudev.Context()
    device_file = "/dev/video{}".format(device)
    device = pyudev.Devices.from_device_file(context, device_file)
    info = { item[0] : item[1] for item in device.items()}
    return info["ID_SERIAL_SHORT"]
Серийный номер камеры, полученный через pyudev
ПримечаниеЕсли нужен другой серийный номер, напишите нам на quote@arducam-russia.ru.

4. Трансляция видео через GStreamer

GStreamer — популярный открытый мультимедийный фреймворк. Его высокоуровневые API позволяют строить собственные приложения для трансляции, воспроизведения и монтажа видео с разными кодеками и функциями.

ПримечаниеПодробнее о форматах видеоузлов — в разделе «Видеоузел, поддерживаемые разрешения и частота кадров».

4.1. Формат видео

Камера выдаёт видео в трёх форматах.

MJPEG (формат вывода video0):

gst-launch-1.0 v4l2src device=/dev/video0 ! \
    image/jpeg,width=1280,height=720,framerate=30/1 ! \
    decodebin ! autovideosink

YUV (формат вывода video0):

gst-launch-1.0 -vv v4l2src device=/dev/video0 ! \
    video/x-raw,format=YUY2,width=1280,height=720,framerate=10/1 ! \
    videoconvert ! autovideosink

H.264 (формат вывода video2):

gst-launch-1.0 v4l2src device=/dev/video2 ! queue ! \
    video/x-h264,width=1280,height=720,framerate=30/1 ! \
    avdec_h264 ! autovideosink

4.2. Трансляция

В отличие от сжатых форматов MJPEG и H.264, YUV даёт большой объём данных и для трансляции не подходит.

MJPEG:

# server
gst-launch-1.0 v4l2src device=/dev/video0 ! \
    image/jpeg,width=1280,height=720,framerate=30/1 ! \
    tcpserversink host=0.0.0.0 port=5001
# client 
# change xxx.xxx.xxx.xxx to the actual ip address
gst-launch-1.0 -v tcpclientsrc host=xxx.xxx.xxx.xxx port=5001 ! \
    decodebin ! autovideosink

H.264:

# server
gst-launch-1.0 v4l2src device=/dev/video2 ! queue ! \
    video/x-h264,width=1280,height=720,framerate=30/1 ! \
    rtph264pay ! gdppay  ! tcpserversink host=0.0.0.0 port=5001
# client
# change xxx.xxx.xxx.xxx to the actual ip address
gst-launch-1.0 -v tcpclientsrc host=xxx.xxx.xxx.xxx port=5001 ! \
    gdpdepay ! rtph264depay ! avdec_h264 ! autovideosink

4.3. Работа с камерой

Запись видео:

gst-launch-1.0 v4l2src device=/dev/video0 ! image/jpeg,width=1280,height=720,framerate=30/1 ! jpegdec ! x264enc ! qtmux ! filesink location=test.mp4 -e

Сохранение снимка:

gst-launch-1.0 v4l2src device=/dev/video0 num-buffers=1 ! jpegenc ! filesink sync=false location=file.jpg

Просмотр:

gst-launch-1.0 v4l2src device=/dev/video0 ! image/jpeg,width=1280,height=720,framerate=30/1 ! jpegdec ! autovideosink

Запросить цену

Укажите количество — пришлём коммерческое предложение.