OpenCV pÄ STM32F7-Discovery

OpenCV pÄ STM32F7-Discovery Jag Àr en av utvecklarna av operativsystemet Embox, och i den hÀr artikeln ska jag berÀtta om hur jag lyckades köra OpenCV pÄ STM32746G-kortet.

Om man slÄr upp nÄgot som "OpenCV pÄ STM32-kort" i en sökmotor kan man hitta ganska mÄnga som Àr intresserade av att anvÀnda detta bibliotek pÄ STM32-kort eller andra mikrokontroller.
Det finns flera videor som, utifrÄn namnet, borde demonstrera det som behövs, men vanligtvis (i alla videor jag har sett) sÄ utfördes bara bildtagning frÄn kameran pÄ STM32-kortet och resultatet visades pÄ skÀrmen, medan sjÀlva bildbehandlingen gjordes antingen pÄ en vanlig dator eller pÄ kraftfullare plattor (till exempel Raspberry Pi).

Varför Àr detta svÄrt?

Populariteten av sökfrÄgor förklaras av det faktum att OpenCV Àr det mest populÀra biblioteket för datorseende, vilket betyder att fler utvecklare Àr bekanta med det, och möjligheten att köra fÀrdig kod för dator pÄ en mikrokontroller förenklar utvecklingsprocessen avsevÀrt. Men varför finns det fortfarande inga populÀra fÀrdiga lösningar pÄ detta problem?

Problemet med att anvÀnda OpenCV pÄ smÄ enheter Àr relaterat till tvÄ egenskaper:

  • Om man kompilerar biblioteket Ă€ven med det minsta antalet moduler sĂ„ fĂ„r man helt enkelt inte plats med det i flashminnet pĂ„ samma STM32F7Discovery (Ă€ven utan att rĂ€kna med OS) pĂ„ grund av den mycket stora koden (flera megabyte instruktioner)
  • Biblioteket Ă€r skrivet i C++, vilket innebĂ€r
    • Att det behövs stöd för C++ runtime (undantag osv.)
    • Lite stöd för LibC/Posix, som vanligtvis finns i operativsystem för inbĂ€ddade system – det behövs standardbibliotek för C++ och STL-standardbibliotek (vector osv.)

Portering till Embox

Som vanligt, innan man porterar nĂ„gra program till operativsystemet, Ă€r det bra att försöka bygga det i den form som utvecklarna avsĂ„g. I vĂ„rt fall finns det inga problem med detta – kĂ€llkoden kan hittas pĂ„ GitHub, biblioteket kan byggas under GNU/Linux med vanlig cmake.

Av de goda nyheterna Àr att OpenCV kan byggas som ett statiskt bibliotek direkt, vilket gör porteringen enklare. Vi bygger biblioteket med standardkonfigurationen och ser hur mycket utrymme de tar. Varje modul byggs i ett separat 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 det framgÄr av sista raden tar .bss och .data inte sÄ mycket utrymme, men koden Àr mer Àn 70 MiB. Det Àr klart att om detta statiskt sammanlÀnkas med en specifik applikation kommer koden att bli mindre.

LÄt oss försöka ta bort sÄ mÄnga moduler som möjligt för att skapa ett minimalt exempel (som till exempel bara skriver ut versionen av OpenCV), sÄ vi kollar pÄ cmake .. -LA och stÀnger av allt som kan stÀngas av i alternativen.

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

Å ena sidan Ă€r detta bara en modul av biblioteket, Ă„ andra sidan Ă€r detta utan kompilatoroptimering för storleken pĂ„ koden (-Os). ~3 MiB kod Ă€r fortfarande ganska mycket, men ger redan hopp om framgĂ„ng.

Körning i emulator

Det Àr mycket lÀttare att debugga i emulatorn, sÄ lÄt oss först sÀkerstÀlla att biblioteket fungerar pÄ qemu. Jag valde Integrator/CP som emulerad plattform, eftersom det dels ocksÄ Àr ARM, och dels stödjer Embox grafikutmatning för denna plattform.

I Embox finns det en mekanism för att bygga externa bibliotek, med dess hjÀlp lÀgger vi till OpenCV som modul (genom att överlÀmna alla samma alternativ för 'minimal' byggning i form av statiska bibliotek), efter det lÀgger jag till en enklaste applikation som ser ut sÄ hÀr:

version.cpp:

#include 
#include 

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

    return 0;
}

Vi bygger systemet, kör det — och fĂ„r förvĂ€ntad output.

root@embox:\/ #opencv_version                                                     
OpenCV: 
AllmÀn konfiguration för OpenCV 4.0.1 =====================================
  Versionskontroll:               bd6927bdf-dirty

  Plattform:
    TidsstÀmpel:                   2019-06-21T10:02:18Z
    VĂ€rd:                        Linux 5.1.7-arch1-1-ARCH x86_64
    MÄl:                      Generic arm-unknown-none
    CMake:                       3.14.5
    CMake-generator:             Unix Makefiles
    CMake-byggverktyg:            \/usr\/bin\/make
    Konfiguration:               Debug

  CPU\/HW-funktioner:
    Baslinje:
      begÀrt:                 DETECT
      inaktiverad:                  VFPV3 NEON

  C\/C++:
    Byggd som dynamiska bibliotek?:      NEJ
< Fler byggparameter följer -- vilka flaggor som anvÀndes vid kompilering,
  vilka OpenCV-moduler som ingÄr i byggnaden osv.>

NÀsta steg Àr att köra ett exempel, helst ett standardexempel frÄn utvecklarna sjÀlva. pÄ deras webbplats.. Jag valde Canny-kantdetektorn..

Exemplet fick skrivas om lite för att visa bilden med resultatet direkt i framebuffer. Det hĂ€r var nödvĂ€ndigt eftersom funktionen imshow() kan rita bilder genom QT, GTK och Windows-grĂ€nssnitt, vilka sjĂ€lvklart inte finns i konfigurationen för STM32. Egentligen Ă€r QT ocksĂ„ möjligt att köra pĂ„ STM32F7Discovery, men det kommer att beskrivas i en annan artikel 🙂

Efter en kort undersökning av vilket format resultatet frÄn kantdetektorn lagras i, fÄr vi bilden.

OpenCV pÄ STM32F7-Discovery

Den ursprungliga bilden

OpenCV pÄ STM32F7-Discovery

Resultat

Körning pÄ STM32F7Discovery.

PÄ 32F746GDISCOVERY finns det flera hÄrdvaru minnessektioner som vi kan anvÀnda pÄ olika sÀtt.

  1. 320KiB RAM-minne.
  2. 1MiB flashminne för avbildning.
  3. 8MiB SDRAM.
  4. 16MiB QSPI NAND-flash.
  5. Anslutning för microSD-kort.

SD-kortet kan anvÀndas för att lagra bilder, men i sammanhanget av att köra ett minimalt exempel Àr det inte sÀrskilt anvÀndbart.
SkĂ€rmen har en upplösning pĂ„ 480×272, vilket innebĂ€r att minnet för framebuffer kommer att vara 522 240 byte vid en djup av 32 bitar, d.v.s. mer Ă€n storleken pĂ„ RAM-minnet, sĂ„ vi kommer att placera framebuffer och heap (som ocksĂ„ behövs för OpenCV för att lagra data för bilder och hjĂ€lpsstrukturer) i SDRAM, medan allt annat (minne för stackar och andra systembehov) gĂ„r till RAM.

Om vi tar en minimal konfiguration för STM32F7Discovery (tar bort allt nÀtverk, alla kommandon, gör stackarna sÄ smÄ som möjligt, osv.) och lÀgger till OpenCV med exempel, ser den nödvÀndiga minnesfördelningen ut som följer:

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

För dem som inte Àr sÄ bekanta med vilka sektioner som hör till vad, lÄt mig förklara: i .text och .rodata ligger instruktioner och konstanter (grovt sagt read-only-data), i .data ligger förÀnderliga data, i .bss ligger "nollstÀllda" variabler, som ÀndÄ behöver plats (denna sektion kommer "gÄ till" RAM).

Den goda nyheten Ă€r att .data/.bss mĂ„ste rymmas, men problemet Ă€r att .text underlaget Ă€r endast 1MiB minne. Man kan ta bort bilden frĂ„n exemplet och lĂ€sa den, till exempel frĂ„n ett SD-kort till minnet vid start, men fruits.png vĂ€ger cirka 330KiB, sĂ„ det löser inte problemet: största delen .text bestĂ„r faktiskt av kod frĂ„n OpenCV. .text Stort sett kvarstĂ„r bara en sak – att ladda en del av koden pĂ„ QSPI-flashminnet (det har ett speciellt driftslĂ€ge för minnesmappning pĂ„ systembussen sĂ„ att processorn kan komma Ă„t dessa data direkt). Men det uppstĂ„r ett problem: för det första Ă€r QSPI-flashminnets minne inte tillgĂ€ngligt direkt efter omstart av enheten (det mĂ„ste initieras separat i memory-mapped-lĂ€get), för det andra kan man inte "flasha" detta minne med en vanlig bootloader.

Som en följd av detta beslutades att lÀnka all kod i QSPI, och flasha den med en egen skriven bootloader som fÄr den nödvÀndiga binÀren via TFTP.

IdĂ©n att portera detta bibliotek till Embox kom upp för ungefĂ€r ett Ă„r sedan, men det har gĂ„ng pĂ„ gĂ„ng skjutits upp av olika anledningar. En av dem Ă€r stödet för libstdc++ och standard template library. Problemet med C++-stödet i Embox ligger utanför ramen för denna artikel, sĂ„ hĂ€r ska jag bara nĂ€mna att vi lyckades uppnĂ„ detta stöd i den utstrĂ€ckning som krĂ€vs för att anvĂ€nda detta bibliotek 🙂

Resultat

I slutÀndan övervanns dessa problem (Ätminstone i tillrÀcklig utstrÀckning för att exemplet med OpenCV skulle fungera), och exemplet kördes. KortlÀggningen av kanter med Canny-filter tar 40 lÄngsamma sekunder för styrenheten. Det Àr, naturligtvis, för lÄngsamt (det finns idéer om hur man kan optimera detta, och detta kan bli föremÄl för en separat artikel om det lyckas).

Trots detta var den mellanliggande mÄlsÀttningen att skapa en prototyp som skulle visa den grundlÀggande möjligheten att köra OpenCV pÄ STM32, och den mÄlet har uppnÄtts, hurra!

OpenCV pÄ STM32F7-Discovery

tl;dr: steg-för-steg-instruktioner

0: Ladda ner kÀllkoden till Embox, till exempel sÄ hÀr:

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

    1: Vi börjar med att bygga bootloadern som "flashar" QSPI-flashminnet.

make confload-arm/stm32f7cube

    make confload-arm/stm32f7cube

Nu behöver vi konfigurera nÀtverket, eftersom vi ska ladda bilden via TFTP. För att ange IP-adresser för kortet och vÀrdena mÄste filen conf/rootfs/network Àndras.

Exempelkonfiguration:

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 — vĂ€rdens adress som bilden kommer att laddas frĂ„n, address — kortets adress.

Efter detta samlar vi in startprogrammet:

    make

2: Vanlig laddning av startprogrammet (ursĂ€kta ordleken) till kortet — hĂ€r behövs inget specifikt, det görs som för alla andra program för STM32F7Discovery. Om du inte vet hur man gör det kan du lĂ€sa om det ). Ett typiskt exempel pĂ„ anvĂ€ndning:.
3: Kompilera bilden med konfigurationen för OpenCV.

    make confload-platform/opencv/stm32f7discovery
    make

4: Utdragning av sektioner frÄn ELF som ska skrivas till 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 finns ett skript som gör detta, sÄ det gÄr att köra det

    ./conf/qspi_objcopy.sh # Den behövda binÀren -- build/base/bin/qspi.bin

5: Med hjÀlp av tftp laddar vi qspi.bin.fill i QSPI-flashminnet. PÄ vÀrden mÄste vi kopiera qspi.bin till rotmappen för tftp-servern (vanligtvis Àr det /srv/tftp/ eller /var/lib/tftpboot/; paketen för motsvarande server finns i de flesta populÀra distributioner, som vanligtvis kallas tftpd eller tftp-hpa, ibland behövs systemctl start tftpd.service för att starta).

    # ĐČĐ°Ń€ĐžĐ°ĐœŃ‚ ĐŽĐ»Ń 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 startprogrammet) mÄste vi köra följande kommando (vi förutsÀtter att serverns adress Àr 192.168.2.1):

    embox> qspi_loader qspi.bin 192.168.2.1

6: Med hjÀlp av kommandot goto mÄste vi "hoppa" in i QSPI-minnet. Den specifika platsen kommer att variera beroende pÄ hur bilden lÀnkas, den hÀr adressen kan visas med kommandot mem 0x90000000 (startadressen ligger i den andra 32-bitars ordet av bilden); du behöver ocksÄ stÀlla in stacken med flaggan -s, stackens adress ligger vid adress 0x90000000, exempel:

    embox>mem 0x90000000
    0x90000000:     0x20023200  0x9000c27f  0x9000c275  0x9000c275
                      ↑           ↑
              detta Àr adressen    detta Àr adressen 
                för stacken        för första
                           instruktionen

    embox>goto -i 0x9000c27f -s 0x20023200 # Flaggan -i behövs för att förhindra avbrott under systeminitiering

7: Vi startar

    embox> edges 20

och njuter av en 40 sekunder lĂ„ng kantdetektering 🙂

Om nĂ„got gĂ„r fel — skriv en issue i vĂ„r repo, eller till e-postlistan embox-devel@googlegroups.com, eller i kommentarerna hĂ€r.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster