OpenCV pada STM32F7-Discovery

Saya adalah salah satu pengembang sistem operasi Embox , dan dalam artikel ini saya akan berbicara tentang bagaimana saya berhasil menjalankan OpenCV pada papan STM32746G.


Jika Anda mengendarai mesin pencari seperti "OpenCV on STM32 board", Anda dapat menemukan beberapa yang tertarik menggunakan pustaka ini di 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 dilakukan baik pada di komputer biasa, atau di papan yang lebih kuat (misalnya, Raspberry Pi).


Mengapa ini sulit?


Popularitas permintaan pencarian dijelaskan oleh fakta bahwa OpenCV adalah perpustakaan visi komputer yang paling populer, yang berarti bahwa lebih banyak pengembang yang mengenalnya, dan kemampuan untuk menjalankan kode yang siap untuk desktop pada mikrokontroler sangat menyederhanakan proses pengembangan. Tetapi mengapa masih belum ada resep siap pakai yang populer untuk menyelesaikan masalah ini?


Masalah menggunakan OpenCV pada papan kecil dikaitkan dengan dua fitur:


  • Jika Anda mengkompilasi perpustakaan bahkan dengan set modul minimal, itu tidak akan cocok dengan memori flash dari STM32F7 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.)
    • Ada sedikit dukungan untuk LibC / Posix, yang biasanya ditemukan di OS untuk sistem embedded - Anda memerlukan pustaka plus standar dan pustaka templat STL standar (vektor, dll.)

Porting ke Embox


Seperti biasa, sebelum mem-porting program apa pun ke sistem operasi, ada baiknya mencoba merakitnya dalam bentuk yang diinginkan pengembang. Dalam kasus kami, tidak ada masalah dengan ini - sumber dapat ditemukan di github , perpustakaan dibangun di bawah GNU / Linux dengan cmake yang biasa.


Dari kabar baiknya - OpenCV out of the box dapat dirakit sebagai perpustakaan statis, yang membuat porting lebih mudah. Kami mengumpulkan perpustakaan dengan konfigurasi standar dan melihat berapa banyak ruang yang dibutuhkan. Setiap modul dirakit 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 dapat Anda lihat dari baris terakhir, .bss dan .data tidak memakan banyak ruang, tetapi kode lebih dari 70 MiB. Jelas bahwa jika ini dikaitkan secara statis dengan aplikasi tertentu, kode akan menjadi lebih kecil.


Mari kita coba melempar modul sebanyak mungkin sehingga contoh minimal (yang, misalnya, hanya menampilkan versi OpenCV) dirakit, jadi perhatikan cmake .. -LA dan nonaktifkan semua yang dinonaktifkan pada opsi.


  -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, itu tanpa optimasi oleh kompiler dalam hal ukuran kode ( -Os ). ~ 3 MiB kode masih cukup banyak, tetapi sudah memberi harapan untuk sukses.


Jalankan di emulator


Debug pada emulator jauh lebih mudah, jadi pertama pastikan bahwa perpustakaan berjalan pada qemu. Sebagai platform yang ditiru, saya memilih Integrator / CP, karena pertama, itu juga ARM, dan kedua, Embox mendukung output grafis untuk platform ini.


Embox memiliki mekanisme untuk membangun perpustakaan eksternal, dengan menggunakannya kita menambahkan OpenCV sebagai modul (melewati semua opsi yang sama untuk membangun "minimal" sebagai perpustakaan statis), setelah itu saya menambahkan aplikasi paling 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 kesimpulan 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, terbaik dari semua standar yang ditawarkan pengembang sendiri di situs web mereka . Saya memilih detektor perbatasan Canny .


Contoh harus ditulis ulang sedikit untuk menampilkan gambar dengan hasil langsung di buffer bingkai. Saya harus melakukan ini karena fungsi imshow() dapat menggambar gambar melalui antarmuka QT, GTK dan Windows, yang, tentu saja, tidak akan berada dalam konfigurasi STM32. Bahkan, QT juga dapat dijalankan di STM32F7Discovery, tetapi ini akan dibahas dalam artikel lain :)


Setelah klarifikasi singkat di mana format hasil detektor perbatasan disimpan, kami mendapatkan gambar.



Gambar asli



Hasil


Berjalan di STM32F7Discovery


Ada beberapa partisi perangkat keras pada 32F746GDISCOVERY yang dapat kita gunakan


  1. RAM 320KiB
  2. 1MiB flash untuk gambar
  3. 8MiB SDRAM
  4. 16MiB QSPI NAND flash drive
  5. Slot kartu microSD

Kartu SD dapat digunakan untuk menyimpan gambar, tetapi dalam konteks menjalankan contoh minimal, ini tidak terlalu berguna.
Layar memiliki resolusi 480x272, yang berarti bahwa memori untuk framebuffer akan menjadi 522.240 byte pada kedalaman 32 bit, mis. ini lebih dari ukuran RAM, jadi kami akan menempatkan framebuffer dan banyak (yang akan diperlukan untuk OpenCV untuk menyimpan data untuk gambar dan struktur tambahan) di SDRAM, semua yang lain (memori untuk tumpukan dan kebutuhan sistem lainnya) akan masuk ke RAM .


Jika kita mengambil konfigurasi minimal untuk STM32F7Discovery (membuang seluruh jaringan, semua perintah, buat tumpukan sekecil mungkin, dll.) Dan tambahkan OpenCV dengan contoh di sana, dengan memori yang diperlukan, berikut ini akan menjadi:


  text data bss dec hex filename 2876890 459208 312736 3648834 37ad42 build/base/bin/embox 

Bagi mereka yang tidak terbiasa dengan bagian apa yang sedang dilipat, saya akan menjelaskan: instruksi dan konstanta (kira-kira, data hanya baca) ada di .rodata dan .rodata , data bisa berubah dalam. .data , dan "nol" ada di .bss variabel yang, bagaimanapun, membutuhkan tempat (bagian ini akan "pergi" ke RAM).


Berita baiknya adalah bahwa .bss / .bss harus sesuai, tetapi dengan .text masalahnya adalah hanya ada 1MiB memori untuk gambar. Anda dapat .text gambar dari contoh dari .text dan membacanya, misalnya, dari kartu SD ke memori saat startup, tetapi buah.png memiliki berat sekitar 330KiB, jadi ini tidak akan menyelesaikan masalah: sebagian besar .text terdiri dari kode OpenCV.


Pada umumnya, hanya ada satu hal yang tersisa - memuat bagian kode ke flash drive QSPI (ia memiliki mode operasi khusus untuk memetakan memori ke bus sistem, sehingga prosesor dapat mengakses data ini secara langsung). Dalam kasus ini, muncul masalah: pertama, memori flash drive QSPI tidak tersedia segera setelah perangkat di-boot ulang (Anda perlu secara terpisah menginisialisasi mode yang dipetakan memori), dan kedua, Anda tidak dapat mem-flash memori ini dengan bootloader biasa.


Akibatnya, diputuskan untuk menautkan semua kode dalam QSPI, dan mem-flash-nya dengan bootloader, yang akan menerima biner yang diperlukan melalui TFTP.


Hasil


Gagasan untuk memindahkan pustaka ini ke Embox muncul sekitar setahun yang lalu, tetapi berulang kali itu ditunda karena berbagai alasan. Salah satunya adalah dukungan untuk libstdc ++ dan perpustakaan templat standar. Masalah mendukung 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 untuk perpustakaan ini bekerja :)


Pada akhirnya, masalah ini diatasi (setidaknya cukup untuk contoh OpenCV untuk bekerja), dan contoh dimulai. 40 detik yang lama membutuhkan papan untuk mencari batas oleh filter Canny. Ini, tentu saja, terlalu lama (ada pertimbangan tentang bagaimana mengoptimalkan masalah ini, akan mungkin untuk menulis artikel terpisah tentang hal itu jika berhasil).




Namun demikian, tujuan antara adalah untuk membuat prototipe yang akan menunjukkan kemungkinan mendasar menjalankan OpenCV pada STM32, masing-masing, tujuan ini tercapai, tepuk tangan!

tl; dr: petunjuk langkah demi langkah


0: Unduh sumber-sumber Embox, misalnya seperti ini:


  git clone https://github.com/embox/embox && cd ./embox 

1: Mari kita mulai dengan membangun 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 memodifikasi 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 adalah alamat host dari mana gambar akan dimuat, address adalah alamat board.


Setelah itu, kumpulkan bootloader:


  make 

2: Pemuatan bootloader normal (maaf untuk permainan kata-kata) di papan - tidak ada yang spesifik di sini, Anda perlu melakukan ini seperti untuk aplikasi lain untuk STM32F7Discovery. Jika Anda tidak tahu cara melakukan ini, Anda dapat membacanya di sini .
3: Kompilasi gambar dengan konfigurasi untuk OpenCV.


  make confload-platform/opencv/stm32f7discovery make 

4: Mengekstrak dari bagian ELF yang perlu ditulis ke QSPI, di 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 

Direktori conf berisi skrip yang melakukan ini, sehingga Anda dapat menjalankannya


  ./conf/qspi_objcopy.sh #   -- build/base/bin/qspi.bin 

5: Menggunakan tftp, muat qspi.bin.bin ke flash drive QSPI. Untuk melakukan ini, pada host, salin qspi.bin ke folder root dari server tftp (biasanya itu adalah / srv / tftp / atau / var / lib / tftpboot /; paket untuk server yang sesuai adalah dalam distribusi yang paling populer, biasanya disebut tftpd atau tftp-hpa, terkadang Anda perlu membuat 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 

Pada Embox (mis., Di bootloader), Anda perlu menjalankan perintah berikut (kami menganggap bahwa server memiliki alamat 192.168.2.1):


  embox> qspi_loader qspi.bin 192.168.2.1 

6: Menggunakan perintah goto , Anda harus "melompat" ke memori QSPI. Lokasi spesifik akan bervariasi tergantung pada bagaimana gambar dihubungkan, Anda dapat melihat alamat ini dengan mem 0x90000000 (alamat mulai cocok dengan kata gambar 32-bit kedua); Anda juga perlu mengatur stack dengan flag -s , alamat stack berada di 0x90000000, misalnya:


  embox>mem 0x90000000 0x90000000: 0x20023200 0x9000c27f 0x9000c275 0x9000c275 ↑ ↑        embox>goto -i 0x9000c27f -s 0x20023200 #  -i         <      ,    OpenCV > 

7: Jalankan


  embox> edges 20 

dan nikmati pencarian perbatasan 40 detik :)


Jika ada masalah - tuliskan masalah di repositori kami , atau di milis embox-devel@googlegroups.com, atau di komentar di sini.

Source: https://habr.com/ru/post/id457724/


All Articles