FAVORITAR
FecharPlease login

libcamera: A biblioteca de câmera multiplataforma

Com os recentes avanços em computação de borda, a necessidade por soluções de aquisição de imagem em sistemas embarcados só cresce. O processo, desde a leitura de dados de um sensor de câmera, até a transformação desses dados em uma imagem digital visível ao olho humano é trabalhoso e requer proficiência altamente especializada. Por conta disso, uma prática comum de mercado é a terceirização do processo de aquisição e pré-processamento de dados de imagem para o fabricante do hardware. Nesse contexto, os desenvolvedores de aplicação são responsáveis pela utilização de frameworks de câmera fornecidos para realizar o pós-processamento da imagem adquirida (foto visível) de acordo com a aplicação específica, como, por exemplo: identificação de faces, placas de carros, filtros estéticos, dentre outros.

O resultado disso é a existência de diversos frameworks de câmera que são atrelados aos hardwares para o qual foram desenvolvidos, diminuindo a adaptabilidade e portabilidade de soluções de câmera entre diferentes sensores de imagem e plataformas. O problema desse tipo de ecossistema é que um desenvolvedor pode ficar preso a um determinado conjunto de hardware por conta dos altos custos de desenvolvimento resultante da troca de componentes. Além disso, durante o ciclo de desenvolvimento de um novo produto, o simples processo de testar diferentes sensores de imagem para efeitos de prova de conceito pode ser trabalhoso, dadas as limitações de compatibilidade de determinadas plataformas.

Buscando aumentar o potencial de reutilização de código e diminuir algumas das dificuldades causadas pelo uso de ecossistemas proprietários de câmera, a libcamera é uma biblioteca de alto nível que faz interface com o Kernel Linux e fornece uma API genérica para acesso às funcionalidades de câmera de um sistema baseado em Linux.

Sobre a libcamera

libcamera
Figura 1: Logomarca oficial do libcamera, disponível em https://libcamera.org.

A libcamera atua como um framework de câmera de código livre para Linux, Android e ChromeOS. Ativamente em desenvolvimento pela comunidade de mídia do Linux, a sua proposta é fornecer uma API multiplataforma de aquisição de dados de câmera a partir de uma camada de abstração de hardware no espaço do usuário, baseada nas famílias de APIs Video4Linux 2 (V4L2) e Media Controller do Kernel. Apesar da natureza de código aberto, a licença da libcamera permite o vínculo de código proprietário por meio de objetos compartilhados, como forma de incentivar desenvolvedores de hardware a contribuir para a portabilidade do projeto em suas plataformas sem comprometer sua propriedade intelectual.

A leitura da documentação completa, disponível em: https://libcamera.org/docs.html e do código da biblioteca é recomendável, uma vez que aqui pretendemos passar apenas pelos conceitos básicos. A Figura 2 mostra uma visão de alto do nível da pilha de câmera proposta na libcamera. Nela, é possível identificar a ideia fundamental da biblioteca, de atuar como uma camada de abstração entre aplicação e o espaço de Kernel. A libcamera nesse contexto, fica responsável por organizar as informações e fornecer uma API, em teoria, agnóstica ao hardware.

Figura 2: Stack de Câmera utilizando a libcamera. Adaptado de https://libcamera.org.

A entidade de mais alto nível na libcamera é chamada de Camera Device, que representa, de forma simplificada, um dispositivo de fornecimento de imagem. Essa estrutura pode ser utilizada pela aplicação de alto nível para garantir o acesso a uma câmera conectada no sistema, configurar características como tipo do stream de dados, resolução de aquisição, dentre outras coisas, além de efetivamente iniciar a captura de imagem. Como ilustrado na Figura 3, do ponto de vista do código de aplicação, boa parte desse processo é independente do tipo de sensor de imagem conectado à plataforma. Para exemplificar essa ideia, o procedimento básico de aquisição de um sensor de imagem conectado a uma aplicação fundada na libcamera pode ser visto a seguir (C++).

Uma vez que o novo fornecedor de imagem é registrado na estrutura de câmera, na libcamera acontece um processo de vínculo entre os dispositivos identificados e o PipelineHandler (PH) e Image Processing Algorithm (IPA) disponíveis para eles, o que compõe a parte intrinsecamente dependente do hardware. Dessa forma é possível expor estruturas relativamente simples para o desenvolvedor de aplicação, enquanto as particularidades do hardware são tratadas pela biblioteca.

Para ilustrar melhor a ideia exposta acima, é interessante discutir sobre o PH e o IPA, por serem dois dos principais componentes da arquitetura interna da biblioteca, que pode ser vista na Figura 3.

Figura 3: Arquitetura interna da libcamera. Adaptado de https://libcamera.org.

Pipeline Handler

O PH é um componente da libcamera responsável por gerenciar as APIs do Linux (Media Controller e V4L2), abstraindo as complexidades de baixo nível e as especificidades (até certo ponto) de hardware do restante da biblioteca. Dessa forma, os demais subsistemas internos da libcamera e o usuário final podem utilizar a entidade Camera para alterar configurações de stream de imagem (resolução, frequência, etc) ou pipelines de qualidade de imagem (aumentar brilho, correção de branco, etc).

Mesmo que não tenha sido possível avaliar a funcionalidade de todos os PHs já disponíveis na libcamera nesse estudo, ao analisar seu código no repositório da Raspberry (https://github.com/raspberrypi/libcamera/tree/main/src/libcamera/pipeline), pudemos identificar alguns pipelines já escritos para alguns hardwares e protocolos de câmera. Dentre outros:

  • Imx8-isi – Escrito para suportar o ISI (Image Sensor Interface), uma interface para sensores de imagem conectados por meio do CSI (Camera Serial Interface) de processadores i.MX8 da NXP.
  • Rkisp1 – Escrito para suportar o Rockchip ISP1, uma interface da Rockchip usada em algum dos seus SoC (system-on-a-chip), como, por exemplo, o RK3288 para controle de câmera.
  • Rpi – Escrito para garantir suporte ao kit de desenvolvimento do Raspberry Pi e sua linha de sensores de imagem.
  • Uvcvideo – Escrito com o objetivo de garantir suporte ao driver de mesmo nome do Linux Kernel, usualmente utilizado para fazer interfaces com webcams conectadas por meio de USB.

Durante os testes este último funcionou, mesmo que as vezes de forma limitada, em uma variedade de dispositivos diferentes.

Image Processing Algorithms

Os algoritmos de processamento de imagem são um dos pontos fundamentais de toda pilha de software de câmera. A escolha de que algoritmos usar no pré-processamento dos dados do sensor de imagem tem um impacto significativo na foto final, exemplos clássicos desses algoritmos são os algoritmos de 3A (Auto-Exposure, Auto-White Balance, Auto-Focus), porém a técnica de debayer, dentre outros também são fundamentais.

Muitos dos algoritmos de processamento de imagem têm caráter fechado e confidencial, uma vez que os custos atrelados ao seu desenvolvimento e parametrização são altos. Posto isso, um dos pontos principais desse subsistema da libcamera é que desenvolvedores de hardware podem optar por adicionar esses algoritmos no código oficial do framework, o que atrela seu trabalho à licença da biblioteca, ou adicioná-los por meio de plugins, o que ajuda na manutenção da confidencialidade de informações proprietárias. Essa estratégia é um bom incentivo para que desenvolvedores de hardware adicionem suporte oficial à libcamera para os seus dispositivos.

Durante a escrita deste artigo, a compilação e utilização básica do libcamera no Ubuntu 20.04 – x86-64 foi trivial seguindo as instruções contidas em https://libcamera.org/getting-started.html, porém, dependendo do hardware alvo, pode haver complicações não observadas aqui. Um pedaço de código que vale a pena dar destaque é a aplicação de testes simple-cam fornecida pelos desenvolvedores do libcamera, disponível em: https://git.libcamera.org/libcamera/simple-cam.git. O repositório mostra um único arquivo, bem documentado que ensina o processo de aquisição de quadros utilizando a API nativa da libcamera de uma forma simples e intuitiva, do ponto de vista de desenvolvedores de aplicação. Considera-se a compilação e utilização dessa aplicação no ambiente citado acima como os primeiros exercícios ideais para estudar tanto o funcionamento quanto a aplicabilidade deste framework.

A implementação do suporte à libcamera pela Raspberry Pi, como uma alternativa ao hoje legado framework de câmera do Raspberry Pi OS, é um dos casos mais interessantes do uso da libcamera em sistemas embarcados e por isso será discutido a seguir.

Utilizando a libcamera no Raspberry Pi 4

Segundo artigo publicado no site da Pi Foundation em Maio de 2020 por David Plowman, a demanda da comunidade por uma solução de câmera de código aberto e as dificuldades intrínsecas do desenvolvimento de aplicações de câmera com suporte a múltiplos sensores de imagem foram motivadores importantes para a adoção da libcamera como pilha de câmera para a placa de desenvolvimento.

Hoje, além de suportar todos os módulos de câmera clássicos da Raspberry Pi (OV5647, IMX219, IMX477, IMX708), o libcamera também suporta alguns dos módulos de câmera de terceiros mais utilizados. A portabilidade da libcamera para a Raspberry Pi foi realizada por meio de várias contribuições da Pi Foundation ao repositório oficial da biblioteca. As mudanças vão desde a criação de um PH específico para suportar, além de outras coisas, o CSI da Raspberry Pi. Além disso, houve desde a adição de sistemas de controle avançados para os módulos de câmera mais sofisticados até adição de IPAs com tuning dedicados aos sensores da Raspberry, com arquivos editáveis de calibração de qualidade de imagem.

As imagens mais recentes do Raspberry Pi OS já contém o libcamera, porém, também é possível fazer a compilação da versão mais atualizada da biblioteca direto do repositório oficial. A Pi Foundation mantém um fork do libcamera, para propósitos de controle de versão, que pode ser encontrado em: https://github.com/raspberrypi/libcamera. Para fazer a compilação da biblioteca, é recomendável a leitura completa das instruções contidas no artigo de Camera Software, disponível no site oficial da fabricante (https://www.raspberrypi.com/documentation/computers/camera_software.html). O processo pode ser dividido em três etapas nas últimas versões do Raspberry Pi OS.

1. Instalação de dependências:

2. Clone do repositório e configuração de compilação:

3. Compilação e atualização dos pacotes.

4. Captura de uma imagem.

Para propósitos de testes, podemos usar tanto a aplicação nativa de teste do libcamera (cam) quanto o conjunto de aplicações nativas para fazer interface com a implementação do libcamera na Raspberry (rpicam-apps). Ambas as aplicações têm código aberto, disponíveis em https://github.com/raspberrypi/libcamera/tree/main/src/apps/cam e https://github.com/raspberrypi/rpicam-apps respectivamente. Utilizando o rpicam-apps, no terminal, podemos recorrer ao comando abaixo para fazer a aquisição de uma imagem:

libcamera
Figura 4: Exemplo de imagem adquirida na Raspberry Pi utilizando o sensor de imagem IMX219 conectado ao CSI (JPG).

Como é possível observar no exemplo, graças ao forte suporte da Pi Foundation ao projeto, a libcamera funciona como uma biblioteca muito bem estruturada e estável para aplicações de câmera na Raspberry, oferecendo suporte para diversos sensores de imagem e variações dos modelos da placa. Isso somado a possibilidade de acesso aos arquivos de calibração de qualidade de imagem e com os diversos recursos de aprendizado para diminuir atrito de adoção (código aberto, tanto da biblioteca, quanto das aplicações) tornam o framework em questão uma escolha óbvia na hora de trabalhar com câmera nessa plataforma. Dito isso, uma dúvida que surge é: Qual seriam as dificuldades para um terceiro portar a libcamera em um hardware sem suporte oficial? Esse exercício é importante para entender o nível de maturidade do projeto e a complexidade técnica para adotar essa solução com o objetivo de desenvolver uma aplicação de câmera multiplataforma.

Utilizando a libcamera no Jetson Nano Developer Kit

A linha Jetson da NVIDIA é uma das escolhas mais populares para trabalhar com computação visual de ponta nos últimos anos e, devido à alta disponibilidade deste hardware, neste artigo, a Jetson Nano foi utilizada para analisar a viabilidade da utilização do libcamera em uma plataforma sem suporte oficial. Levando isso em conta, a versão Nano da família de placas de desenvolvimento não foi uma boa escolha, dada a versão do kernel 4.9 desta plataforma, e visto que, segundo informações retiradas do fórum oficial da plataforma Jetson, a NVIDIA não tem planos para suportar o kernel 5.0, um requisito da libcamera, como veremos a seguir.

A primeira dificuldade foi encontrada logo na compilação da biblioteca. Utilizando a imagem oficial fornecida no site da NVIDIA Jetson, foram observadas incompatibilidades entre a versão do compilador gcc e os requisitos do sistema de compilação da libcamera. Para solucionar esse problema, a simples atualização do gcc provavelmente seria o suficiente, porém para evitar problemas de compatibilidade posteriores foi decidido fazer o upgrade da versão do Ubuntu disponibilizada pela NVIDIA. Um guia não oficial para esse processo pode ser encontrado em https://qengineering.eu/install-ubuntu-20.04-on-jetson-nano.html.

Uma vez que a biblioteca foi compilada com sucesso, o primeiro objetivo foi tentar verificar se era possível identificar o sensor conectado ao CSI da Jetson a partir da libcamera. Observamos que embora fosse possível identificá-lo usando o v4l2-ctl, pelo comando abaixo: 

Utilizando a API do libcamera, não era possível identificar qualquer sensor de imagem conectado. Aqui, vale entrar um pouco no sistema de câmera da Jetson Nano, mostrado de forma simplificada na Figura 5 abaixo.

libcamera
Figura 5: Pilha de Câmera da plataforma Jetson. Disponível em https://docs.nvidia.com/.

A imagem descreve uma pilha de software de câmera complexa que envolve drivers adicionais de caráter proprietário e, embora não confirmado, mostra uma evidência de uma possível incompatibilidade dos drivers e/ou compatibilidade do V4L2 com a implementação do libcamera na Jetson Nano. O sistema de câmera mostrado na Figura 5, ilustra a ideia já discutida acima que a terceirização do processo de aquisição de imagem para o desenvolvedor do hardware muitas vezes pode resultar em pilhas complexas e com pouca maleabilidade.

A segunda tentativa de realizar uma captura com a libcamera na Jetson Nano foi utilizar um PH mais genérico para acessar os dados de imagem. Como já tinha sido confirmado a funcionalidade do PH de UVC no dispositivo x86-64, foi realizada a tentativa de conectar uma câmera USB na Jetson. Ao fazer isso, utilizando a aplicação nativa cam, foi imediatamente possível identificar um sensor conectado à plataforma, utilizando a PH de UVC. Para isso foi utilizado o comando mostrado a seguir.

Ao tentar realizar a captura de imagem encontramos outra dificuldade. No código da libcamera, existem diferentes etapas de assert para garantir que o ambiente no qual a biblioteca está funcionando está de acordo com os requisitos mínimos preestabelecidos. Devido à versão customizada do Kernel 4.9 da Jetson Nano, foram encontradas algumas dependências de ecossistema que não eram cumpridas, sendo o exemplo mais notável a falta de suporte para a versão 4.9 do Kernel. A partir de análise individual de cada problema, e adição de soluções ou workarounds na camada de comunicação com o v4l2, foi possível realizar a captura conforme esperado. Para fazer a aquisição contínua de quadros de uma câmera conectada por USB, utilizando o PH de UVC por meio da aplicação nativa (cam), foi utilizado:

libcamera
Figura 6: Exemplo de imagem adquirida na Jetson Nano utilizando uma câmera conectada por USB por meio do protocolo UVC (MJPG).

Também foram feitas algumas tentativas de realizar o upstream da versão do kernel, adicionando as porções de código específica do hardware em questão, porém foram enfrentados problemas com alguns periféricos e então houve a decisão de parar os esforços nessa frente. Esse estudo mostrou que muito provavelmente seria necessário escrever um PH exclusivo para a plataforma ou adaptar um PH existente para que o libcamera funcionasse de acordo com as expectativas nesse hardware. De forma geral, a experiência com a Jetson Nano expôs que a utilização da libcamera em uma plataforma sem suporte oficial pode ser um processo desafiador, e dado que a quantidade de plataformas oficialmente suportadas é baixa, atualmente o framework ainda não tem uma maturidade necessária para a maior parte dos projetos comerciais.

Conclusões

O libcamera é uma ferramenta muito promissora para minimizar diversos problemas clássicos de portabilidade para sistemas de câmera, porém, ainda existe um suporte limitado para a maior parte dos hardwares de câmera comumente utilizados em aplicações comerciais. O principal objetivo desse artigo é divulgar a libcamera para comunidade brasileira na esperança de aumentar de número de colaboradores individuais dispostos a ajudar no desenvolvimento da biblioteca.

A partir dos testes realizados, foi identificado que o suporte dos desenvolvedores de hardware será muito importante para o processo de portabilidade do libcamera em diferentes plataformas. O estudo na jetson mostrou que a falta de suporte oficial resultaria em um atrito grande de adoção dessa plataforma caso o objetivo fosse sua efetiva utilização em uma aplicação real, e nesse caso, seria mais interessante a utilização da pilha nativa de câmera fornecida pela NVIDIA, mesmo levando em conta as desvantagens discutidas aqui.

Dito isso, a experiência de utilização da biblioteca na Raspberry Pi foi positiva, o que nos mostra o claro potencial deste framework na diminuição do retrabalho na portabilidade de sistemas que utilizam câmera. O suporte ao libcamera pode se tornar um ponto de venda interessante no futuro e, portanto, desenvolvedores de hardware tem incentivos para contribuir.

Referências

https://libcamera.org/index.html

https://www.raspberrypi.com/news/an-open-source-camera-stack-for-raspberry-pi-using-libcamera/

https://www.raspberrypi.com/documentation/computers/camera_software.html

https://docs.nvidia.com/jetson/archives/r35.4.1/DeveloperGuide/text/SD/CameraDevelopment/CameraSoftwareDevelopmentSolution.html

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.
Home » Software » libcamera: A biblioteca de câmera multiplataforma

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS