OpenCV pÄ STM32F7-Discovery

OpenCV pÄ STM32F7-Discovery Eg er ein av utviklarane av operativsystemet Embox, og i denne artikkelen vil eg fortelje om korleis eg fekk OpenCV til Ä fungere pÄ STM32746G-brettet.

Dersom ein sÞker etter noko som «OpenCV on STM32 board», kan ein finne ganske mange som er interessert i Ä bruke dette biblioteket pÄ STM32-brett eller andre mikrokontrollarar.
Det fins fleire videoar som, ut frÄ tittelen, skal demonstrere det som er nÞdvendig, men som regel (i alle videoar eg har sett) vart det pÄ STM32-brettet berre henta bilde frÄ eit kamera og vist resultatet pÄ skjermen, medan sjÞlve bildebehandlinga vart gjort enten pÄ ein vanlig datamaskin eller pÄ kraftigare brett (for eksempel Raspberry Pi).

Kvifor er dette vanskeleg?

Populariteten til sÞkjerane kan forklarast med at OpenCV er det mest populÊre biblioteket for datamaskinsyn, noko som betyr at fleire utviklarar er kjent med det, og moglegheita for Ä kÞyre ferdig kode for desktop pÄ ein mikrokontroller gjer utviklingsprosessen mykje enklare. Men kvifor finst det fortsatt inga populÊre konkrete lÞysing pÄ dette problemet?

Problemet med Ä bruke OpenCV pÄ smÄ brett heng saman med to sÊrtrekk:

  • Dersom ein kompilerer biblioteket med til og med det minimale settet av moduler, vil det rett og slett ikkje fĂ„ plass i flash-minnet til STM32F7Discovery (utan Ă„ ta med OS) pĂ„ grunn av den store stĂžrrelsen pĂ„ koden (flere megabyte instruksjonar)
  • Selve biblioteket er skrive i C++, og det betyr
    • At ein treng stĂžtte for C++-runtime (unntak m.m.)
    • Lite stĂžtte for LibC/Posix, som vanlegvis finst i operativsystem for innebygde system - ein treng standardbibliotek for C++ og standardmalbiblioteket STL (vektor m.m.)

Portering til Embox

Som vanleg, fÞr ein porterer programvare til operativsystemet, bÞr ein prÞve Ä bygge det slik utviklarane hadde tenkt. I vÄrt tilfelle oppstÄr det ikkje problem med dette - kjeldene kan bli funne pÄ GitHub, biblioteket kan bli bygd for GNU/Linux med vanleg cmake.

Av gode nyheiter er at OpenCV kan bli bygd som eit statisk bibliotek, noko som gjer porteringa enklare. Me byggjer biblioteket med standardkonfigurasjonen og sjÄ kor mykje plass det tar. Kvar modul blir bygd som eit eige bibliotek.

> 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)

Som syns i den siste linjen, tar .bss og .data ikke sÄ mye plass, men kodene er over 70 MiB. Det er klart at dersom dette bindes statisk med en spesifikk applikasjon, vil koden bli mindre.

La oss prÞve Ä fjerne sÄ mange moduler som mulig for Ä samle et minimalt eksempel (som for eksempel bare viser versjonen av OpenCV), sÄ vi ser. cmake .. -LA og deaktiverer alle opsjoner som kan deaktiveres.

        -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)

PÄ den ene siden er dette bare én modul av biblioteket, men pÄ den andre siden er dette uten optimalisering av kompilatoren for kode stÞrrelse (-Os). ~3 MiB kode er fortsatt en god del, men gir allerede hÄp om suksess.

KjĂžring i emulator

Det er mye enklere Ä feilsÞke i emulator, sÄ fÞrst skal vi sikre oss at biblioteket fungerer pÄ qemu. Som emulert plattform valgte jeg Integrator/CP, fordi dette er ogsÄ ARM, og i tillegg stÞtter Embox grafikkutgang for denne plattformen.

I Embox er det et system for Ă„ bygge eksterne biblioteker, med det kan vi legge til OpenCV som modul (ved Ă„ sende alle de samme opsjonene for "minimal" bygging som statiske biblioteker), og etter det legger jeg til en enkel applikasjon som ser slik ut:

version.cpp:

#include 
#include 

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

    return 0;
}

Vi bygger systemet, starter det — og fĂ„r den forventede utgangen.

root@embox:/$opencv_version                                                     
OpenCV: 
Generell konfigurasjon for OpenCV 4.0.1 =====================================
  Versjonskontroll:               bd6927bdf-dirty

  Plattform:
    Tidsstempel:                   2019-06-21T10:02:18Z
    Vert:                        Linux 5.1.7-arch1-1-ARCH x86_64
    MÄl:                      Generisk arm-unknown-none
    CMake:                       3.14.5
    CMake-generator:             Unix Makefiles
    CMake byggeverktĂžy:            /usr/bin/make
    Konfigurasjon:               Debug

  CPU/HW-funksjoner:
    Grunnlinje:
      forespurt:                 DETECT
      deaktivert:                  VFPV3 NEON

  C/C++:
    Bygget som dynamiske biblioteker?:      NEI

Neste steg er Ä kjÞre et eksempel, helst et standard eksempel fra utviklerne selv pÄ deres nettside. Jeg valgte Canny kantdetektor.

Eksemplet mĂ„tte skrives om litt for Ă„ vise bildet med resultatet direkte i framebuffer. Dette mĂ„tte gjĂžres fordi funksjonen imshow() kan tegne bilder via grensesnittene QT, GTK og Windows, som selvfĂžlgelig ikke vil vĂŠre i konfigurasjonen for STM32. Faktisk kan QT ogsĂ„ kjĂžres pĂ„ STM32F7Discovery, men det vil bli behandlet i en annen artikkel 🙂

Etter en kort avklaring om hvilket format resultatet fra kantdetektoren lagres i, fÄr vi bildet.

OpenCV pÄ STM32F7-Discovery

Det originale bildet

OpenCV pÄ STM32F7-Discovery

Resultatet

KjÞring pÄ STM32F7Discovery

PÄ 32F746GDISCOVERY er det flere maskinvareminnesegmenter som vi kan bruke pÄ forskjellige mÄter

  1. 320KiB RAM
  2. 1MiB flashminne for bildet
  3. 8MiB SDRAM
  4. 16MiB QSPI NAND-flash
  5. Grensesnitt for microSD-kort

SD-kortet kan brukes til Ă„ lagre bilder, men i sammenheng med Ă„ kjĂžre et minimalt eksempel er det ikke veldig nyttig.
Skjermen har en opplĂžsning pĂ„ 480×272, sĂ„ minnet for framebufferen vil vĂŠre 522 240 byte med dybde pĂ„ 32 biter, sĂ„ dette er mer enn stĂžrrelsen pĂ„ RAM, sĂ„ framebufferen og stabelen (som ogsĂ„ er nĂždvendig for OpenCV for Ă„ lagre data for bilder og hjelpestrukturer) vil bli plassert i SDRAM, alt annet (minne for stakker og andre systembehov) vil gĂ„ til RAM.

Hvis vi tar en minimal konfigurasjon for STM32F7Discovery (fjerner alt nettverk, alle kommandoer, gjÞr stakkene sÄ smÄ som mulig osv.) og legger til OpenCV med eksempler, vil minnebehovet vÊre fÞlgende:

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

For those who are not very familiar with how sections are arranged, let me explain: in .text og .rodata are stored instructions and constants (roughly speaking, readonly data), in .data are mutable data stored, in .bss are "zeroed" variables, which still need space (this section will go to RAM).

The good news is that .data/.bss should fit, but there's a problem — there is only 1MiB of memory for the image. You can discard the image from the example and read it, for instance, from an SD card into memory at startup, but fruits.png weighs about 330KiB, so that won't solve the problem: a large part .text consists precisely of OpenCV code. .text Basically, there is only one solution left — to load part of the code onto the QSPI flash chip (it has a special operating mode for mapping memory onto the system bus, so the processor can directly access this data). However, there is a problem: firstly, the memory of the QSPI flash is not available immediately after resetting the device (you need to separately initialize the memory-mapped mode), and secondly, you cannot "flash" this memory with the usual bootloader. .text As a result, it was decided to link all the code into QSPI and flash it with a custom bootloader that will obtain the necessary binary via TFTP.

The idea to port this library to Embox came about roughly a year ago, but it was postponed repeatedly for various reasons. One of them is the support of libstdc++ and the standard template library. The issue of supporting C++ in Embox goes beyond the scope of this article, so I will only say here that we managed to achieve this support to the extent required for the operation of this library 🙂

Ultimately, these problems were overcome (at least to a sufficient extent for the OpenCV example to work), and the example ran. The board takes 40 long seconds to find edges with the Canny filter. This is, of course, too long (there are ideas on how to optimize this, and I could write a separate article on it if successful).

Resultatet

Nevertheless, the intermediate goal was to create a prototype that demonstrates the principle possibility of running OpenCV on STM32, and thus, this goal was achieved, hooray!

tl;dr: step-by-step guide

OpenCV pÄ STM32F7-Discovery

0: Download the Embox sources, for instance, like this:

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

1: Let's start with building the bootloader that will "flash" the QSPI flash.

    make confload-arm/stm32f7cube

1: La oss begynne med Ă„ bygge en bootloader som 'programmerer' QSPI-flashminnet.

    make confload-arm/stm32f7cube

NÄ mÄ vi konfigurere nettverket, ettersom vi skal laste opp bildet via TFTP. For Ä angi IP-adressene til kortet og verten, mÄ du endre filen conf/rootfs/network.

Eksempel pÄ konfigurasjon:

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 — adressen til verten som bildet skal lastes opp fra, address — adressen til kortet.

Etter dette bygger vi oppstartslasteren:

    lag

2: Alminnelig lasting av oppstartslasteren (unnskyld ordspillet) pĂ„ kortet — det er ingenting spesifikt her, det mĂ„ gjĂžres som med hvilken som helst annen applikasjon for STM32F7Discovery. Hvis du ikke vet hvordan dette gjĂžres, kan du lese om det here.
3: Kompilering av bildet med konfigurasjon for OpenCV.

    make confload-platform/opencv/stm32f7discovery
    make

4: Utdrag fra ELF-seksjoner som mÄ skrives til QSPI, i 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

I katalogen conf finnes det et skript som gjÞr dette, sÄ du kan starte det

    ./conf/qspi_objcopy.sh # NĂždvendig binĂŠr -- build/base/bin/qspi.bin

5: Ved hjelp av tftp laster vi opp qspi.bin.bin til QSPI-flashminnet. PÄ verten mÄ du kopiere qspi.bin til rotmappen til tftp-serveren (vanligvis er dette /srv/tftp/ eller /var/lib/tftpboot/; pakkene for den aktuelle serveren finnes i de fleste populÊre distribusjoner, ofte kalt tftpd eller tftp-hpa, noen ganger mÄ du gjÞre systemctl start tftpd.service for Ä starte).

    # ĐČĐ°Ń€ĐžĐ°ĐœŃ‚ ĐŽĐ»Ń tftpd
    sudo cp build/base/bin/qspi.bin /srv/tftp
    # ĐČĐ°Ń€ĐžĐ°ĐœŃ‚ ĐŽĐ»Ń tftp-hpa
    sudo cp build/base/bin/qspi.bin /var/lib/tftpboot

PÄ Embox (dvs. i oppstartslasteren) mÄ du utfÞre fÞlgende kommando (vi antar at serverens adresse er 192.168.2.1):

    embox> qspi_loader qspi.bin 192.168.2.1

6: Med kommandoen goto mÄ du "hoppe" inn i QSPI-minnet. Den spesifikke plasseringen vil variere avhengig av hvordan bildet er lenket; du kan se denne adressen med kommandoen mem 0x90000000 (startadressen ligger i det andre 32-bits ordet i bildet); det vil ogsÄ vÊre nÞdvendig Ä sette stakken med flagg -s, stakkens adresse ligger pÄ adressen 0x90000000, eksempel:

    embox>mem 0x90000000
    0x90000000:     0x20023200  0x9000c27f  0x9000c275  0x9000c275
                      ↑           ↑
              dette er adressen    dette er adressen 
                til stakken        til den fĂžrste
                           instruksjonen

    embox>goto -i 0x9000c27f -s 0x20023200 # Flagget -i er nĂždvendig for Ă„ forhindre avbrudd under systeminitialisering

7: KjĂžr

    embox> edges 20

og nyt 40 sekunder med kantdeteksjon 🙂

Hvis noe gĂ„r galt — skriv en issue i vĂ„r repository, eller pĂ„ mailinglisten embox-devel@googlegroups.com, eller i kommentarene her.

Kilde: habr.com

KjĂžp pĂ„litelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere đŸ”„ KjĂžp pĂ„litelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere | ProHoster