Ja sam jedan od programera operativnog sustava
Ako u tražilicu 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 videa koji bi, sudeći po nazivu, trebali demonstrirati što je potrebno, ali obično (u svim videima koje sam vidio) na STM32 ploči samo se prima slika s kamere i rezultat se prikazuje na ekranu, a sama obrada slike radila se ili na običnom računalu, ili na moćnijim pločama (primjerice Raspberry Pi).
Zašto je teško?
Popularnost upita za pretraživanje objašnjava se činjenicom da je OpenCV najpopularnija biblioteka računalnog vida, što znači da je više programera upoznato s njom, a mogućnost pokretanja koda spremnog za desktop na mikrokontroleru uvelike pojednostavljuje razvojni proces. 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 značajke:
- 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 uputa)
- Sama biblioteka je napisana u C++, što znači
- Potrebna podrška za pozitivno vrijeme izvođenja (iznimke, itd.)
- Mala podrška za LibC/Posix, koji se obično nalazi u OS-u za ugrađene sustave - potrebna vam je standardna biblioteka plus i standardna biblioteka STL predložaka (vektor, itd.)
Prijelaz na Embox
Kao i obično, prije prijenosa bilo kojeg programa na operativni sustav, 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 možete pronaći na
Dobra vijest je da se OpenCV može napraviti kao statička biblioteka odmah po korištenju, što olakšava prijenos. Prikupljamo 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 retka, .bss i .data ne zauzimaju puno prostora, ali je kod veći od 70 MiB. Jasno je da ako je ovo statički povezano s određenom aplikacijom, kod će biti manje.
Pokušajmo izbaciti što je više moguće modula tako da se sastavi minimalni primjer (koji će, na primjer, jednostavno ispisati OpenCV verziju), tako da gledamo cmake .. -LA
i isključite u opcijama sve što se isključi.
-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 prevoditelja za veličinu koda (-Os
). ~3 MiB koda je još uvijek dosta, ali već daje nadu za uspjeh.
Pokrenite u emulatoru
Puno je lakše ispravljati pogreške na emulatoru, pa prvo provjerite radi li biblioteka na qemu. Kao emuliranu platformu odabrao sam Integrator / CP, jer prvo, također je ARM, a drugo, Embox podržava grafički izlaz za ovu platformu.
Embox ima mehanizam za izgradnju vanjskih biblioteka, pomoću njega dodajemo OpenCV kao modul (propuštajući sve iste opcije za "minimalnu" izgradnju u obliku statičkih biblioteka), nakon toga dodam 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 sustav, pokrećemo ga - dobivamo 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.
Primjer je morao biti malo prepisan kako bi se slika s rezultatom prikazala izravno u međuspremniku okvira. Morao sam ovo učiniti, jer. funkcija imshow()
može crtati slike kroz QT, GTK i Windows sučelja, što, naravno, definitivno 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 je formatu pohranjen rezultat detektora rubova, dobivamo sliku.
originalna slika
Rezultirati
Radi na STM32F7Discovery
Na 32F746GDISCOVERY postoji nekoliko odjeljaka hardverske memorije koje možemo koristiti na ovaj ili onaj način
- 320KiB RAM
- 1MiB flash za sliku
- 8 MiB SDRAM
- 16MiB QSPI NAND Flash
- utor za microSD karticu
SD kartica se može koristiti za pohranu slika, ali u kontekstu pokretanja minimalnog primjera, to nije baš korisno.
Zaslon ima rezoluciju od 480×272, što znači da će memorija framebuffera biti 522 bajta na dubini od 240 bita, tj. ovo je više od veličine RAM-a, tako da će međuspremnik okvira i gomila (koji će biti potrebni, uključujući i za OpenCV, za pohranu podataka za slike i pomoćne strukture) biti smješteni u SDRAM, sve ostalo (memorija za hrpe i druge potrebe sustava ) će ići u RAM .
Ako uzmemo minimalnu konfiguraciju za STM32F7Discovery (izbacimo cijelu mrežu, sve naredbe, napravimo stogove što je moguće manjim, itd.) i tamo dodamo OpenCV s primjerima, potrebna memorija bit će sljedeća:
text data bss dec hex filename
2876890 459208 312736 3648834 37ad42 build/base/bin/embox
Za one koji nisu baš upoznati s tim koji dijelovi idu gdje, objasnit ću: in .text
и .rodata
upute i konstante (grubo rečeno, podaci samo za čitanje) leže u .data
podaci su promjenjivi, .bss
postoje "nulirane" varijable, koje ipak trebaju mjesto (ovaj odjeljak će "ići" u RAM).
Dobra vijest je da .data
/.bss
trebao bi odgovarati, ali sa .text
problem je što postoji samo 1MiB memorije za sliku. Može se izbaciti .text
sliku iz primjera i pročitajte je, na primjer, sa SD kartice u memoriju pri pokretanju, ali fruits.png teži oko 330KiB, tako da to 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 sabirnicu, tako da procesor može izravno pristupiti tim podacima). U ovom slučaju nastaje problem: prvo, memorija QSPI flash pogona nije dostupna odmah nakon ponovnog pokretanja uređaja (morate posebno inicijalizirati način mapiranja memorije), i drugo, ne možete "bljeskati" ovu memoriju s poznati bootloader.
Kao rezultat toga, odlučeno je da se sav kod poveže u QSPI, i da se flešuje s programom za učitavanje koji je sam napisao i koji će primiti potrebnu binarnu datoteku putem TFTP-a.
Rezultirati
Ideja o prijenosu ove biblioteke na Embox pojavila se prije otprilike godinu dana, ali je uvijek iznova odgađana iz raznih razloga. Jedan od njih je podrška za libstdc++ i standardnu biblioteku predložaka. Problem C++ podrške u Emboxu je izvan okvira ovog članka, pa ću ovdje samo reći da smo uspjeli postići tu podršku u pravoj količini da ova biblioteka radi 🙂
Na kraju su ti problemi prevladani (barem dovoljno da OpenCV primjer radi) i primjer je pokrenut. Ploči je potrebno 40 dugih sekundi da traži granice pomoću Canny filtera. Ovo je, naravno, predugo (ima razmišljanja kako ovu stvar optimizirati, o tome će se u slučaju uspjeha moći napisati poseban članak).
Međutim, srednji cilj je bio stvoriti prototip koji će pokazati temeljnu mogućnost pokretanja OpenCV-a na STM32, odnosno, ovaj cilj je postignut, hura!
tl;dr: upute korak po korak
0: Preuzmite Embox izvore, poput ovog:
git clone https://github.com/embox/embox && cd ./embox
1: Počnimo s sastavljanjem bootloadera koji će "flashati" QSPI flash pogon.
make confload-arm/stm32f7cube
Sada morate konfigurirati mrežu, jer. Sliku ćemo učitati putem TFTP-a. Za postavljanje IP adrese ploče i hosta, trebate 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
- host adresa s koje će se slika učitavati, address
- adresa odbora.
Nakon toga prikupljamo bootloader:
make
2: Uobičajeno učitavanje bootloadera (oprostite na dosjetki) na ploči - ovdje nema ničeg posebnog, 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
3: Sastavljanje slike s konfiguracijom za OpenCV.
make confload-platform/opencv/stm32f7discovery
make
4: Izvadak iz ELF odjeljaka 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
Postoji skripta u conf direktoriju 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 flash pogon. Na glavnom računalu, da biste to učinili, kopirajte qspi.bin u korijensku mapu tftp poslužitelja (obično /srv/tftp/ ili /var/lib/tftpboot/; paketi za odgovarajući poslužitelj dostupni su u većini popularnih distribucija, 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 Emboxu (tj. u bootloaderu) trebate izvršiti sljedeću naredbu (pretpostavljamo da poslužitelj ima adresu 192.168.2.1):
embox> qspi_loader qspi.bin 192.168.2.1
6: Uz naredbu goto
potrebno je "skočiti" u QSPI memoriju. Specifična lokacija će se razlikovati ovisno o tome kako je slika povezana, ovu adresu možete vidjeti pomoću naredbe mem 0x90000000
(početna adresa stane u drugu 32-bitnu riječ slike); također ćete morati označiti stog -s
, adresa steka je 0x90000000, 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 traženju granice od 40 sekundi 🙂
Ako nešto pođe po zlu - upišite problem
Izvor: www.habr.com