Vídeo de Lectura y Procesamiento: Clase de CameraServer

Conceptos

La cámara usualmente usada en FRC® (cámaras de USB Y Ethernet de consumo como el Axis cámara) ofrece modos de operación relativamente limitados. En general, te dan solo una imagen de salida (normalmente en formato comprimido RGB como JPG) en una simple resolución y cuadros por segundo. Las cámaras USB son particularmente limitadas ya que solo una aplicación puede acceder a la cámara a la vez.

CameraServer soporta múltiples cámaras. Este cuenta con detalles como reconexión automática cuando la cámara se desconecta, también hace imágenes desde la disponibilidad de la cámara hacia múltiples “clientes” ( p.ej. El código del robot y su dashboard pueden conectarse simultáneamente).

Nombres de Cámaras

Cada cámara en CameraServer debe tener un nombre exclusivo. Este es también el nombre que aparece en el Dashboard. Algunas variantes del CameraServer startAutomaticCapture() y addAxisCamera() nombrarán a la cámara automáticamente ( p.ej. “USB Camera 0” o “Axis Camera”), o puede dar un nombre más descriptivo a la cámara ( p.ej. “Intake Camera” ). El único requisito es que la cámara tenga su propio nombre.

Notas de Cámara USB

Uso de CPU

La CameraServer está diseñada para minimizar el uso de CPU realizando solo comprensión y operaciones de descompresión cuando sea necesario y deshabilitar automáticamente la transmisión cuando no hay clientes conectados.

Para minimizar el uso de CPU, la resolución de las dashboard debe establecerse en la misma resolución que la cámara; esto permite que CameraServer no se descomprima y recomprimir la imagen, en lugar, simplemente puede reenviar la imagen JPEG recibida desde la cámara directamente al dashboard. Es importante notar que cambiando la resolución en el dashboard no hace cambio en la resolución de la cámara; cambiando la resolución de la cámara puede ser hecho llamando setResolution() en el objeto de la cámara.

Ancho de Banda de USB

La RoboRIO solo puede transmitir y recibir cierta información al mismo tiempo sobre las interfaces de la USB. Las imágenes de la cámara requiere mucha información, y en sí es relativamente fácil reproducir las imágenes en estos límites. El error más común en el ancho de banda de USB es seleccionar un modo de video non-JPEG o corriendo una resolución muy alta, particularmente cuando múltiples cámaras están conectadas.

Arquitectura

La CameraServer consiste en dos capas, el nivel alto WPILib CameraServer clase y el nivel bajo librería cscore.

Clase de CameraServer

La clase de CameraServer ( parte de WPILib ) provisiona un alto nivel de interface para añadir cámaras al código del robot. También es responsable por publicar información sobre las cámaras y los servidores de cámaras a las NetworkTables para que las dashboards de la Driver Station como la LabVIEW, Dashboard y Shuffleboard pueden enlistar las cámaras y determinar dónde está localizada la transmisión de estas. Esto usa un patrón único para mantener una base de datos de todos los servidores y cámaras creadas.

Algunas funciones clave en la CameraServer son:

  • startAutomaticCapture(): Agregue una cámara USB ( p.ej. Microsoft LifeCam ) e inicie un servidor para que pueda verse desde el dashboard.

  • addAxisCamera(): Agregue una cámara Axis. Aún cuando no esté procesando imágenes desde la cámara Axis al código del robot, usted querrá usar esta función para que aparezca la cámara Axis en la lista desplegable de cámaras del Dashboard. También inicia un servidor así que la transmisión de Axis pueda seguir siendo vista cuando el driver station está conectada a la RoboRIO via USB (es útil que en una competencia si tiene conectado la RoboRIO y una Cámara Axis a los dos puertos Ethernet del robot)

  • getVideo(): Obtenga acceso a OpenCV a la cámara. Esto le permite obtener las imágenes desde la cámara para el procesamiento de la imagen en la RoboRIO (en el código del robot).

  • putVideo(): Inicie un servidor al que pueda alimentar imágenes de OpenCV. Esto le permite pasar imágenes personalizadas procesadas y/o anotadas en el dashboard.

Librería cscore

La librería cscore provisiona el menor nivel de implementación para:

  • Obtener imágenes desde las cámaras USB y HTTP ( p.ej. Axis )

  • Cambiar la configuración de la cámara ( p.ej. contraste y brillo )

  • Cambiar los modos de vídeo de la cámara (formato del pixel, resolución y cuadros por segundo)

  • Actuar como un servidor web y servir imágenes como una transmisión MJPEG estándar

  • Convertir imágenes a/desde objetos Mat OpenCV para el procesamiento de la imagen

Fuentes y Receptores

La arquitectura básica de la Librería cscore a la de MJPGStreamer, con funcionalidad dividida entre fuentes y receptores. Puede haber múltiples fuentes y múltiples receptores creado y operando simultáneamente.

Un objeto que genera imágenes es una fuente y un objeto que acepta / consume imágenes es un receptor. El generar / consumir es desde la perspectiva de la biblioteca. Por lo tanto, las cámaras son fuentes (generan imágenes). El servidor web MJPEG es un receptor porque acepta imágenes de dentro del programa (aunque puede reenviar esas imágenes a un navegador web o dashboard). Las fuentes pueden estar conectadas a múltiples receptores, pero los receptores pueden conectarse a uno y solo una fuente. Cuando un receptor se conecta a una fuente, la biblioteca cscore se encarga de pasar cada imagen desde la fuente al sumidero.

  • Las fuentes obtienen marcos individuales (como los proporcionados por una cámara USB) y disparan un evento cuando hay un nuevo marco disponible. Si ningún receptor está escuchando una fuente en particular, la biblioteca puede pausar o desconectarse de una fuente para ahorrar procesadores y recursos de I / O. La biblioteca maneja de forma autónoma las desconexiones y reconexiones de la cámara simplemente pausando y reanudando la activación de eventos (por ejemplo, una desconexión no genera nuevos marcos, no hay un error).

  • Los receptores escuchan el evento de una fuente en particular, toman la última imagen y la reenvían a su destino en el formato apropiado. De manera similar a las fuentes, si un receptor particular está inactivo (por ejemplo, ningún cliente está conectado a un servidor MJPEG configurado a través de HTTP), la biblioteca puede deshabilitar partes de su procesamiento para ahorrar recursos del procesador.

El código de usuario (como el utilizado en un programa de robot FRC) puede actuar como fuente (proporcionando cuadros procesados ​​como si fuera una cámara) o como un receptor (que recibe un cuadro para su procesamiento) a través de la fuente de OpenCV y recibir objetos. Por lo tanto, una tubería de procesamiento de imágenes que obtiene imágenes de una cámara y sirve las imágenes procesadas se ve como el siguiente gráfico:

Block diagram showing that a program can either sink or source from OpenCV.

Debido a que las fuentes pueden tener múltiples receptores conectados, la tubería puede ramificarse. Por ejemplo, la imagen de la cámara original también se puede servir conectando la fuente USBCamera a un segundo receptor MjpegServer además del CvSink, lo que da como resultado el siguiente gráfico:

Block diagram of multiple sinks.

Cuando la cámara captura una nueva imagen, tanto el CvSink como el MjpegServer [1] la reciben.

El gráfico anterior es lo que crea el siguiente fragmento de CameraServer:

import edu.wpi.first.cameraserver.CameraServer;
import edu.wpi.cscore.CvSink;
import edu.wpi.cscore.CvSource;

// Creates UsbCamera and MjpegServer [1] and connects them
CameraServer.startAutomaticCapture();

// Creates the CvSink and connects it to the UsbCamera
CvSink cvSink = CameraServer.getVideo();

// Creates the CvSource and MjpegServer [2] and connects them
CvSource outputStream = CameraServer.putVideo("Blur", 640, 480);
#include "cameraserver/CameraServer.h"

// Creates UsbCamera and MjpegServer [1] and connects them
frc::CameraServer::StartAutomaticCapture();

// Creates the CvSink and connects it to the UsbCamera
cs::CvSink cvSink = frc::CameraServer::GetVideo();

// Creates the CvSource and MjpegServer [2] and connects them
cs::CvSource outputStream = frc::CameraServer::PutVideo("Blur", 640, 480);

La implementación de CameraServer efectivamente hace lo siguiente en el nivel del cscore (con fines explicativos). El CameraServer se encarga de muchos de los detalles, como la creación de nombres únicos para todos los objetos cscore y seleccionando automáticamente los números de puerto. CameraServer también mantiene un registro único de los objetos creados para que no se destruyan si salen del alcance.

import edu.wpi.cscore.CvSink;
import edu.wpi.cscore.CvSource;
import edu.wpi.cscore.MjpegServer;
import edu.wpi.cscore.UsbCamera;

// Creates UsbCamera and MjpegServer [1] and connects them
UsbCamera usbCamera = new UsbCamera("USB Camera 0", 0);
MjpegServer mjpegServer1 = new MjpegServer("serve_USB Camera 0", 1181);
mjpegServer1.setSource(usbCamera);

// Creates the CvSink and connects it to the UsbCamera
CvSink cvSink = new CvSink("opencv_USB Camera 0");
cvSink.setSource(usbCamera);

// Creates the CvSource and MjpegServer [2] and connects them
CvSource outputStream = new CvSource("Blur", PixelFormat.kMJPEG, 640, 480, 30);
MjpegServer mjpegServer2 = new MjpegServer("serve_Blur", 1182);
mjpegServer2.setSource(outputStream);
#include "cscore_oo.h"

// Creates UsbCamera and MjpegServer [1] and connects them
cs::UsbCamera usbCamera("USB Camera 0", 0);
cs::MjpegServer mjpegServer1("serve_USB Camera 0", 1181);
mjpegServer1.SetSource(usbCamera);

// Creates the CvSink and connects it to the UsbCamera
cs::CvSink cvSink("opencv_USB Camera 0");
cvSink.SetSource(usbCamera);

// Creates the CvSource and MjpegServer [2] and connects them
cs::CvSource outputStream("Blur", cs::PixelFormat::kMJPEG, 640, 480, 30);
cs::MjpegServer mjpegServer2("serve_Blur", 1182);
mjpegServer2.SetSource(outputStream);

Recuento de Referencias

Todos los objetos cscore se cuentan internamente como referencia. La conexión de un receptor a una fuente aumenta el recuento de referencias de la fuente, por lo que solo es estrictamente necesario mantener el receptor dentro del alcance. La clase CameraServer mantiene un registro de todos los objetos creados con las funciones de CameraServer, por lo que las fuentes y los receptores creados de esa manera nunca salen del alcance (a menos que explícitamente se remueva).