Olen üks operatsioonisüsteemi arendajatest
Kui sisestate otsingumootorisse midagi sellist nagu "OpenCV STM32 plaadil", võite leida päris palju inimesi, kes on huvitatud selle teegi kasutamisest STM32 plaatidel või muudel mikrokontrolleritel.
On mitmeid videoid, mis nime järgi otsustades peaksid näitama, mida on vaja, kuid tavaliselt (kõikides videotes, mida nägin) STM32 tahvlil võeti kaamerast vastu ainult pilt ja tulemus kuvati ekraanil, ja pilditöötlus ise toimus kas tavalisel arvutil, või võimsamatel tahvlitel (näiteks Raspberry Pi).
Miks on see keeruline?
Otsingupäringute populaarsust seletatakse sellega, et OpenCV on kõige populaarsem arvutinägemise teek, mis tähendab, et sellega on tuttavad rohkem arendajad ning võimalus käivitada mikrokontrolleris töölauale sobivat koodi lihtsustab arendusprotsessi oluliselt. Kuid miks pole endiselt populaarseid valmisretsepte selle probleemi lahendamiseks?
OpenCV kasutamise probleem väikestel suurrätikutel on seotud kahe funktsiooniga:
- Kui koostate raamatukogu isegi minimaalse moodulite komplektiga, ei mahu see väga suure koodi (mitu megabaiti juhiseid) tõttu lihtsalt sama STM32F7Discovery välkmällu (isegi ilma operatsioonisüsteemi arvesse võtmata)
- Teek ise on kirjutatud C++ keeles, mis tähendab
- Vajab positiivse käitusaja tuge (erandid jne)
- Väike tugi LibC/Posixi jaoks, mida tavaliselt leidub manustatud süsteemide OS-is – vajate tavalist plussteeki ja standardset STL-i malliteeki (vektor jne).
Emboxi teisaldamine
Nagu tavaliselt, on enne mis tahes programmide teisaldamist operatsioonisüsteemi hea mõte proovida see ehitada sellisel kujul, nagu arendajad selle kavandasid. Meie puhul pole sellega probleeme - lähtekoodi leiate aadressilt
Hea uudis on see, et OpenCV saab karbist välja ehitada staatilise raamatukoguna, mis muudab teisaldamise lihtsamaks. Kogume standardse konfiguratsiooniga raamatukogu ja vaatame, kui palju ruumi need võtavad. Iga moodul on kogutud eraldi teeki.
> 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)
Nagu viimaselt realt näha, ei võta .bss ja .data palju ruumi, kuid kood on üle 70 MiB. On selge, et kui see on staatiliselt seotud konkreetse rakendusega, väheneb kood.
Proovime võimalikult palju mooduleid välja visata, et oleks kokku pandud minimaalne näide (mis näiteks lihtsalt väljastab OpenCV versiooni), nii et vaatame cmake .. -LA
ja lülitage valikutes välja kõik, mis lülitub välja.
-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)
Ühest küljest on see ainult üks teegi moodul, teisest küljest on see ilma kompilaatori optimeerimiseta koodi suuruse jaoks (-Os
). ~3 MiB koodi on ikka päris palju, aga annab juba lootust edule.
Käivitage emulaatoris
Emulaatoris on silumine palju lihtsam, seega veendu esmalt, et teek qemu puhul töötab. Emuleeritud platvormina valisin Integrator / CP, kuna esiteks on see ka ARM ja teiseks toetab Embox selle platvormi graafikaväljundit.
Emboxil on mehhanism väliste teekide loomiseks, seda kasutades lisame moodulina OpenCV (edastades kõik samad valikud "minimaalse" ehitamise jaoks staatiliste teekide kujul), pärast seda lisan lihtsa rakenduse, mis näeb välja selline:
version.cpp:
#include <stdio.h>
#include <opencv2/core/utility.hpp>
int main() {
printf("OpenCV: %s", cv::getBuildInformation().c_str());
return 0;
}
Me paneme süsteemi kokku, käivitame selle - saame oodatud väljundi.
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 включены в сборку и т.п.>
Järgmine samm on käivitada mõni näide, eelistatavalt mõni arendajate endi pakutavatest standardsetest.
Näidet tuli veidi ümber kirjutada, et kuvada pilt koos tulemusega otse kaadripuhvris. Ma pidin seda tegema, sest. funktsiooni imshow()
saab joonistada pilte läbi QT, GTK ja Windowsi liideste, mida STM32 konfiguratsioonis muidugi kindlasti ei ole. Tegelikult saab QT-d käivitada ka STM32F7Discovery abil, kuid sellest tuleb juttu teises artiklis 🙂
Pärast lühikest selgitust, millises formaadis servadetektori tulemus salvestatakse, saame pildi.
originaal pilt
Tulemus
Töötab STM32F7Discoveryga
Seadmel 32F746GDISCOVERY on mitu riistvaramälu sektsiooni, mida saame ühel või teisel viisil kasutada
- 320KiB RAM
- 1 MB välklamp pildi jaoks
- 8 MiB SDRAM
- 16 MiB QSPI NAND välklamp
- microSD-kaardi pesa
SD-kaarti saab kasutada piltide salvestamiseks, kuid minimaalse näite käivitamise kontekstis pole see eriti kasulik.
Ekraani eraldusvõime on 480×272, mis tähendab, et kaadripuhvri mälu saab olema 522 240 baiti 32 biti sügavusel, s.o. see on rohkem kui RAM-i suurus, nii et kaadripuhver ja hunnik (mida on vaja, sealhulgas OpenCV jaoks piltide ja abistruktuuride andmete salvestamiseks) asuvad SDRAM-is, kõik muu (mälu virnade ja muude süsteemi vajaduste jaoks ) läheb RAM-i.
Kui võtta STM32F7Discovery jaoks minimaalne konfiguratsioon (visata välja kogu võrk, kõik käsud, teha virnad võimalikult väikseks jne) ja lisada sinna OpenCV koos näidetega, on vajalik mälu järgmine:
text data bss dec hex filename
2876890 459208 312736 3648834 37ad42 build/base/bin/embox
Neile, kes pole väga kursis, millised jaotised kuhu lähevad, selgitan: sisse .text
и .rodata
juhised ja konstandid (jämedalt öeldes kirjutuskaitstud andmed) peituvad .data
andmed on muutlikud, .bss
on "nulleeritud" muutujaid, mis siiski vajavad kohta (see jaotis "läheb" RAM-i).
Hea uudis on see .data
/.bss
peaks sobima, aga koos .text
häda on selles, et pildi jaoks on ainult 1MiB mälu. Võib välja visata .text
pilti näitest ja lugege see näiteks SD-kaardilt käivitamisel mällu, kuid fruits.png kaalub umbes 330KiB, nii et see probleemi ei lahenda: enamik .text
koosneb OpenCV koodist.
Laias laastus jääb üle vaid üks - osa koodi laadimine QSPI-välklampe (sellel on spetsiaalne töörežiim mälu kaardistamiseks süsteemisiiniga, et protsessor saaks nendele andmetele otse ligi). Sel juhul tekib probleem: esiteks pole QSPI-mälupulga mälu kohe pärast seadme taaskäivitamist saadaval (peate mälukaardistatud režiimi eraldi initsialiseerima) ja teiseks ei saa te seda mälu "välkutada" tuttav alglaadur.
Selle tulemusena otsustati linkida kogu kood QSPI-s ja flashida ise kirjutatud laadijaga, mis saab vajaliku binaarfaili TFTP kaudu.
Tulemus
Idee see teek Emboxi portida tekkis umbes aasta tagasi, kuid ikka ja jälle lükkus see erinevatel põhjustel edasi. Üks neist on libstdc++ ja standardse malliteegi tugi. Emboxi C++ toe probleem jääb sellest artiklist välja, nii et siinkohal ütlen vaid, et meil õnnestus see tugi saavutada õiges mahus, et see teegi toimiks 🙂
Lõpuks saadi need probleemid üle (vähemalt piisavalt, et OpenCV näide töötaks) ja näide jooksis. Tahvlil kulub Canny filtri abil piiride otsimiseks 40 pikka sekundit. See on muidugi liiga pikk (seal on kaalutlusi, kuidas seda asja optimeerida, edu korral on võimalik sellest eraldi artikkel kirjutada).
Vaheeesmärk oli aga luua prototüüp, mis näitaks põhimõttelist võimalust OpenCV käivitamiseks vastavalt STM32 peal, see eesmärk sai täidetud, hurraa!
tl;dr: samm-sammult juhised
0: laadige alla Emboxi allikad, näiteks:
git clone https://github.com/embox/embox && cd ./embox
1: Alustame alglaaduri kokkupanemisest, mis "vilgub" QSPI-mälupulgale.
make confload-arm/stm32f7cube
Nüüd peate võrgu konfigureerima, kuna. Laadime pildi üles TFTP kaudu. Tahvli ja hosti IP-aadresside määramiseks peate redigeerima faili conf/rootfs/network.
Konfiguratsiooni näide:
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
- hosti aadress, kust pilt laaditakse, address
- juhatuse aadress.
Pärast seda kogume alglaaduri:
make
2: Tavaline alglaaduri laadimine (vabandan sõnamängu pärast) tahvlil - siin pole midagi konkreetset, peate seda tegema nagu iga muu STM32F7Discovery rakenduse puhul. Kui te ei tea, kuidas seda teha, võite selle kohta lugeda
3: OpenCV konfiguratsiooniga pildi koostamine.
make confload-platform/opencv/stm32f7discovery
make
4: väljavõte ELF-i sektsioonidest, mis kirjutatakse QSPI-sse faili 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
Conf kataloogis on skript, mis seda teeb, nii et saate seda käivitada
./conf/qspi_objcopy.sh # Нужный бинарник -- build/base/bin/qspi.bin
5: tftp abil laadige qspi.bin.bin alla QSPI-mälupulgale. Selleks kopeerige hostis qspi.bin tftp-serveri juurkausta (tavaliselt /srv/tftp/ või /var/lib/tftpboot/; vastava serveri paketid on saadaval enamikes populaarsetes distributsioonides, tavaliselt nn. tftpd või tftp-hpa, mõnikord peate seda tegema systemctl start tftpd.service
alustama).
# вариант для tftpd
sudo cp build/base/bin/qspi.bin /srv/tftp
# вариант для tftp-hpa
sudo cp build/base/bin/qspi.bin /var/lib/tftpboot
Emboxis (st alglaaduris) peate täitma järgmise käsu (oletame, et serveri aadress on 192.168.2.1):
embox> qspi_loader qspi.bin 192.168.2.1
6: käsuga goto
peate "hüppama" QSPI mällu. Konkreetne asukoht varieerub sõltuvalt sellest, kuidas pilt on lingitud, näete seda aadressi käsuga mem 0x90000000
(algusaadress mahub pildi teise 32-bitise sõna sisse); peate ka virna märgistama -s
, virna aadress on 0x90000000, näiteks:
embox>mem 0x90000000
0x90000000: 0x20023200 0x9000c27f 0x9000c275 0x9000c275
↑ ↑
это адрес это адрес
стэка первой
инструкции
embox>goto -i 0x9000c27f -s 0x20023200 # Флаг -i нужен чтобы запретить прерывания во время инициализации системы
< Начиная отсюда будет вывод не загрузчика, а образа с OpenCV >
7: Käivitage
embox> edges 20
ja naudi 40-sekundilist piiriotsingut 🙂
Kui midagi läheb valesti, kirjutage probleem
Allikas: www.habr.com