milkv-duo
riscv64-linux-musl
✅ HW JPG decoder
✅ MIPI CSI camera
Tradução e testes (Duo 256)
Opencv-mobile é uma versão leve da biblioteca OpenCV que minimiza a compilação do OpenCV ajustando os parâmetros de compilação e removendo certas partes do código-fonte do OpenCV.
O opencv-mobile fornece funcionalidades comumente usadas do OpenCV, como processamento de imagem, operações de matriz e muito mais. Ele permanece sincronizado com a versão upstream e não tem dependências de terceiros. Na maioria dos casos, ele pode substituir perfeitamente o OpenCV oficial com apenas 1/10 do tamanho, tornando-o particularmente adequado para ambientes móveis e incorporados com requisitos de tamanho específicos.
Comparação de tamanhos de pacotes de código-fonte:
Link do projeto: https://github.com/nihui/opencv-mobile | Obrigado a nihui
!
dica
O opencv-mobile já suporta decodificação JPG acelerada por hardware e aceleração de hardware VPSS (Video Processing Subsystem) no Milk-V Duo/Duo256M/DuoS.
1. Passos rápidos
Baixe Opencv eCrie um novo diretóriotório
unzip opencv-mobile-4.10.0-milkv-duo.zip
cd opencv-mobile-4.10.0-milkv-duo/host-tools.tar.gz
Crie um novo diretório picture-resize
e digite:
mkdir picture-resizecd picture-resizeunzip ../opencv-mobile-4.10.0-milkv-duo.zip
wget https://sophon-file.sophon.cn/sophon-prod-s3/drive/23/03/07/16/host-tools.tar.gz
unzip host-tools.tar.gz
tar -xf host-tools.tar.gz
Criar código fonte
Crie um novo arquivo chamado main.cpp
:
vi/nano main.cpp
Adicione o seguinte:
#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>
int main(){ cv::Mat bgr = cv::imread("in.jpg", 1);
cv::resize(bgr, bgr, cv::Size(200, 200));
cv::imwrite("out.jpg", bgr);
return 0;}
Sua função é dimensionar uma imagem nomeada in.jpg
para um tamanho 200x200
e então gerá-la como um arquivo out.jpg
.
Crie CMakeLists.txt
Para compilar usando cmake, você precisa criar um arquivo CMakeLists.txt:
vi/nano CMakeLists.txt
O conteúdo é o seguinte:
project(opencv-mobile-test) cmake_minimum_required(VERSION 3.5) set(CMAKE_CXX_STANDARD 11) set(CMAKE_C_COMPILER "${CMAKE_CURRENT_SOURCE_DIR}/host-tools/gcc/riscv64-linux-musl-x86_64/bin/riscv64-unknown-linux-musl-gcc") set(CMAKE_CXX_COMPILER "${CMAKE_CURRENT_SOURCE_DIR}/host-tools/gcc/riscv64-linux-musl-x86_64/bin/riscv64-unknown-linux-musl-g++") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -mcpu=c906fdv -march=rv64imafdcv0p7xthead -mcmodel=medany -mabi=lp64d") set(OpenCV_DIR "${CMAKE_CURRENT_SOURCE_DIR}/opencv-mobile-4.10.0-milkv-duo/lib/cmake/opencv4") find_package(OpenCV REQUIRED) add_executable(opencv-mobile-test main.cpp) target_link_libraries(opencv-mobile-test ${OpenCV_LIBS})
Há três variáveis que precisam ser observadas e configuradas de acordo com seu próprio caminho de arquivo:
- OpenCV_DIR : O diretório correspondente ao pacote pré-compilado previamente extraído para o diretório atual. Preste atenção ao número da versão no caminho.
- CMAKE_C_COMPILER : O caminho para o gcc na cadeia de ferramentas de compilação cruzada.
- CMAKE_CXX_COMPILER : O caminho para g++ na cadeia de ferramentas de compilação cruzada
Link para download para cross-compilation toolchain: host-tools.tar.gz . Você pode baixá-lo através do comando wget e então descompactar:
wget https://sophon-file.sophon.cn/sophon-prod-s3/drive/23/03/07/16/host-tools.tar.gztar -xf host-tools.tar.gz
Se você já compilou duo-buildroot-sdk , o diretório host-tools
sob seu diretório raiz é o diretório da cadeia de ferramentas de compilação cruzada. Não há necessidade de baixá-lo novamente. Você pode modificá-lo OpenCV_DIR
e especificá-lo diretamente para este diretório. Ou criar um link apontando para o diretório.
Compile
Compilar no modo cmake criará alguns diretórios e arquivos intermediários, então criamos um novo diretório build
e entramos neste diretório para concluí-lo:
mkdir buildcd buildcmake ..make
A saída normal da compilação é a seguinte:
$ make[ 50%] Building CXX object CMakeFiles/opencv-mobile-test.dir/main.cpp.o[100%] Linking CXX executable opencv-mobile-test[100%] Built target opencv-mobile-test
Erro gerado porque a versão estava errada no CMakeLists.txt
set(OpenCV_DIR "${CMAKE_CURRENT_SOURCE_DIR}/opencv-mobile-4.10.0-milkv-duo/lib/cmake/opencv4")
O opencv-mobile-test
gerado no diretório build
atual é o programa de teste:
$ lsCMakeCache.txt CMakeFiles cmake_install.cmake Makefile opencv-mobile-test
A estrutura do diretório neste momento é a seguinte:
picture-resize/ # Test program root directory├── build # Compile output directory├── CMakeLists.txt # CMake configuration file├── host-tools # Duo cross-compilation tool chain directory├── main.cpp # Test program source code file└── opencv-mobile-4.9.0-milkv-duo/ # opencv-mobile precompiled library directory
Transfira o programa opencv-mobile-test gerado para o Duo através do comando scp
:
Em seguida, transfira uma imagem jpg
com tamanho de 1024x1024
para teste para o Duo:
scp in.jpg root@192.168.42.1:/root/
in.jpg
:
Execute o programa de teste no Duo
Para firmware Duo, use temporariamente a versão V1.0.8
Efetue login no terminal Duo através da porta serial ou ssh e entre no diretório /root/:
cd /root/
Adicione permissões executáveis ao opencv-mobile-test:
chmod +x opencv-mobile-test
Execute o programa de teste:
Se você encontrar um erro OOM
, pode ser que a resolução da imagem esteja muito grande e o uso da memória exceda a memória disponível do Duo. É normal alterar a imagem para um tamanho menor.
Out of memory: Killed process 3718 (opencv-mobile-t) total-vm:31168kB, anon-rss:11384kB, file-rss:4kB, shmem-rss:0kB, UID:0
Use o comando ls
para verificar se o arquivo out.jpg
foi gerado no diretório atual:
[root@milkv-duo]~# lsin.jpg opencv-mobile-test out.jpg
Use o comando scp
no computador para recuperar o arquivo out.jpg
localmente e verifique se o tamanho é 200x200:
2. Teste de decodificação de Hardware acelerada
opencv-mobile já suporta decodificação JPG acelerada por hardware no Milk-V Duo
- O módulo opencv-mobile highgui carrega dinamicamente a biblioteca cvi e a decodificação de hardware JPG em tempo de execução
- Não há necessidade de modificar o código, cv::imread() e cv::imdecode() são suportados automaticamente
- Suporta rotação automática EXIF e decodificação direta para escala de cinza
- Acelerado de 5 a 11 vezes!
Exemplo de teste
Para verificar o efeito real da aceleração de hardware JPG, você também pode usar o programa de exemplo anterior que dimensiona o arquivo jpg para 200x200 e usar o pacote pré-compilado opencv-mobile sem aceleração de hardware JPG e o pacote pré-compilado com aceleração de hardware JPG para gerar programas de teste, comparar pelo tempo de execução no Duo.
Pacote pré-compilado sem aceleração de hardware JPG: opencv-mobile-4.8.0-milkv-duo.zip
Pacote pré-compilado com aceleração de hardware JPG: opencv-mobile-4.9.0-milkv-duo.zip
Use dois pacotes pré-compilados para compilar opencv-mobile-test
respectivamente e transferi-los para o Duo para execução. Eu testei no Duo-256M aqui. in.jpg
usa uma imagem com resolução de 3000x3000 e tamanho de imagem jpg de 3,2M.
[root@milkv-duo]~# time ./opencv-mobile-test-4.8.0 real 0m 2.56suser 0m 2.31ssys 0m 0.24s
[root@milkv-duo]~# time ./opencv-mobile-test-4.9.0 this device is not whitelisted for jpeg encoder rkmppreal 0m 0.37suser 0m 0.13ssys 0m 0.14s
Pode-se observar que o tempo de execução sem aceleração de hardware JPG é 2.56s
, e o tempo de execução com aceleração de hardware JPG é apenas 0.37s
, o que equivale a cerca 6.92
de vezes.
Alguns detalhes e limitaçõess
Carregar biblioteca dinâmica cvi-mmf em tempo real
Para reduzir o acoplamento de compilação, o opencv-mobile usa o método dlopen/dlsym de tempo de execução para carregar libsys libvpu libae libawb libisp libcvi_bin libsns_gc2083. Mesmo se a biblioteca estiver ausente durante a compilação, ela ainda é compatível e está disponível.
Este método também pode se adaptar automaticamente a atualizações posteriores da biblioteca do sistema.
Whitetlist
O código otimizado foi verificado e testado no Milk-V Duo / Milk-V Duo-256M.
Ao carregar a biblioteca cvi-mmf, também é determinado se /proc/device-tree/model é um dispositivo Milk-V Duo e pode retornar automaticamente para a versão não otimizada em outros dispositivos.
Evite resoluções especiais
Durante o teste, descobriu-se que, em resoluções ultrapequenas (2x2) e ultra grandes (4096x4096), as imagens geralmente ficam danificadas ou o conteúdo fica distorcido, ocorrem erros de codificação e até mesmo o dispositivo é desligado devido à memória insuficiente.
Portanto, nas seguintes circunstâncias especiais, ele retornará automaticamente para a versão não otimizada:
- w ou h não é múltiplo de 2
- w ou h é menor que 8
Armadilhas no processo de decodificação e alinhamento de vpss
- Ler arquivo jpg na memória
- Analise o cabeçalho jpg e obtenha o método de amostragem do número do canal wh EXIF e outras informações
- cvi-mmf prepara 3 vbuffers para vb decodificado, vb rotacionado e vb convertido por BGR
- vdec decodifica para yuv444/yuv422/yuv420/y
- vpss faz a rotação e yuv converte para nv12
- vpss faz conversão nv12 para bgr
Entre eles, o teste ** descobriu que o vpss tem requisitos mais altos para alinhamento de dados. Acontecerá que os dados decodificados pelo vdec são alinhados em 64 bytes, enquanto o vpss requer que os dados sejam alinhados em 128 bytes**.
Em alguns tamanhos que não são múltiplos de 128, podem ocorrer falhas de decodificação ou erros de dados de imagem decodificados:
Então foi relrealizado um "hack" no meio de vdec->vpss. Após a decodificação de vdec e antes do processamento de vpss, eu resetei o valor de phyaddr e re-memmove os dados do canal UV para atender aos requisitos de alinhamento de vpss.
Se for decodificado em escala de cinza, o vpss tratará yuv diretamente como y, o que pode acelerar a rotação.
No geral, o processo de decodificação de jpg é muito mais complicado do que a codificação, e há mais situações a serem consideradas.
8 Direção das rotações
O vdec só pode ser configurado para emitir flip/mirror, e com o vpss ele só pode fazer rotação de 90/180/270 e pode combinar 8 direções de rotação.
Como o vpss só pode rotacionar dados nv12, o canal uv decodificado pelo yuv444 será inevitavelmente subamostrado, o que é prejudicial à qualidade da imagem .
Yuv422 vertical e progressivo não são suportados .
Durante o teste, foi descoberto que yuv422 horizontal jpg pode ser decodificado normalmente, mas yuv422 vertical jpg é decodificado incorretamente por vdec. Esse tipo de jpg retornará automaticamente para decodificação de software.
Além disso, jpgs progressivos não são suportados.
Testes de desempenho
O teste lê a imagem com antecedência e chama repetidamente cv::imdecode() para decodificar JPG e eliminar a interferência da leitura e gravação do arquivo, e as estatísticas mais rápidas e demoradas são obtidas.
Teste arquivos jpg em quatro espaços de cores de YUV444 YUV422 YUV420 GREY com resolução de 720p e teste em conjunto o processo de decodificação de rotação de 90 graus de acordo com EXIF.
Teste cv::Mat decodificado para BGR e escala de cinza, respectivamente.
Testado em Milk-V Duo e Milk-V Duo-256M.
Os resultados dos testes mostram que a decodificação JPG acelerada por hardware cvi-mmf melhorou muito.
3. Teste de aceleração de Hardware VPSSeste
O opencv-mobile agora oferece suporte a câmeras MIPI CSI Milk-V Duo/Duo256M/DuoS e aceleração de hardware VPSS.
- O módulo opencv-mobile highgui implementa acesso a fluxos de câmera com base em cvi-mmf
- Carregue automaticamente e dinamicamente a biblioteca ae+awb+isp+cvi_bin em tempo de execução para implementar o ajuste de imagem ISP
- Carregue automaticamente e dinamicamente a biblioteca vpss em tempo de execução para implementar a aceleração de hardware crop + YUV2BGR
- Não há necessidade de modificar o código, chamar cv::VideoCapture automaticamente o suportará e permitirá a definição da resolução.
- Atualmente suporta apenas a câmera oficial GC2083 da Milk-V
Exemplo de teste
- Use cv::VideoCapture para abrir a câmera e definir a resolução para 320x240
- Obtenha 1 quadro de imagem a cada 1 segundo
- Desligar a câmera
- Por fim, costure as 9 imagens e salve-as
O primeiro quadro está preto porque o ISP ainda está contando as informações da imagem e é tarde demais para processá-las automaticamente.
Código de exemplo:
#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>
#include <unistd.h> // sleep()
int main(){ cv::VideoCapture cap; cap.set(cv::CAP_PROP_FRAME_WIDTH, 320); cap.set(cv::CAP_PROP_FRAME_HEIGHT, 240); cap.open(0);
const int w = cap.get(cv::CAP_PROP_FRAME_WIDTH); const int h = cap.get(cv::CAP_PROP_FRAME_HEIGHT); fprintf(stderr, "%d x %d\n", w, h);
cv::Mat bgr[9]; for (int i = 0; i < 9; i++) { cap >> bgr[i];
sleep(1); }
cap.release();
// combine into big image { cv::Mat out(h * 3, w * 3, CV_8UC3); bgr[0].copyTo(out(cv::Rect(0, 0, w, h))); bgr[1].copyTo(out(cv::Rect(w, 0, w, h))); bgr[2].copyTo(out(cv::Rect(w * 2, 0, w, h))); bgr[3].copyTo(out(cv::Rect(0, h, w, h))); bgr[4].copyTo(out(cv::Rect(w, h, w, h))); bgr[5].copyTo(out(cv::Rect(w * 2, h, w, h))); bgr[6].copyTo(out(cv::Rect(0, h * 2, w, h))); bgr[7].copyTo(out(cv::Rect(w, h * 2, w, h))); bgr[8].copyTo(out(cv::Rect(w * 2, h * 2, w, h)));
cv::imwrite("out.jpg", out); }
return 0;}
Da mesma forma, consulte o método para transferir outros arquivos compilados para o Duo para executar o comando ./opencv-mobile-test
:
- A câmera precisa estar conectada antes que o Duo seja ligado
- Quando o comando é executado, a direção da câmera pode ser girada para capturar imagens diferentes até que o programa termine
[root@milkv-duo]~# ./opencv-mobile-test this device is not whitelisted for jpeg encoder rkmppthis device is not whitelisted for capture v4l2 rkaiqthis device is not whitelisted for capture v4l2 rkaiqISP Vipipe(0) Allocate pa(0x8bf30000) va(0x0x3fe7c50000) size(291120)awbInit ver 6.8@20215000 R:1400 B:3100 CT:28501 R:1500 B:2500 CT:39002 R:2300 B:1600 CT:6500Golden 1024 1024 1024WB Quadratic:0isWdr:0ViPipe:0,===GC2083 1080P 30fps 10bit LINE Init OK!===binName = /mnt/cfg/param/cvi_sdr_bin********************************************************************************cvi_bin_isp messagegerritId: 36403 commitId: c69c5863e md5: cab880835a2ad5184de5ed7762404b84sensorNum 1 sensorName0 2083
PQBIN messagegerritId: 80171 commitId: 5c9d8fc5d md5: ba5a510e093ad42db6788e6c2d13169esensorNum 3 sensorName0 2053
author: wanqiang.he desc: 思博慧CV1812H_GC2083_RGB_mode_V1.0.0createTime: 2023-08-04 16:48:08version: V1.1 tool Version: v3.0.5.24 mode: ********************************************************************************sensorName(0) mismatch, mwSns:2083 != pqBinSns:2053320 x 2400 R:1165 B:3087 CT:26881 R:1464 B:2327 CT:39372 R:1974 B:1613 CT:7225Golden 1464 1024 2327wdrLEOnly:1ISP Vipipe(0) Free pa(0x8bf30000) va(0x0x3fe7c50000)gc2083_standby
Após a operação bem-sucedida, uma imagem out.jpg
composta de 9 quadros de imagens será gerada.
[root@milkv-duo]~# lsopencv-mobile-test out.jpg
Use o scp
comando no seu computador para recuperar o arquivo out.jpg
localmente:
scp root@192.168.42.1:/root/out.jpg .
Veja a imagem gerada out.jpg
:
Alguns detalhes e limitações
Carregar biblioteca dinâmica cvi-mmf em tempo realtempo de execução
Para reduzir o acoplamento de compilação, o opencv-mobile usa o método dlopen/dlsym de tempo de execução para carregar libsys libvpu libae libawb libisp libcvi_bin libsns_gc2083. Mesmo se a biblioteca estiver ausente durante a compilação, ela ainda é compatível e está disponível.
Este método também pode se adaptar automaticamente a atualizações posteriores da biblioteca do sistema.
Detecção de dispositivos e whitelisting
O código otimizado foi verificado e testado no Milk-V Duo / Milk-V Duo-256M.
Ao carregar a biblioteca cvi-mmf, determine adicionalmente se /proc/device-tree/model é um dispositivo Milk-V Duo
As interfaces cvi-mmf Milk-V Duo e Milk-V Duo-256M são compatíveis com o código-fonte, mas, na verdade, os arquivos de configuração sns ini são diferentes. Se usados incorretamente, os quadros de imagem não podem ser obtidos normalmente e um erro será relatado.
isp_err_chk:6343(): CSIBDG_A CH0 frm height less than setting(1080)
Distinga dois modelos de acordo com as informações do modelo e retome o trabalho após carregar a configuração correspondente:
- Milk-V Duo: sensor_cfg_gc2083.ini
- Milk-V Duo-256M:sensor_cfg_gc2083.ini
Resolução adaptativa
A resolução nativa da câmera é 1920x1080 30 fps.
- Se o tamanho da solicitação do usuário exceder 1080p, o tamanho será reduzido automaticamente para dentro do intervalo de 1080p, mantendo a proporção
- Se o usuário solicitar menos de 1080p, ele será automaticamente cortado no centro e mantido reduzido para a resolução necessária
Número do pool de memória vb
Embora, em teoria, um bloco de memória possa ser reutilizado o tempo todo para fornecer busca de quadros ao NV21, durante os testes foi descoberto que, quando há poucos blocos de memória vb, ocorre um erro de exaustão de memória vb, resultando na incapacidade de buscar quadros normalmente após um período de tempo.
Consulte o código de exemplo cvi-mmf para abrir 4 blocos de memória para armazenar dados NV21, para que o problema de exaustão de vb não ocorra mais.
Material de referência
- opencv-mobile 现已支持 milkv-duo/duo256m MIPI CSI 摄像头和vpss硬件加速
- opencv-mobile 现已支持 milkv-duo cvi-mmf 硬件加速 JPG 解码
- opencv-mobile (迷你版opencv库)在 milkv-duo 上的移植和应
- https://milkv.io/docs/duo/resources/opencv-mobile
Sobre a SMARTCORE
A SMARTCORE FORNECE CHIPS E MÓDULOS PARA IOT, COMUNICAÇÃO WIRELESS, BIOMETRIA, CONECTIVIDADE, RASTREAMENTO E AUTOMAÇÃO. NOSSO PORTFÓLIO INCLUI MODEM 2G/3G/4G/NB-IOT, SATELITAL, MÓDULOS WIFI, BLUETOOTH, GPS, SIGFOX, LORA, LEITOR DE CARTÃO, LEITOR QR CCODE, MECANISMO DE IMPRESSÃO, MINI-BOARD PC, ANTENA, PIGTAIL, BATERIA, REPETIDOR GPS E SENSORES.
Nenhum comentário:
Postar um comentário