Ja sam jedan od programera operativnog sistema
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
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.
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.
originalna slika
rezultat
Radi na STM32F7Discovery
Na 32F746GDISCOVERY postoji nekoliko sekcija hardverske memorije koje možemo koristiti na ovaj ili onaj način
- 320KiB RAM-a
- 1MiB flash za sliku
- 8MiB SDRAM
- 16MiB QSPI NAND Flash
- 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).
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
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
izvor: www.habr.com