OpenCV në STM32F7-Discovery

OpenCV në STM32F7-Discovery Unë jam një nga zhvilluesit e sistemit të operimit Embox, dhe në këtë artikull do të flas për mënyrën se si arrita të aktivizoj OpenCV në pllakën STM32746G.

Nëse shkruani në motorin e kërkimit diçka si 'OpenCV on STM32 board', mund të gjeni mjaft njerëz që janë të interesuar për përdorimin e kësaj biblioteke në pllakat STM32 ose në mikrokontrollera të tjerë.
Ekzistojnë disa video që, sipas titullit, duhet të demonstrojnë atë që duhet, por zakonisht (në të gjitha videoto që kam parë) në pllakën STM32 është kryer vetëm marrja e pamjes nga Kamera dhe shfaqja e rezultatit në ekran, ndërsa vetë përpunimi i imazhit bëhej ose në një kompjuter të zakonshëm, ose në pllaka më të fuqishme (p.sh., Raspberry Pi).

Pse është e vështirë?

Popullariteti i kërkimeve shpjegohet me faktin se OpenCV është biblioteka më popullore e vizionit kompjuterik, dhe kjo do të thotë se shumë më shumë zhvillues janë të njohur me të, dhe mundësia për të aktivizuar kodin e gatshëm për desktop në mikrokontroller e thjeshton ndjeshëm procesin e zhvillimit. Por pse ende nuk ka ndonjë recetë të njohur të gatshme për zgjidhjen e kësaj problemi?

Problemi i përdorimit të OpenCV në pllaka të vogla është i lidhur me dy karakteristika:

  • NĂ«se e kompiloni bibliotekĂ«n madje edhe me njĂ« grup minimal module, nĂ« memorien flash tĂ« po asaj STM32F7Discovery ajo thjesht nuk do tĂ« hyjĂ« (madje pa marrĂ« parasysh OS-nĂ«) pĂ«r shkak tĂ« kodit shumĂ« tĂ« madh (disa megabajt instrukcionesh)
  • Biblioteka vetĂ« Ă«shtĂ« shkruar nĂ« C++, dhe kjo do tĂ« thotĂ«
    • Duhet mbĂ«shtetje pĂ«r runtime-in e C++ (pĂ«rjashtime etj.)
    • Ka pak mbĂ«shtetje LibC/Posix, tĂ« cilat zakonisht janĂ« nĂ« OS-tĂ« pĂ«r sisteme tĂ« integruara — nevojitet biblioteka standarde e C++ dhe biblioteka standarde e templatit STL (vektori etj.)

Portimi në Embox

Si zakonisht, para se tĂ« portoni ndonjĂ« program nĂ« njĂ« sistem operativ, nuk do tĂ« ishte keq tĂ« provoni ta ndĂ«rtoni atĂ« nĂ« formĂ«n qĂ« e kanĂ« menduar zhvilluesit. NĂ« rastin tonĂ« nuk ka probleme me kĂ«tĂ« — burimet mund tĂ« gjenden nĂ« GitHub, biblioteka ndĂ«rtrohet nĂ«n GNU/Linux me cmake tĂ« zakonshĂ«m.

Nga lajmet e mira — OpenCV nga kutia mund tĂ« ndĂ«rtohet nĂ« formĂ«n e njĂ« biblioteke statike, gjĂ« qĂ« e bĂ«n portimin mĂ« tĂ« lehtĂ«. NdĂ«rtojmĂ« bibliotekĂ«n me konfigurimin standard dhe shikojmĂ« sa hapĂ«sirĂ« po zĂ«. Çdo modul ndĂ«rtohet nĂ« njĂ« bibliotekĂ« tĂ« veçantĂ«.

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

Siç duket nga rreshti i fundit, .bss dhe .data nuk zënë aq shumë hapësirë, por ka mbi 70 MiB kod. E qartë është se nëse kjo lidhet statikisht me një aplikacion të caktuar, kodi do të zvogëlohet.

Le të përpiqemi të heqim sa më shumë module që të jetë e mundur, në mënyrë që të krijojmë një shembull minimal (i cili, për shembull, thjesht do të tregojë versionin e OpenCV), kështu që po shohim cmake .. -LA dhe fikim në opsione gjithçka që mund të fiket.

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

Nga njĂ«ra anĂ«, ky Ă«shtĂ« vetĂ«m njĂ« modul i bibliotekĂ«s, nga ana tjetĂ«r, ky Ă«shtĂ« pa optimizimin e kompilerit pĂ«r madhĂ«sinĂ« e kodit (-Os). ~3 MiB kod — kjo Ă«shtĂ« ende e konsiderueshme, por tashmĂ« jep shpresĂ« pĂ«r sukses.

Ekzekutimi në emulator

Në emulator është shumë më e lehtë të bësh debug, prandaj, fillimisht sigurohemi që biblioteka funksionon në qemu. Si platformë e emuluar kam zgjedhur Integrator/CP, sepse, nga njëra anë, është gjithashtu ARM dhe, nga ana tjetër, Embox mbështet daljen grafike për këtë platformë.

Në Embox ka një mekanizëm për ndërtimin e bibliotekave të jashtme, me ndihmën e tij e shtoj OpenCV si modul (duke kaluar të gjithë ato opsione për ndërtimin "minimal" në formën e bibliotekave statike), pas kësaj shtoj një aplikacion të thjeshtë që duket kështu:

version.cpp:

#include 
#include 

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

    return 0;
}

NdĂ«rtojmĂ« sistemin, e ekzekutojmĂ« — dhe marrim rezultatin e pritur.

root@embox:/*opencv_version */
OpenCV: 
Konfigurimi i përgjithshëm për OpenCV 4.0.1 =====================================
  Kontrolli i versionit:               bd6927bdf-dirty

  Platforma:
    Data e kohës:                   2019-06-21T10:02:18Z
    Host:                        Linux 5.1.7-arch1-1-ARCH x86_64
    Objektivi:                      Generic arm-unknown-none
    CMake:                       3.14.5
    Generatori i CMake:             Unix Makefiles
    Instrumenti për ndërtimin e CMake:            /usr/bin/make
    Konfigurimi:               Debug

  Tiparet e CPU/HW:
    Bazë:
      e kërkuar:                 DETECT
      e ndaluar:                  VFPV3 NEON

  C/C++:
    Ndërtuar si biblioteka dinamike?:      JO

Hapi tjetër është të ekzekutoni një shembull, më mirë ndonjë standard nga ata që ofrohen nga vetë zhvilluesit në faqen tuaj. Kam zgjedhur detektor të skajeve Këni.

Shembulli ishte paksa e nevojshme ta rregulloja, pĂ«r tĂ« shfaqur imazhin me rezultatin direkt nĂ« frame-buffer. Duhej ta bĂ«ja kĂ«tĂ«, pasi funksioni imshow() di tĂ« vizatojĂ« imazhe pĂ«rmes interface-ve QT, GTK dhe Windows, tĂ« cilat, natyrisht, nĂ« konfigurimin pĂ«r STM32 nuk do tĂ« jenĂ«. NĂ« tĂ« vĂ«rtetĂ«, QT gjithashtu mund tĂ« ekzekutohet nĂ« STM32F7Discovery, por pĂ«r kĂ«tĂ« do tĂ« flitet nĂ« njĂ« artikull tjetĂ«r 🙂

Pas një sqarimi të shkurtër mbi se në cilin format ruhet rezultati i punës së detektorit të skajeve, marrim imazhin.

OpenCV në STM32F7-Discovery

Imazhi origjinal

OpenCV në STM32F7-Discovery

Rezultati

Ekzekutimi në STM32F7Discovery

Në 32F746GDISCOVERY ka disa seksione të ndryshme të memories që mund t'i përdorim në një mënyrë ose në një tjetër

  1. 320KiB memorie të përkohshme
  2. 1MiB memorie flash për figurën
  3. 8MiB SDRAM
  4. 16MiB QSPI NAND-flash
  5. Priza për kartën microSD

SD-karta mund të përdoret për ruajtjen e imazheve, por në kontekstin e ekzekutimit të një shembulli minimal nuk është shumë e dobishme.
Ekrani ka njĂ« resolutĂ« prej 480×272, dhe kĂ«shtu, memoria pĂ«r frame-buffer do tĂ« ketĂ« 522 240 byte nĂ« thellĂ«si 32 bit, pra kjo Ă«shtĂ« mĂ« shumĂ« se sa sasia e memories sĂ« pĂ«rkohshme, kĂ«shtu qĂ« frame-buffer dhe heaps (tĂ« cilat do tĂ« kĂ«rkohen edhe pĂ«r OpenCV, pĂ«r tĂ« ruajtur tĂ« dhĂ«nat pĂ«r imazhet dhe pĂ«r strukturat ndihmĂ«se) do tĂ« vendosen nĂ« SDRAM, çdo gjĂ« tjetĂ«r (memoria pĂ«r steka dhe nevojat e tjera sistemore) do tĂ« shkojĂ« nĂ« RAM.

Nëse merrni konfigurimin minimal për STM32F7Discovery (hiqni të gjithë rrjetin, të gjitha komandat, bëni stekat sa më të vogla dhe etj.) dhe e shtoni OpenCV me shembuj, kjo do të ishte për sa i përket memories së kërkuar:

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

Për ata që nuk janë shumë të njohur me sekuencat që shkojnë ku, le të shpjegoj: në .text dhe .rodata janë ruajtur instruksionet dhe konstantet (për ta thënë thjesht, të dhënat pa lexim), në .data janë të dhënat e ndryshueshme, në .bss janë variablat "e zeruara", të cilat, megjithatë, kanë nevojë për hapësirë (kjo seksion "do të dërgohet" në RAM).

Lajmi i mirĂ« Ă«shtĂ« se .data/.bss duhen vendosur, por me .text problem — pĂ«r imazhin ka vetĂ«m 1MiB memorie. Mund ta heqim nga .text imazhin e shembujve dhe ta lexojmĂ«, pĂ«r shembull, nga karta SD nĂ« memorie gjatĂ« aktivizimit, por fruits.png ka peshĂ« rreth 330KiB, kĂ«shtu qĂ« kjo problem nuk e zgjidh: pjesa mĂ« e madhe .text pĂ«rbĂ«het pikĂ«risht nga kodi OpenCV.

NĂ« thelb, mbetet vetĂ«m njĂ« zgjidhje — ngarkimi i pjesĂ«s sĂ« kodit nĂ« QSPI-flash (ajo ka njĂ« mod utilizimi tĂ« veçantĂ« pĂ«r mapimin e memories nĂ« autobusin sistemor, kĂ«shtu qĂ« procesori mund t'i qaset kĂ«tyre tĂ« dhĂ«nave direkt). MegjithatĂ«, lind problemi: sĂ« pari, memoria e QSPI-flash nuk Ă«shtĂ« e arritshme menjĂ«herĂ« pas rinisjes sĂ« pajisjes (duhet tĂ« inizializoni veçmas modin e mapeuar tĂ« memories), sĂ« dyti, nuk mund tĂ« "flash" kĂ«tĂ« memorie me boot loader-in e zakonshĂ«m.

Në fund, u vendos të lidhet i gjithë kodi në QSPI, dhe ta flashojmë me një boot loader të shkruar nga vetë, i cili do të merrte binarin e nevojshëm përmes TFTP.

Rezultati

Ideja pĂ«r tĂ« portuar kĂ«tĂ« bibliotekĂ« nĂ« Embox ka lindur rreth njĂ« viti mĂ« parĂ«, por herĂ« pas here Ă«shtĂ« shtyrĂ« pĂ«r shkak tĂ« arsyeve tĂ« ndryshme. NjĂ«ra prej tyre Ă«shtĂ« mbĂ«shtetje pĂ«r libstdc++ dhe standardin e bibliotekave tĂ« templatuara. Problemi i mbĂ«shtetjes C++ nĂ« Embox del pĂ«rtej kĂ«tij artikulli, ndaj kĂ«tu do tĂ« them vetĂ«m se arritĂ«m tĂ« sigurojmĂ« kĂ«tĂ« mbĂ«shtetje nĂ« masĂ«n e nevojshme pĂ«r funksionimin e kĂ«saj biblioteke 🙂

Në fund, këto probleme u kapërcyen (të paktën, në masën e mjaftueshme për funksionimin e shembujve OpenCV), dhe shembulli u aktivizua. 40 sekonda të gjata kërkon blloku për të gjetur kufijtë me filtrin Canny. Kjo, natyrisht, është shumë e gjatë (ka propozime se si ta optimizojmë këtë proces, për këtë mund të shkruajmë një artikull të veçantë në rast suksesi).

OpenCV në STM32F7-Discovery

Megjithatë, qëllimi ndërmjetës ishte krijimi i një prototipi që do të tregonte mundësinë themelore të aktivizimit të OpenCV në STM32, përkatësisht, ky qëllim u arrit, urime!

tl;dr: udhëzim hap pas hapi

0: Shkarkoni burimet e Embox, për shembull kështu:

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

1: Le të fillojmë me ndërtimin e boot loader-it, i cili "do ta flash" QSPI-flash.

    make confload-arm/stm32f7cube

Tani duhet të konfiguroni rrjetin, sepse do ta ngarkojmë imazhin përmes TFTP. Për të caktuar adresat IP të kartës dhe hostit, duhet të modifikoni skedarin conf/rootfs/network.

Shembulli i konfigurimit:

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 — adresa e hostit nga ku do tĂ« ngarkohet imazhi, address — adresa e kartĂ«s.

Pasi të keni bërë këtë, ndjekim krijimin e ngarkuesit:

    make

2: Ngarkimi normal i ngarkuesit (falni pĂ«r lojĂ«n me fjalĂ«) nĂ« kartĂ« — kĂ«tu nuk ka asgjĂ« specifike, duhet bĂ«rĂ« si pĂ«r çdo tjetĂ«r aplikacion pĂ«r STM32F7Discovery. NĂ«se nuk e dini se si bĂ«het, mund tĂ« lexoni pĂ«r kĂ«tĂ« kĂ«tu.
3: Kompilimi i imazhit me konfigurimin për OpenCV.

    make confload-platform/opencv/stm32f7discovery
    make

4: Nxjerrja nga ELF e seksioneve që duhet të shkruhen në QSPI, në 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

Në direktorinë conf ndodhet një skript që e bën këtë, kështu që mund ta filloni atë

    ../conf/qspi_objcopy.sh # Binaries i nevojshëm -- build/base/bin/qspi.bin

5: Me ndihmën e tftp ngarkoni qspi.bin.bin në QSPI-flash. Në host, për këtë duhet të kopjoni qspi.bin në dosjen rrënjësore të serverit tftp (zakonisht është /srv/tftp/ ose /var/lib/tftpboot/; paketat për serverin përkatës janë të disponueshme në shumicën e shpërndarjeve popullore, zakonisht quhen tftpd ose tftp-hpa, ndonjëherë duhet të bëni systemctl start tftpd.service për të filluar).

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

Në Embox (pra, në ngarkues) duhet të ekzekutoni këtë komandë (duke supozuar se adresa e serverit është 192.168.2.1):

    embox> qspi_loader qspi.bin 192.168.2.1

6: Me ndihmën e komandës goto duhet "të hidheni" në memorien QSPI. Lokacioni specifik do të ndryshojë në varësi të mënyrës se si imazhi është lidhur, këtë adresë mund ta shihni me komandën mem 0x90000000 (adresa e fillimit përdoret në fjalën e dytë 32-bit të imazhit); gjithashtu do të kërkohet të vendosni flamurin e stack-ut -s, adresa e stack-ut ndodhet në adresën 0x90000000, shembull:

    embox>mem 0x90000000
    0x90000000:     0x20023200  0x9000c27f  0x9000c275  0x9000c275
                      ↑           ↑
              kjo është adresa    kjo është  adresa 
                e stack-ut        e parë
                           e instrukcionit

    embox>goto -i 0x9000c27f -s 0x20023200 # Flamuri -i është i nevojshëm për të ndaluar ndërprerjet gjatë inicimit të sistemit

7: Nisim

    embox> edges 20

dhe shijoni kĂ«rkimin e kufijve pĂ«r 40 sekonda 🙂

NĂ«se ndodhi ndonjĂ« problem — shkruani njĂ« çështje nĂ« repositori ynĂ«, ose nĂ« listĂ«n e postimeve embox-devel@googlegroups.com, ose nĂ« komentet kĂ«tu.

Burimi: habr.com

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster