Olen yksi käyttöjärjestelmän kehittäjistä
Jos kirjoitat hakukoneeseen esimerkiksi "OpenCV STM32-kortilla", voit löytää useita ihmisiä, jotka ovat kiinnostuneita käyttämään tätä kirjastoa STM32-korteilla tai muilla mikrokontrollereilla.
On olemassa useita videoita, joiden nimestä päätellen pitäisi osoittaa, mitä tarvitaan, mutta yleensä (kaikissa videoissa, jotka näin) STM32-kortilla vain kuva vastaanotettiin kamerasta ja tulos näytettiin näytöllä, ja itse kuvankäsittely tehtiin joko tavallisella tietokoneella tai tehokkaammilla levyillä (esim. Raspberry Pi).
Miksi se on vaikeaa?
Hakukyselyiden suosio selittyy sillä, että OpenCV on suosituin tietokonenäkökirjasto, mikä tarkoittaa, että useammat kehittäjät tuntevat sen, ja kyky ajaa työpöytävalmiutta koodia mikro-ohjaimella yksinkertaistaa kehitysprosessia huomattavasti. Mutta miksi vieläkään ei ole suosittuja valmiita reseptejä tämän ongelman ratkaisemiseksi?
Ongelma OpenCV:n käyttämisessä pienissä huiveissa liittyy kahteen ominaisuuteen:
- Jos käännät kirjaston jopa minimaalisella moduulijoukolla, se ei yksinkertaisesti mahdu saman STM32F7Discoveryn flash-muistiin (edes ottamatta huomioon käyttöjärjestelmää) erittäin suuren koodin vuoksi (useita megatavuja ohjeita)
- Itse kirjasto on kirjoitettu C++:lla, mikä tarkoittaa
- Tarvitsevat tukea positiiviselle suoritusajalle (poikkeukset jne.)
- Pieni tuki LibC/Posixille, jota yleensä löytyy sulautettujen järjestelmien käyttöjärjestelmästä - tarvitset tavallisen plus-kirjaston ja standardin STL-mallikirjaston (vektori jne.)
Siirtäminen Emboxiin
Kuten tavallista, ennen ohjelmien siirtämistä käyttöjärjestelmään, on hyvä idea yrittää rakentaa se siinä muodossa, jossa kehittäjät sen suunnittelivat. Meidän tapauksessamme tässä ei ole ongelmia - lähdekoodi löytyy osoitteesta
Hyvä uutinen on, että OpenCV voidaan rakentaa staattisena kirjastona, joka tekee siirtämisestä helpompaa. Keräämme kirjaston vakiokonfiguraatiolla ja katsomme kuinka paljon tilaa ne vievät. Jokainen moduuli on koottu erilliseen kirjastoon.
> 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)
Kuten viimeiseltä riviltä näet, .bss ja .data eivät vie paljon tilaa, mutta koodi on yli 70 MiB. On selvää, että jos tämä on staattisesti linkitetty tiettyyn sovellukseen, koodista tulee vähemmän.
Yritetään heittää ulos mahdollisimman monta moduulia, jotta kootaan minimaalinen esimerkki (joka esimerkiksi yksinkertaisesti tulostaa OpenCV-version), joten katsomme cmake .. -LA
ja sammuta vaihtoehdoista kaikki, mikä sammuu.
-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)
Toisaalta tämä on vain yksi kirjaston moduuli, toisaalta tämä on ilman kääntäjän optimointia koodin koon (-Os
). ~3 MiB koodia on vielä aika paljon, mutta antaa jo toivoa onnistumisesta.
Suorita emulaattori
On paljon helpompaa tehdä virheenkorjaus emulaattorissa, joten varmista ensin, että kirjasto toimii qemussa. Emuloiduksi alustaksi valitsin Integrator / CP, koska Ensinnäkin se on myös ARM, ja toiseksi Embox tukee tämän alustan grafiikkaa.
Emboxissa on mekanismi ulkoisten kirjastojen rakentamiseen, sen avulla lisäämme OpenCV:n moduuliksi (välitämme kaikki samat vaihtoehdot "minimaaliselle" rakennukselle staattisten kirjastojen muodossa), sen jälkeen lisään yksinkertaisen sovelluksen, joka näyttää tältä:
version.cpp:
#include <stdio.h>
#include <opencv2/core/utility.hpp>
int main() {
printf("OpenCV: %s", cv::getBuildInformation().c_str());
return 0;
}
Kokoamme järjestelmän, käytämme sitä - saamme odotetun tuloksen.
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 включены в сборку и т.п.>
Seuraava askel on suorittaa jokin esimerkki, mieluiten jokin kehittäjien itsensä tarjoamista vakiomalleista.
Esimerkkiä piti kirjoittaa hieman uudelleen, jotta kuva näkyisi tuloksen kanssa suoraan kehyspuskurissa. Minun oli tehtävä tämä, koska. toiminto imshow()
voi piirtää kuvia QT-, GTK- ja Windows-rajapintojen kautta, mikä ei tietenkään ole STM32:n konfiguraatiossa. Itse asiassa QT voidaan suorittaa myös STM32F7Discoveryllä, mutta tästä keskustellaan toisessa artikkelissa 🙂
Lyhyen selvennyksen jälkeen, missä muodossa reunatunnistimen tulos on tallennettu, saadaan kuva.
alkuperäinen kuva
Tulos
Toimii STM32F7Discoveryllä
32F746GDISCOVERYssä on useita laitteistomuistiosioita, joita voimme käyttää tavalla tai toisella
- 320KiB RAM-muistia
- 1 MiB:n salama kuvaa varten
- 8 MiB SDRAM
- 16 MiB QSPI NAND -salama
- microSD-korttipaikka
SD-korttia voidaan käyttää kuvien tallentamiseen, mutta minimaalisen esimerkin yhteydessä tämä ei ole kovin hyödyllistä.
Näytön resoluutio on 480×272, mikä tarkoittaa, että kehyspuskurimuisti tulee olemaan 522 240 tavua 32 bitin syvyydessä, ts. tämä on enemmän kuin RAM-muistin koko, joten kehyspuskuri ja kasa (jotka tarvitaan myös OpenCV:ssä kuvien ja apurakenteiden tietojen tallentamiseen) sijoitetaan SDRAM:iin, kaikki muu (muisti pinoille ja muille järjestelmätarpeille) ) siirtyy RAM-muistiin.
Jos otamme STM32F7Discoveryn vähimmäiskonfiguraation (heitetään pois koko verkko, kaikki komennot, tehdään pinot mahdollisimman pieneksi jne.) ja lisätään siihen esimerkkejä sisältävä OpenCV, tarvittava muisti on seuraava:
text data bss dec hex filename
2876890 459208 312736 3648834 37ad42 build/base/bin/embox
Selitän niille, jotka eivät ole kovin perillä siitä, mitkä osiot menevät minne .text
и .rodata
käskyt ja vakiot (karkeasti sanottuna vain luku -tiedot) ovat sisällä .data
data on muuttuva, .bss
on "nollattuja" muuttujia, jotka kuitenkin tarvitsevat paikan (tämä osio "menee" RAM:iin).
Hyvä uutinen on se .data
/.bss
pitäisi sopia, mutta kanssa .text
Ongelmana on, että kuvalle on vain 1 MiB muistia. Voidaan heittää pois .text
kuva esimerkistä ja lue se esimerkiksi SD-kortilta muistiin käynnistyksen yhteydessä, mutta fruits.png painaa noin 330KiB, joten tämä ei ratkaise ongelmaa: useimmat .text
koostuu OpenCV-koodista.
Yleisesti ottaen on jäljellä vain yksi asia - ladata osan koodista QSPI-flashille (sillä on erityinen toimintatapa muistin yhdistämiseksi järjestelmäväylään, jotta prosessori pääsee suoraan näihin tietoihin). Tässä tapauksessa syntyy ongelma: ensinnäkin QSPI-flash-aseman muisti ei ole käytettävissä heti laitteen uudelleenkäynnistyksen jälkeen (sinun on alustettava muistikartoitettu tila erikseen), ja toiseksi et voi "flash"a tätä muistia tuttu käynnistyslatain.
Tämän seurauksena päätettiin linkittää kaikki koodi QSPI:ssä ja flash se itse kirjoitetulla latauslaitteella, joka vastaanottaa vaaditun binaarin TFTP:n kautta.
Tulos
Ajatus tämän kirjaston siirtämisestä Emboxiin syntyi noin vuosi sitten, mutta kerta toisensa jälkeen sitä lykättiin eri syistä. Yksi niistä on tuki libstdc++:lle ja vakiomallikirjastolle. Emboxin C++-tuen ongelma ei kuulu tämän artikkelin piiriin, joten sanon tässä vain, että onnistuimme saavuttamaan tämän tuen oikean määrän, jotta tämä kirjasto toimisi 🙂
Lopulta nämä ongelmat voitettiin (ainakin tarpeeksi, jotta OpenCV-esimerkki toimisi), ja esimerkki juoksi. Lautalla kestää 40 pitkää sekuntia etsiä rajoja Canny-suodattimen avulla. Tämä on tietysti liian pitkä (on pohdintoja tämän asian optimoinnista, tästä on mahdollista kirjoittaa erillinen artikkeli onnistumisen yhteydessä).
Välitavoitteena oli kuitenkin luoda prototyyppi, joka näyttää perustavanlaatuisen mahdollisuuden käyttää OpenCV:tä STM32:lla, tämä tavoite saavutettiin, hurraa!
tl;dr: vaiheittaiset ohjeet
0: Lataa Embox-lähteitä, kuten tämä:
git clone https://github.com/embox/embox && cd ./embox
1: Aloitetaan kokoamalla käynnistyslatain, joka "vilkkaa" QSPI-flash-aseman.
make confload-arm/stm32f7cube
Nyt sinun on määritettävä verkko, koska. Lataamme kuvan TFTP:n kautta. Jotta voit asettaa kortin ja isännän IP-osoitteet, sinun on muokattava conf/rootfs/network.
Esimerkki kokoonpanosta:
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
- isäntäosoite, josta kuva ladataan, address
- hallituksen osoite.
Tämän jälkeen keräämme käynnistyslataimen:
make
2: Tavallinen käynnistyslataimen lataus (anteeksi sanapeli) laudalla - tässä ei ole mitään erityistä, sinun on tehtävä se kuten minkä tahansa muun STM32F7Discoveryn sovelluksen kohdalla. Jos et tiedä miten se tehdään, voit lukea siitä
3: Kuvan kokoaminen konfiguraatiolla OpenCV:tä varten.
make confload-platform/opencv/stm32f7discovery
make
4: Ote ELF-osioista, jotka kirjoitetaan QSPI:hen qspi.biniin
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
Conf-hakemistossa on komentosarja, joka tekee tämän, joten voit suorittaa sen
./conf/qspi_objcopy.sh # Нужный бинарник -- build/base/bin/qspi.bin
5: Lataa qspi.bin.bin QSPI-muistitikulle tftp:n avulla. Kopioi isännässä tiedosto qspi.bin tftp-palvelimen juurikansioon (yleensä /srv/tftp/ tai /var/lib/tftpboot/; vastaavan palvelimen paketit ovat saatavilla suosituimmissa jakeluissa, yleensä ns. tftpd tai tftp-hpa, joskus sinun on tehtävä systemctl start tftpd.service
aloittaa).
# вариант для tftpd
sudo cp build/base/bin/qspi.bin /srv/tftp
# вариант для tftp-hpa
sudo cp build/base/bin/qspi.bin /var/lib/tftpboot
Emboxissa (eli käynnistyslataimessa) sinun on suoritettava seuraava komento (oletamme, että palvelimen osoite on 192.168.2.1):
embox> qspi_loader qspi.bin 192.168.2.1
6: Komennolla goto
sinun täytyy "hyppää" QSPI-muistiin. Tarkka sijainti vaihtelee sen mukaan, miten kuva on linkitetty, näet tämän osoitteen komennolla mem 0x90000000
(aloitusosoite sopii kuvan toiseen 32-bittiseen sanaan); sinun tulee myös merkitä pino -s
, pinon osoite on 0x90000000, esimerkki:
embox>mem 0x90000000
0x90000000: 0x20023200 0x9000c27f 0x9000c275 0x9000c275
↑ ↑
это адрес это адрес
стэка первой
инструкции
embox>goto -i 0x9000c27f -s 0x20023200 # Флаг -i нужен чтобы запретить прерывания во время инициализации системы
< Начиная отсюда будет вывод не загрузчика, а образа с OpenCV >
7: Käynnistä
embox> edges 20
ja nauti 40 sekunnin rajahausta 🙂
Jos jokin menee pieleen - kirjoita ongelma
Lähde: will.com