Saya adalah salah satu pengembang sistem operasi
Jika Anda mengetikkan sesuatu seperti "OpenCV pada papan STM32" ke dalam mesin pencari, Anda dapat menemukan beberapa orang yang tertarik untuk menggunakan pustaka ini pada papan STM32 atau mikrokontroler lainnya.
Ada beberapa video yang, dilihat dari namanya, harus menunjukkan apa yang dibutuhkan, tetapi biasanya (di semua video yang saya lihat) di papan STM32, hanya gambar yang diterima dari kamera dan hasilnya ditampilkan di layar, dan pemrosesan gambar itu sendiri dilakukan di komputer biasa, atau di papan yang lebih kuat (misalnya, Raspberry Pi).
Mengapa sulit?
Popularitas kueri penelusuran dijelaskan oleh fakta bahwa OpenCV adalah pustaka visi komputer paling populer, yang berarti lebih banyak pengembang yang mengetahuinya, dan kemampuan untuk menjalankan kode siap-desktop pada mikrokontroler sangat menyederhanakan proses pengembangan. Tapi mengapa masih belum ada resep siap pakai yang populer untuk mengatasi masalah ini?
Masalah menggunakan OpenCV pada syal kecil terkait dengan dua fitur:
- Jika Anda mengkompilasi perpustakaan bahkan dengan set modul minimal, itu tidak akan cocok dengan memori flash dari STM32F7Discovery yang sama (bahkan tanpa memperhitungkan OS) karena kode yang sangat besar (beberapa megabyte instruksi)
- Perpustakaan itu sendiri ditulis dalam C++, yang artinya
- Butuh dukungan untuk runtime positif (pengecualian, dll.)
- Sedikit dukungan untuk LibC/Posix, yang biasanya ditemukan di OS untuk sistem tersemat - Anda memerlukan pustaka standar plus dan pustaka templat STL standar (vektor, dll.)
Porting ke Embox
Seperti biasa, sebelum mem-porting program apa pun ke sistem operasi, ada baiknya mencoba membuatnya dalam bentuk yang diinginkan pengembang. Dalam kasus kami, tidak ada masalah dengan ini - kode sumber dapat ditemukan di
Kabar baiknya adalah bahwa OpenCV dapat dibangun sebagai perpustakaan statis di luar kotak, yang membuat porting menjadi lebih mudah. Kami mengumpulkan perpustakaan dengan konfigurasi standar dan melihat berapa banyak ruang yang mereka gunakan. Setiap modul dikumpulkan di perpustakaan terpisah.
> 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)
Seperti yang Anda lihat dari baris terakhir, .bss dan .data tidak memakan banyak ruang, tetapi kodenya lebih dari 70 MiB. Jelas bahwa jika ini ditautkan secara statis ke aplikasi tertentu, kodenya akan menjadi lebih sedikit.
Mari kita coba membuang modul sebanyak mungkin sehingga contoh minimal dirakit (yang, misalnya, hanya menampilkan versi OpenCV), jadi kita lihat cmake .. -LA
dan matikan di opsi semua yang mati.
-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)
Di satu sisi, ini hanya satu modul perpustakaan, di sisi lain, ini tanpa pengoptimalan kompiler untuk ukuran kode (-Os
). Kode ~3 MiB masih cukup banyak, tapi sudah memberi harapan untuk sukses.
Jalankan di emulator
Jauh lebih mudah untuk melakukan debug pada emulator, jadi pertama-tama pastikan pustaka berfungsi pada qemu. Sebagai platform emulasi, saya memilih Integrator/CP, karena pertama, ini juga ARM, dan kedua, Embox mendukung keluaran grafis untuk platform ini.
Embox memiliki mekanisme untuk membangun perpustakaan eksternal, menggunakannya kami menambahkan OpenCV sebagai modul (melewati semua opsi yang sama untuk build "minimal" dalam bentuk perpustakaan statis), setelah itu saya menambahkan aplikasi sederhana yang terlihat seperti ini:
version.cpp:
#include <stdio.h>
#include <opencv2/core/utility.hpp>
int main() {
printf("OpenCV: %s", cv::getBuildInformation().c_str());
return 0;
}
Kami merakit sistem, menjalankannya - kami mendapatkan hasil yang diharapkan.
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 Π²ΠΊΠ»ΡΡΠ΅Π½Ρ Π² ΡΠ±ΠΎΡΠΊΡ ΠΈ Ρ.ΠΏ.>
Langkah selanjutnya adalah menjalankan beberapa contoh, sebaiknya salah satu contoh standar yang ditawarkan oleh pengembang sendiri.
Contoh harus sedikit ditulis ulang untuk menampilkan gambar dengan hasilnya langsung di buffer bingkai. Saya harus melakukan ini, karena. fungsi imshow()
dapat menggambar gambar melalui antarmuka QT, GTK dan Windows, yang tentunya tidak akan ada dalam konfigurasi untuk STM32. Sebenarnya QT juga bisa dijalankan di STM32F7Discovery, tapi ini akan dibahas di artikel lain π
Setelah klarifikasi singkat di mana format hasil detektor tepi disimpan, kami mendapatkan gambar.
gambar asli
Hasil
Berjalan di STM32F7Discovery
Pada 32F746GDISCOVERY ada beberapa bagian memori perangkat keras yang dapat kita gunakan dengan satu atau lain cara
- RAM 320KiB
- Flash 1MiB untuk gambar
- SDRAM 8MiB
- Flash NAND QSPI 16MiB
- slot kartu microSD
Kartu SD dapat digunakan untuk menyimpan gambar, tetapi dalam konteks menjalankan contoh minimal, ini tidak terlalu berguna.
Layar memiliki resolusi 480Γ272, yang berarti memori framebuffer akan berukuran 522 byte pada kedalaman 240 bit, mis. ini lebih dari ukuran RAM, jadi framebuffer dan heap (yang akan diperlukan, termasuk untuk OpenCV, untuk menyimpan data untuk gambar dan struktur tambahan) akan ditempatkan di SDRAM, yang lainnya (memori untuk tumpukan dan kebutuhan sistem lainnya ) akan masuk ke RAM .
Jika kami mengambil konfigurasi minimum untuk STM32F7Discovery (membuang seluruh jaringan, semua perintah, membuat tumpukan sekecil mungkin, dll.) Dan menambahkan OpenCV dengan contoh di sana, memori yang diperlukan adalah sebagai berikut:
text data bss dec hex filename
2876890 459208 312736 3648834 37ad42 build/base/bin/embox
Bagi mereka yang tidak begitu paham dengan bagian mana pergi ke mana, saya akan menjelaskan: di .text
ΠΈ .rodata
instruksi dan konstanta (secara kasar, data hanya baca) ada di .data
data dapat berubah, .bss
ada variabel "nulled", yang, bagaimanapun, membutuhkan tempat (bagian ini akan "masuk" ke RAM).
Kabar baiknya adalah .data
/.bss
harus pas, tapi dengan .text
masalahnya adalah hanya ada 1MiB memori untuk gambar tersebut. Bisa dibuang .text
gambar dari contoh dan membacanya, misalnya dari kartu SD ke dalam memori saat startup, tetapi berat fruit.png sekitar 330KiB, jadi ini tidak akan menyelesaikan masalah: sebagian besar .text
terdiri dari kode OpenCV.
Pada umumnya, hanya ada satu hal yang tersisa - memuat sebagian kode ke flash QSPI (memiliki mode operasi khusus untuk memetakan memori ke bus sistem, sehingga prosesor dapat mengakses data ini secara langsung). Dalam hal ini, muncul masalah: pertama, memori flash drive QSPI tidak tersedia segera setelah perangkat di-boot ulang (Anda perlu menginisialisasi mode pemetaan memori secara terpisah), dan kedua, Anda tidak dapat "mem-flash" memori ini dengan bootloader yang sudah dikenal.
Akibatnya, diputuskan untuk menautkan semua kode di QSPI, dan mem-flash-nya dengan loader yang ditulis sendiri yang akan menerima biner yang diperlukan melalui TFTP.
Hasil
Ide untuk mem-port library ini ke Embox muncul sekitar setahun yang lalu, namun berulang kali ditunda karena berbagai alasan. Salah satunya adalah dukungan untuk libstdc++ dan pustaka template standar. Masalah dukungan C++ di Embox berada di luar cakupan artikel ini, jadi di sini saya hanya akan mengatakan bahwa kami berhasil mencapai dukungan ini dalam jumlah yang tepat agar pustaka ini berfungsi π
Pada akhirnya, masalah ini teratasi (setidaknya cukup untuk membuat contoh OpenCV), dan contoh berjalan. Butuh waktu 40 detik bagi papan untuk mencari batas menggunakan filter Canny. Ini, tentu saja, terlalu lama (ada pertimbangan tentang cara mengoptimalkan masalah ini, akan memungkinkan untuk menulis artikel terpisah tentang ini jika berhasil).
Namun, tujuan antara adalah untuk membuat prototipe yang akan menunjukkan kemungkinan mendasar menjalankan OpenCV di STM32, masing-masing, tujuan ini tercapai, hore!
tl;dr: petunjuk langkah demi langkah
0: Unduh sumber Embox, seperti ini:
git clone https://github.com/embox/embox && cd ./embox
1: Mari kita mulai dengan merakit bootloader yang akan "mem-flash" flash drive QSPI.
make confload-arm/stm32f7cube
Sekarang Anda perlu mengkonfigurasi jaringan, karena. Kami akan mengunggah gambar melalui TFTP. Untuk mengatur alamat IP board dan host, Anda perlu mengedit file conf/rootfs/network.
Contoh konfigurasi:
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
- alamat host tempat gambar akan dimuat, address
- alamat dewan.
Setelah itu, kami mengumpulkan bootloader:
make
2: Pemuatan bootloader yang biasa (maaf untuk permainan kata-kata) di papan tulis - tidak ada yang spesifik di sini, Anda perlu melakukannya seperti aplikasi lain untuk STM32F7Discovery. Jika Anda tidak tahu bagaimana melakukannya, Anda dapat membacanya
3: Mengkompilasi gambar dengan konfigurasi untuk OpenCV.
make confload-platform/opencv/stm32f7discovery
make
4: Ekstrak dari bagian ELF untuk ditulis ke QSPI ke 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
Ada skrip di direktori conf yang melakukan ini, jadi Anda bisa menjalankannya
./conf/qspi_objcopy.sh # ΠΡΠΆΠ½ΡΠΉ Π±ΠΈΠ½Π°ΡΠ½ΠΈΠΊ -- build/base/bin/qspi.bin
5: Menggunakan tftp, unduh qspi.bin.bin ke flash drive QSPI. Di host, untuk melakukan ini, salin qspi.bin ke folder root server tftp (biasanya /srv/tftp/ atau /var/lib/tftpboot/; paket untuk server terkait tersedia di sebagian besar distribusi populer, biasanya disebut tftpd atau tftp-hpa, terkadang Anda harus melakukannya systemctl start tftpd.service
untuk memulai).
# Π²Π°ΡΠΈΠ°Π½Ρ Π΄Π»Ρ tftpd
sudo cp build/base/bin/qspi.bin /srv/tftp
# Π²Π°ΡΠΈΠ°Π½Ρ Π΄Π»Ρ tftp-hpa
sudo cp build/base/bin/qspi.bin /var/lib/tftpboot
Di Embox (yaitu di bootloader), Anda perlu menjalankan perintah berikut (kami berasumsi bahwa server memiliki alamat 192.168.2.1):
embox> qspi_loader qspi.bin 192.168.2.1
6: Dengan perintah goto
Anda perlu "melompat" ke memori QSPI. Lokasi spesifik akan bervariasi tergantung pada bagaimana gambar ditautkan, Anda dapat melihat alamat ini dengan perintah mem 0x90000000
(alamat awal cocok dengan kata 32-bit kedua dari gambar); Anda juga perlu menandai tumpukan -s
, alamat tumpukannya adalah 0x90000000, contoh:
embox>mem 0x90000000
0x90000000: 0x20023200 0x9000c27f 0x9000c275 0x9000c275
β β
ΡΡΠΎ Π°Π΄ΡΠ΅Ρ ΡΡΠΎ Π°Π΄ΡΠ΅Ρ
ΡΡΡΠΊΠ° ΠΏΠ΅ΡΠ²ΠΎΠΉ
ΠΈΠ½ΡΡΡΡΠΊΡΠΈΠΈ
embox>goto -i 0x9000c27f -s 0x20023200 # Π€Π»Π°Π³ -i Π½ΡΠΆΠ΅Π½ ΡΡΠΎΠ±Ρ Π·Π°ΠΏΡΠ΅ΡΠΈΡΡ ΠΏΡΠ΅ΡΡΠ²Π°Π½ΠΈΡ Π²ΠΎ Π²ΡΠ΅ΠΌΡ ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΡΠΈΡΡΠ΅ΠΌΡ
< ΠΠ°ΡΠΈΠ½Π°Ρ ΠΎΡΡΡΠ΄Π° Π±ΡΠ΄Π΅Ρ Π²ΡΠ²ΠΎΠ΄ Π½Π΅ Π·Π°Π³ΡΡΠ·ΡΠΈΠΊΠ°, Π° ΠΎΠ±ΡΠ°Π·Π° Ρ OpenCV >
7: Luncurkan
embox> edges 20
dan nikmati pencarian perbatasan 40 detik π
Jika terjadi kesalahan - tulis masalah di
Sumber: www.habr.com