OpenCV nantu à STM32F7-Discovery

OpenCV nantu à STM32F7-Discovery Sò unu di i sviluppatori di u sistema operatore Embox, è in questu articulu vi parraraghju di cumu aghju sappiutu eseguisce OpenCV nantu à u STM32746G.

Se scrivite qualcosa cum'è "OpenCV on STM32 board" in un mutore di ricerca, pudete truvà parechje persone chì anu interessatu à utilizà sta libreria nantu à schede STM32 o altri microcontrollers.
Ci hè parechje video chì, à ghjudicà da u nome, deve dimustrà ciò chì hè necessariu, ma di solitu (in tutti i video chì aghju vistu) nantu à a tavula STM32, solu l'imaghjina hè stata ricevuta da a camera è u risultatu hè statu affissatu nantu à u screnu. è u prucessu di l'imaghjini stessu hè statu fattu sia nantu à un ordinatore regulare, sia in schede più putenti (per esempiu, Raspberry Pi).

Perchè hè difficiule?

A pupularità di e dumande di ricerca hè spiegata da u fattu chì OpenCV hè a biblioteca di visione di l'informatica più populari, chì significa chì più sviluppatori sò familiarizati cù questu, è a capacità di eseguisce codice prontu per desktop in un microcontroller simplifica assai u prucessu di sviluppu. Ma perchè ùn ci sò ancu ricetti populari pronti per risolve stu prublema?

U prublema di utilizà OpenCV nantu à picculi scialli hè ligatu à duie caratteristiche:

  • Se compilate a biblioteca ancu cù un settore minimu di moduli, simpricimenti ùn si mette micca in a memoria flash di u stessu STM32F7Discovery (ancu senza piglià in contu l'OS) per via di un codice assai grande (parechji megabytes d'istruzzioni)
  • A biblioteca stessa hè scritta in C++, chì significa
    • Avete bisognu di supportu per runtime pusitivu (eccezzioni, etc.)
    • Pocu supportu per LibC/Posix, chì si trova di solitu in OS per i sistemi integrati - avete bisognu di una libreria standard plus è una biblioteca di mudelli STL standard (vettore, etc.)

Porting à Embbox

Comu solitu, prima di portà qualsiasi prugramma à u sistema upirativu, hè una bona idea di pruvà à custruisce in a forma chì i sviluppatori l'intendevanu. In u nostru casu, ùn ci sò micca prublemi cù questu - u codice fonte pò esse truvatu github, a biblioteca hè custruita sottu GNU/Linux cù u solitu cmake.

A bona nutizia hè chì OpenCV pò esse custruitu cum'è una biblioteca statica fora di a scatula, chì facilita u porting. Cullemu una biblioteca cù una cunfigurazione standard è vede quantu spaziu occupanu. Ogni modulu hè recullatu in una biblioteca separata.

> size lib/*so --totals
   text    data     bss     dec     hex filename
1945822   15431     960 1962213  1df0e5 lib/libopencv_calib3d.so
17081885     170312   25640 17277837    107a38d lib/libopencv_core.so
10928229     137640   20192 11086061     a928ed lib/libopencv_dnn.so
 842311   25680    1968  869959   d4647 lib/libopencv_features2d.so
 423660    8552     184  432396   6990c lib/libopencv_flann.so
8034733   54872    1416 8091021  7b758d lib/libopencv_gapi.so
  90741    3452     304   94497   17121 lib/libopencv_highgui.so
6338414   53152     968 6392534  618ad6 lib/libopencv_imgcodecs.so
21323564     155912  652056 22131532    151b34c lib/libopencv_imgproc.so
 724323   12176     376  736875   b3e6b lib/libopencv_ml.so
 429036    6864     464  436364   6a88c lib/libopencv_objdetect.so
6866973   50176    1064 6918213  699045 lib/libopencv_photo.so
 698531   13640     160  712331   ade8b lib/libopencv_stitching.so
 466295    6688     168  473151   7383f lib/libopencv_video.so
 315858    6972   11576  334406   51a46 lib/libopencv_videoio.so
76510375     721519  717496 77949390    4a569ce (TOTALS)

Comu pudete vede da l'ultima linea, .bss è .data ùn occupanu assai spaziu, ma u codice hè più di 70 MiB. Hè chjaru chì s'ellu hè stata ligata à una applicazione specifica, u codice diventerà menu.

Pruvemu di scaccià quant'è moduli pussibule in modu chì un esempiu minimu hè assemblatu (chì, per esempiu, simplificà a versione OpenCV), cusì fighjemu cmake .. -LA è spegne in l'opzioni tuttu ciò chì si spegne.

        -DBUILD_opencv_java_bindings_generator=OFF 
        -DBUILD_opencv_stitching=OFF 
        -DWITH_PROTOBUF=OFF 
        -DWITH_PTHREADS_PF=OFF 
        -DWITH_QUIRC=OFF 
        -DWITH_TIFF=OFF 
        -DWITH_V4L=OFF 
        -DWITH_VTK=OFF 
        -DWITH_WEBP=OFF 
        <...>

> size lib/libopencv_core.a --totals
   text    data     bss     dec     hex filename
3317069   36425   17987 3371481  3371d9 (TOTALS)

Da una banda, questu hè solu un modulu di a biblioteca, da l'altra banda, questu hè senza ottimisazione di compilatore per a dimensione di codice (-Os). ~ 3 MiB di codice hè sempre assai, ma dà digià speranza di successu.

Eseguite in l'emulatore

Hè assai più faciule per debug nantu à l'emulatore, cusì prima assicuratevi chì a biblioteca travaglia in qemu. Cum'è una piattaforma emulata, aghju sceltu Integrator / CP, perchè prima, hè ancu ARM, è in segundu, Embbox supporta l'output graficu per questa piattaforma.

Embox hà un mecanismu per a custruzzione di biblioteche esterne, aduprendu l'aghjunghje OpenCV cum'è un modulu (passendu tutte e listesse opzioni per a custruzzione "minimale" in forma di biblioteche statiche), dopu aghjunghje una applicazione simplice chì pare cusì:

version.cpp:

#include <stdio.h>
#include <opencv2/core/utility.hpp>

int main() {
    printf("OpenCV: %s", cv::getBuildInformation().c_str());

    return 0;
}

Assemblamu u sistema, eseguimu - avemu u risultatu previstu.

root@embox:/#opencv_version                                                     
OpenCV: 
General configuration for OpenCV 4.0.1 =====================================
  Version control:               bd6927bdf-dirty

  Platform:
    Timestamp:                   2019-06-21T10:02:18Z
    Host:                        Linux 5.1.7-arch1-1-ARCH x86_64
    Target:                      Generic arm-unknown-none
    CMake:                       3.14.5
    CMake generator:             Unix Makefiles
    CMake build tool:            /usr/bin/make
    Configuration:               Debug

  CPU/HW features:
    Baseline:
      requested:                 DETECT
      disabled:                  VFPV3 NEON

  C/C++:
    Built as dynamic libs?:      NO
< Дальше идут прочие параметры сборки -- с какими флагами компилировалось,
  какие модули OpenCV включены в сборку и т.п.>

U prossimu passu hè di eseguisce qualchì esempiu, preferibile unu di i standard offerti da i sviluppatori stessi. nant'à u vostru situ. Aghju sceltu detector di cunfini canny.

L'esempiu duvia esse riscritta ligeramente per vede l'imaghjini cù u risultatu direttamente in u buffer di frame. Aviu avutu à fà questu, perchè. funzione imshow() pò disegnà l'imaghjini attraversu l'interfacce QT, GTK è Windows, chì, sicuru, ùn serà micca definitu in a cunfigurazione per STM32. In fattu, QT pò ancu esse eseguitu nantu à STM32F7Discovery, ma questu serà discututu in un altru articulu 🙂

Dopu una breve chjarificazione in quale formatu u risultatu di u detector di bordu hè guardatu, avemu una maghjina.

OpenCV nantu à STM32F7-Discovery

stampa originale

OpenCV nantu à STM32F7-Discovery

risultatu

Esecuzione nantu à STM32F7Discovery

In 32F746GDISCOVERY ci sò parechje sezioni di memoria di hardware chì pudemu usà un modu o un altru

  1. 320 KiB RAM
  2. 1 MiB flash per l'imaghjini
  3. 8 MiB di SDRAM
  4. 16 MiB QSPI NAND Flash
  5. slot per carta microSD

Una carta SD pò esse usata per almacenà l'imaghjini, ma in u cuntestu di eseguisce un esempiu minimu, questu ùn hè micca assai utile.
A visualizazione hà una risuluzione di 480 × 272, chì significa chì a memoria di framebuffer serà 522 bytes à una prufundità di 240 bits, i.e. questu hè più di a dimensione di RAM, cusì u framebuffer è u munzeddu (chì serà necessariu, cumpresu per OpenCV, per almacenà dati per l'imaghjini è strutture ausiliarii) seranu situati in SDRAM, tuttu u restu (memoria per stacks è altri bisogni di u sistema). ) anderà in RAM.

Se pigliamu a cunfigurazione minima per STM32F7Discovery (scaccià tutta a reta, tutti i cumandamenti, fate pile u più chjucu pussibule, etc.) è aghjunghje OpenCV cù esempii quì, a memoria necessaria serà a siguenti:

   text    data     bss     dec     hex filename
2876890  459208  312736 3648834  37ad42 build/base/bin/embox

Per quelli chì ùn sò micca assai familiarizati cù quali rùbbriche vanu induve, spiegheraghju: in .text и .rodata struzzioni è custanti (in generale, dati di lettura) si trovanu .data i dati sò mutabili, .bss ci sò variabili "nullati", chì, però, anu bisognu di un locu (sta sezione "andà" à a RAM).

A bona nutizia hè chì .data/.bss duverebbe adattà, ma cun .text u prublema hè chì ci hè solu 1MiB di memoria per l'imaghjini. Pò esse cacciatu fora .text u ritrattu da l'esempiu è leghje, per esempiu, da a carta SD in memoria à l'iniziu, ma fruits.png pesa circa 330KiB, cusì ùn risolve micca u prublema: più .text custituitu di u codice OpenCV.

In generale, ci hè solu una cosa - carica una parte di u codice in un lampu QSPI (hà un modu speciale di funziunamentu per mapping memoria à l'autobus di u sistema, perchè u processatore pò accede à sta dati direttamente). In questu casu, sorge un prublema: prima, a memoria di una unità flash QSPI ùn hè micca dispunibule immediatamente dopu chì u dispusitivu hè riavviatu (avete bisognu di inizializà separatamente u modu di mappa di memoria), è in segundu, ùn pudete micca "flash" sta memoria cù un bootloader familiar.

In u risultatu, hè statu decisu di ligà tuttu u codice in QSPI, è lampà cù un caricatore auto-scrittu chì riceverà u binariu necessariu via TFTP.

risultatu

L'idea di portà sta bibliuteca à Embox hè apparsa circa un annu fà, ma una volta è una volta hè stata posposta per diversi motivi. Unu di elli hè u supportu per libstdc++ è a biblioteca di mudelli standard. U prublema di u supportu C++ in Embox hè fora di u scopu di questu articulu, cusì quì diceraghju solu chì avemu riesciutu à ottene stu supportu in a quantità ghjusta per questa biblioteca per travaglià 🙂

In fine, sti prublemi sò stati superati (almenu abbastanza per l'esempiu OpenCV per travaglià), è l'esempiu curria. Ci vole 40 seconde longhi per u bordu per circà e fruntiere cù u filtru Canny. Questu, sicuru, hè troppu longu (ci sò cunsiderazioni nantu à cumu ottimisà sta materia, serà pussibule di scrive un articulu separatu nantu à questu in casu di successu).

OpenCV nantu à STM32F7-Discovery

In ogni casu, u scopu intermediu era di creà un prototipu chì mostrarà a pussibilità fundamentale di eseguisce OpenCV in STM32, rispettivamente, stu scopu hè statu rializatu, evviva!

tl;dr: istruzioni passo per passo

0: Scaricate e fonti di Embox, cum'è questu:

    git clone https://github.com/embox/embox && cd ./embox

1: Cuminciamu da assemblendu un bootloader chì "flash" una unità flash QSPI.

    make confload-arm/stm32f7cube

Avà vi tocca à cunfigurà a reta, perchè. Caricà l'imaghjini via TFTP. Per stabilisce l'indirizzi IP di u bordu è l'ospiti, avete bisognu di edità a conf/rootfs/network.

Esempiu di cunfigurazione:

iface eth0 inet static
    address 192.168.2.2
    netmask 255.255.255.0
    gateway 192.168.2.1
    hwaddress aa:bb:cc:dd:ee:02

gateway - indirizzu di l'ospite da induve l'imaghjina serà caricata, address - indirizzu di u tribunale.

Dopu quì, cullemu u bootloader:

    make

2: A carica abituale di u bootloader (scusate per u pun) nantu à u bordu - ùn ci hè nunda di specificu quì, avete bisognu di fà cum'è per qualsiasi altra applicazione per STM32F7Discovery. Se ùn sapete micca cumu fà, pudete leghje nantu à questu ccà.
3: Cumpilà l'imaghjini cù a cunfigurazione per OpenCV.

    make confload-platform/opencv/stm32f7discovery
    make

4: Estratto da e sezioni ELF da scrive in QSPI in qspi.bin

    arm-none-eabi-objcopy -O binary build/base/bin/embox build/base/bin/qspi.bin 
        --only-section=.text --only-section=.rodata 
        --only-section='.ARM.ex*' 
        --only-section=.data

Ci hè un script in u repertoriu conf chì face questu, perchè pudete eseguisce

    ./conf/qspi_objcopy.sh # Нужный бинарник -- build/base/bin/qspi.bin

5: Utilizendu tftp, scaricate qspi.bin.bin à una unità flash QSPI. Nant'à l'ospiti, per fà questu, copiate qspi.bin à u cartulare radicali di u servitore tftp (di solitu /srv/tftp/ o /var/lib/tftpboot/; i pacchetti per u servitore currispundenti sò dispunibuli in i distribuzioni più populari, generalmente chjamati). tftpd o tftp-hpa, qualchì volta avete da fà systemctl start tftpd.service per cumincià).

    # вариант для tftpd
    sudo cp build/base/bin/qspi.bin /srv/tftp
    # вариант для tftp-hpa
    sudo cp build/base/bin/qspi.bin /var/lib/tftpboot

In Embbox (vale à dì in u bootloader), avete bisognu di eseguisce u cumandimu seguitu (assumemu chì u servitore hà l'indirizzu 192.168.2.1):

    embox> qspi_loader qspi.bin 192.168.2.1

6: Cù cumandimu goto avete bisognu di "saltà" in a memoria QSPI. U locu specificu varierà secondu cumu l'imaghjina hè ligata, pudete vede stu indirizzu cù u cumandamentu mem 0x90000000 (l'indirizzu iniziale si mette in a seconda parolla di 32 bit di l'imaghjini); vi sarà dinù bisognu di bandiera a pila -s, l'indirizzu di stack hè in 0x90000000, esempiu:

    embox>mem 0x90000000
    0x90000000:     0x20023200  0x9000c27f  0x9000c275  0x9000c275
                      ↑           ↑
              это адрес    это  адрес 
                стэка        первой
                           инструкции

    embox>goto -i 0x9000c27f -s 0x20023200 # Флаг -i нужен чтобы запретить прерывания во время инициализации системы

    < Начиная отсюда будет вывод не загрузчика, а образа с OpenCV >

7: Lanciata

    embox> edges 20

è gode di a ricerca di cunfini di 40 seconde 🙂

Se qualcosa va male - scrivite un prublema in u nostru repository, o à a lista di mailing [email prutettu], o in un cumentu quì.

Source: www.habr.com

Add a comment