OpenCV di STM32F7-Discovery

OpenCV di STM32F7-Discovery Saya adalah salah satu pengembang sistem operasi kotak masuk, dan dalam artikel ini saya akan berbicara tentang bagaimana saya berhasil menjalankan OpenCV di papan STM32746G.

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 github, perpustakaan dibangun di bawah GNU/Linux dengan cmake biasa.

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. di situs Anda. saya memilih pendeteksi perbatasan cerdik.

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.

OpenCV di STM32F7-Discovery

gambar asli

OpenCV di STM32F7-Discovery

Hasil

Berjalan di STM32F7Discovery

Pada 32F746GDISCOVERY ada beberapa bagian memori perangkat keras yang dapat kita gunakan dengan satu atau lain cara

  1. RAM 320KiB
  2. Flash 1MiB untuk gambar
  3. SDRAM 8MiB
  4. Flash NAND QSPI 16MiB
  5. 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).

OpenCV di STM32F7-Discovery

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 di sini.
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 repositori kami, atau ke milis [email dilindungi], atau di komentar di sini.

Sumber: www.habr.com

Tambah komentar