OpenCV na STM32F7-Discovery

OpenCV na STM32F7-Discovery Ja sam jedan od programera operativnog sistema Embox, a u ovom članku ću govoriti o tome kako sam uspio pokrenuti OpenCV na STM32746G ploči.

Ako u pretraživač upišete nešto poput "OpenCV na STM32 ploči", možete pronaći dosta ljudi koji su zainteresirani za korištenje ove biblioteke na STM32 pločama ili drugim mikrokontrolerima.
Postoji nekoliko video zapisa koji bi, sudeći po nazivu, trebali pokazati šta je potrebno, ali obično (u svim video zapisima koje sam vidio) na ploči STM32 samo je slika primljena sa kamere i rezultat je prikazan na ekranu, a sama obrada slike rađena je ili na običnom računaru, ili na snažnijim pločama (na primjer Raspberry Pi).

Zašto je teško?

Popularnost upita za pretraživanje objašnjava se činjenicom da je OpenCV najpopularnija biblioteka kompjuterskog vida, što znači da je više programera upoznato s njom, a mogućnost pokretanja koda spremnog za radnu površinu na mikrokontroleru uvelike pojednostavljuje proces razvoja. Ali zašto još uvijek nema popularnih gotovih recepata za rješavanje ovog problema?

Problem korištenja OpenCV-a na malim šalovima povezan je s dvije karakteristike:

  • Ako kompajlirate biblioteku čak i s minimalnim skupom modula, ona jednostavno neće stati u flash memoriju istog STM32F7Discovery (čak i bez uzimanja u obzir OS) zbog vrlo velikog koda (nekoliko megabajta instrukcija)
  • Sama biblioteka je napisana u C++, što znači
    • Potrebna je podrška za pozitivno vrijeme rada (izuzeci, itd.)
    • Mala podrška za LibC/Posix, koja se obično nalazi u OS-u za ugrađene sisteme - potrebna vam je standardna plus biblioteka i standardna biblioteka STL šablona (vektor, itd.)

Portiranje u Embox

Kao i obično, prije nego što prenesete bilo koji program na operativni sistem, dobra je ideja pokušati ga izgraditi u obliku u kojem su ga programeri zamislili. U našem slučaju s tim nema problema - izvorni kod se može naći na github, biblioteka je izgrađena pod GNU/Linuxom sa uobičajenim cmakeom.

Dobra vest je da OpenCV može biti napravljen kao statična biblioteka iz kutije, što olakšava prenos. Sakupljamo biblioteku sa standardnom konfiguracijom i vidimo koliko prostora zauzimaju. Svaki modul se prikuplja u zasebnoj biblioteci.

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

Kao što možete vidjeti iz posljednjeg reda, .bss i .data ne zauzimaju puno prostora, ali kod je veći od 70 MiB. Jasno je da ako se ovo statički poveže sa određenom aplikacijom, kod će postati manji.

Pokušajmo izbaciti što više modula kako bi se sastavio minimalni primjer (koji će, na primjer, jednostavno izbaciti OpenCV verziju), pa pogledamo cmake .. -LA i isključite u opcijama sve što se isključuje.

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

S jedne strane, ovo je samo jedan modul biblioteke, s druge strane, ovo je bez optimizacije kompajlera za veličinu koda (-Os). ~3 MiB koda je još uvijek dosta, ali već daje nadu za uspjeh.

Pokrenite u emulatoru

Mnogo je lakše otkloniti greške na emulatoru, pa se prvo uvjerite da biblioteka radi na qemu-u. Kao emuliranu platformu, izabrao sam Integrator / CP, jer prvo, takođe je ARM, a drugo, Embox podržava grafički izlaz za ovu platformu.

Embox ima mehanizam za izgradnju eksternih biblioteka, pomoću njega dodajemo OpenCV kao modul (propuštajući sve iste opcije za "minimalni" build u obliku statičkih biblioteka), nakon toga dodajem jednostavnu aplikaciju koja izgleda ovako:

version.cpp:

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

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

    return 0;
}

Sastavljamo sistem, pokrećemo ga - dobijamo očekivani rezultat.

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 включены в сборку и т.п.>

Sljedeći korak je pokretanje nekog primjera, po mogućnosti jednog od standardnih koje nude sami programeri. na vašem sajtu. ja biram granični detektor canny.

Primer je morao biti malo prepisan da bi se slika sa rezultatom prikazala direktno u baferu okvira. Morao sam ovo da uradim, jer. funkcija imshow() može crtati slike kroz QT, GTK i Windows interfejse, što, naravno, sigurno neće biti u konfiguraciji za STM32. Zapravo, QT se također može pokrenuti na STM32F7Discovery, ali o tome će biti riječi u drugom članku 🙂

Nakon kratkog pojašnjenja u kojem formatu je pohranjen rezultat detektora ivica, dobijamo sliku.

OpenCV na STM32F7-Discovery

originalna slika

OpenCV na STM32F7-Discovery

rezultat

Radi na STM32F7Discovery

Na 32F746GDISCOVERY postoji nekoliko sekcija hardverske memorije koje možemo koristiti na ovaj ili onaj način

  1. 320KiB RAM-a
  2. 1MiB flash za sliku
  3. 8MiB SDRAM
  4. 16MiB QSPI NAND Flash
  5. slot za microSD karticu

SD kartica se može koristiti za pohranjivanje slika, ali u kontekstu pokretanja minimalnog primjera, to nije od velike koristi.
Ekran ima rezoluciju 480×272, što znači da će framebuffer memorija biti 522 bajtova na dubini od 240 bita, tj. ovo je više od veličine RAM-a, tako da će framebuffer i hrpa (koji će biti potrebni, uključujući i OpenCV, za pohranjivanje podataka za slike i pomoćne strukture) biti smješteni u SDRAM, sve ostalo (memorija za stekove i druge sistemske potrebe ) će ići u RAM.

Ako uzmemo minimalnu konfiguraciju za STM32F7Discovery (izbacimo cijelu mrežu, sve naredbe, napravimo stogove što je moguće manje, itd.) i dodamo OpenCV sa primjerima tamo, potrebna memorija će biti sljedeća:

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

Za one koji nisu baš upoznati sa tim koji delovi gde idu, objasniću: u .text и .rodata instrukcije i konstante (grubo govoreći, podaci samo za čitanje) leže u njima .data podaci su promjenjivi, .bss postoje "nulled" varijable, kojima je, ipak, potrebno mjesto (ovaj dio će "ići" u RAM).

Dobra vijest je ta .data/.bss trebalo bi da odgovara, ali sa .text problem je što postoji samo 1MiB memorije za sliku. Može se izbaciti .text sliku iz primjera i pročitajte je npr. sa SD kartice u memoriju pri pokretanju, ali fruits.png teži oko 330KiB, tako da ovo neće riješiti problem: većina .text sastoji se od OpenCV koda.

Uglavnom, preostaje samo jedno - učitavanje dijela koda na QSPI flash (ima poseban način rada za mapiranje memorije na sistemsku magistralu, tako da procesor može direktno pristupiti ovim podacima). U ovom slučaju nastaje problem: prvo, memorija QSPI fleš diska nije dostupna odmah nakon ponovnog pokretanja uređaja (morate posebno inicijalizirati memorijski mapirani način), a drugo, ne možete "flešovati" ovu memoriju sa poznati bootloader.

Kao rezultat toga, odlučeno je da se poveže sav kod u QSPI, i flešuje ga samopisanim učitavačem koji će primati potrebnu binarnu datoteku putem TFTP-a.

rezultat

Ideja da se ova biblioteka prenese u Embox pojavila se prije otprilike godinu dana, ali je uvijek iznova odlagana iz raznih razloga. Jedna od njih je podrška za libstdc++ i standardnu ​​biblioteku šablona. Problem podrške za C++ u Emboxu je izvan okvira ovog članka, pa ću ovdje samo reći da smo uspjeli ostvariti ovu podršku u pravoj količini da ova biblioteka radi 🙂

Na kraju, ovi problemi su prevaziđeni (barem dovoljno da OpenCV primjer radi), a primjer je pokrenut. Potrebno je 40 dugih sekundi da ploča traži granice koristeći Canny filter. Ovo je, naravno, predugo (postoji razmatranje kako optimizirati ovu materiju, o tome će biti moguće napisati poseban članak u slučaju uspjeha).

OpenCV na STM32F7-Discovery

Međutim, međucilj je bio kreiranje prototipa koji će pokazati fundamentalnu mogućnost pokretanja OpenCV-a na STM32, odnosno ovaj cilj je postignut, ura!

tl;dr: upute korak po korak

0: Preuzmite Embox izvore, ovako:

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

1: Počnimo sa sklapanjem bootloadera koji će "flešovati" QSPI fleš disk.

    make confload-arm/stm32f7cube

Sada trebate konfigurirati mrežu, jer. Sliku ćemo učitati putem TFTP-a. Da biste postavili IP adrese ploče i hosta, morate urediti conf/rootfs/network.

Primjer konfiguracije:

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 - adresu domaćina sa koje će se slika učitati, address - adresa odbora.

Nakon toga prikupljamo bootloader:

    make

2: Uobičajeno učitavanje bootloader-a (izvinite na igri riječi) na ploči - ovdje nema ništa specifično, morate to učiniti kao i za bilo koju drugu aplikaciju za STM32F7Discovery. Ako ne znate kako to učiniti, možete pročitati o tome ovdje.
3: Kompajliranje slike sa konfiguracijom za OpenCV.

    make confload-platform/opencv/stm32f7discovery
    make

4: Izvod iz ELF sekcija za pisanje u QSPI u 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

U direktoriju conf postoji skripta koja to radi, tako da je možete pokrenuti

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

5: Koristeći tftp, preuzmite qspi.bin.bin na QSPI fleš disk. Na hostu, da biste to učinili, kopirajte qspi.bin u korijenski folder tftp servera (obično /srv/tftp/ ili /var/lib/tftpboot/; paketi za odgovarajući server su dostupni u najpopularnijim distribucijama, obično se nazivaju tftpd ili tftp-hpa, ponekad morate učiniti systemctl start tftpd.service početi).

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

Na Embox-u (tj. u bootloaderu) morate izvršiti sljedeću naredbu (pretpostavljamo da server ima adresu 192.168.2.1):

    embox> qspi_loader qspi.bin 192.168.2.1

6: Sa komandom goto morate "skočiti" u QSPI memoriju. Konkretna lokacija će se razlikovati ovisno o tome kako je slika povezana, ovu adresu možete vidjeti pomoću naredbe mem 0x90000000 (početna adresa se uklapa u drugu 32-bitnu riječ slike); također ćete morati označiti stek -s, adresa steka je na 0x90000000, na primjer:

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

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

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

7: Lansiranje

    embox> edges 20

i uživajte u pretrazi granice od 40 sekundi 🙂

Ako nešto krene po zlu - napišite problem naše skladište, ili na mailing listu [email zaštićen], ili u komentaru ovdje.

izvor: www.habr.com

Dodajte komentar