STM32F7-Discovery-də OpenCV

STM32F7-Discovery-də OpenCV Mən əməliyyat sistemi mühəndislərindən biriyəm Embox, və bu yazıda STM32746G platasında OpenCV-ni necə işlətməyə müvəffəq olduğum barədə danışacağam.

Axtarış sisteminə "OpenCV on STM32 board" yazanda, bu kitabxananın STM32 platalarında və ya digər mikroidarəedicilərdə istifadəsi ilə maraqlananların sayı olduqca çoxdur.
Bir neçə video var ki, adından belə demək olar ki, bunu nümayiş etdirməlidir, amma adətən (gördüyüm bütün videolarda) STM32 platasında yalnız kamera ilə görüntü alınır və nəticə ekrana verilir, şəkil emalı ya adi bir kompüterdə, ya da daha güclü platalarda (məsələn, Raspberry Pi) edilir.

Niyə bu çətindir?

Axtarış sorğularının populyarlığı, OpenCV-nin ən məşhur kompüter görmə kitabxanası olmasıyla izah olunur, yəni bu kitabxana daha çox inkişaf etdirici tərəfindən tanınır və desktop üçün hazırlanmış kodu mikroidarəedici üzərində işlətmək inkişaf prosesini əhəmiyyətli dərəcədə asanlaşdırır. Amma hələ də niyə bu problemi həll etmək üçün məşhur hazır reseptlər yoxdur?

OpenCV-nin kiçik platalarda istifadəsi iki xüsusiyyətlə bağlıdır:

  • Əgər kitabxananı minimal modullar dəsti ilə tərtib etsəniz, STM32F7Discovery-nin flash yaddaşına sadəcə sığmayacaq (hətta OS nəzərə alınmadan) çox böyük kodu (bir neçə megabayt göstərişləri) olduğu üçün.
  • Kitabxana özü C++-da yazılıb, yəni
    • C++ runtime dəstəyinə (istisnalar və s.) ehtiyac var.
    • LibC/Posix üçün dəstəyin azlığı, adətən, inteqrasiya edilmiş sistemlər üçün OS-lərdə var — standart C++ kitabxanası və STL şablon kitabxanası (vector və s.) lazımdır.

Embox-a portlama

Adətən, hər hansı proqramı əməliyyat sisteminə portlamaqdan əvvəl, onu inkişaf etdiricilərin düşündüyü şəkildə toplamağa çalışmaq yaxşıdır. Bizim halda bununla bağlı bir problem olmur — mənbələri github-datapmaq olur, kitabxana adi cmake vasitəsilə GNU/Linux üçün tərtib edilir.

Yaxşı xəbər odur ki, OpenCV qutudan işlək vəziyyətdə statik kitabxana şəklində tərtib edilə bilər, bu da portlanmanı asanlaşdırır. Kitabxananı standart konfiqurasiyaya uyğun toplayırıq və nə qədər yer tutduğuna baxırıq. Hər bir modul ayrı bir kitabxana olaraq tərtib edilir.

> ölçü lib/*so --toplamlar
   mətn    məlumat     bss     dec     hex fayl adı
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 (TOPLAMLAR)

Son satırdan göründüyü kimi, .bss və .data çox yer tutmur, amma kod 70 MiB-dən çoxdur. Aydındır ki, bu, konkret bir tətbiqlə statik bağlama zamanı daha az kod olmasına səbəb olur.

Mümkün qədər çox modulu çıxarmağa çalışaq ki, minimal bir nümunə toplaya bilək (məsələn, sadəcə OpenCV versiyasını göstərəcək), buna görə diqqət edək. cmake .. -LA və seçimlərdə deaktiv edilən hər şeyi söndürürük.

        -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

> ölçü lib/libopencv_core.a --toplamlar
   mətn    məlumat     bss     dec     hex fayl adı
3317069   36425   17987 3371481  3371d9 (TOPLAMLAR)

Bir tərəfdən, bu yalnız bir moduldur, digər tərəfdən, bu tərtib olunan kod üçün optimallaşdırmadan irəlidədir (-Os). ~3 MiB kod — hələ də çoxdur, lakin uğur üçün ümid verməyə başlayır.

Emulyatorda işə salma

Emulyatorda debuq etmək daha asandır, buna görə əvvəlcə kitabxananın qemu-da işlədiyini təsdiq edək. Emulyasiya edilən platforma olaraq Integrator/CP-ni seçdim, çünki birincisi, bu da ARM-dir, ikincisi isə, Embox bu platforma üçün görüntü çıxışını dəstəkləyir.

Embox-da xarici kitabxanaların yığılması üçün bir mexanizm var, onun köməyi ilə OpenCV-ni modul kimi əlavə edirik (bütün eyni seçimləri istifadə edərək

version.cpp:

#include 
#include 

int main() {
    printf("OpenCV: %s", cv::getBuildInformation().c_str());

    return 0;
}

Sistemi yığıb işə salırıq — gözlənilən çıxışı alırıq.

root@embox:/#opencv_version                                                     
OpenCV: 
OpenCV 4.0.1 üçün Ümumi konfiqurasiya =====================================
  Versiya idarəsi:               bd6927bdf-dirty

  Platforma:
    Zaman damğası:                   2019-06-21T10:02:18Z
    Ev sahibi:                        Linux 5.1.7-arch1-1-ARCH x86_64
    Hədəf:                      Generic arm-unknown-none
    CMake:                       3.14.5
    CMake generator:             Unix Makefiles
    CMake yığma aləti:            /usr/bin/make
    Konfiqurasiya:               Debug

  CPU/HW xüsusiyyətləri:
    Əsas xətt:
      istəklər:                 DETECT
      deaktiv edilmiş:                  VFPV3 NEON

  C/C++:
    Dinamik kitabxana kimi yığıldımı?:      HƏN

Sonrakı addım, hansısa bir nümunəni işə salmaqdır, ən yaxşısı isə, inkişaf etdiricilərin təklif etdiyi standart nümunələrdən biri olsun. öz saytınızda. Mən seçdim Kenny sərhəd detektorunu.

Nümunəni bir az yenidən yazmaq lazım gəldi ki, nəticə görüntüsünü birbaşa frame buffer-da göstərsin. Bunu etmək lazım gəldi, çünki imshow() QT, GTK və Windows interfeysləri vasitəsilə görüntüləri çəkməyi bacarır ki, bunlar STM32 konfiqurasiyasında qurulmayacaq. Əslində, QT-nin də STM32F7Discovery-də çalışdırılması mümkündür, amma bu artıq başqa bir məqalədə müzakirə olunacaq 🙂

Qısa bir araşdırmadan sonra, sərhəd detektorunun iş nəticəsinin hansı formatda saxlandığını tədqiq etdik, görüntünü alırıq.

STM32F7-Discovery-də OpenCV

Əsas görüntü

STM32F7-Discovery-də OpenCV

Nəticə

STM32F7Discovery-də işə salmaq

32F746GDISCOVERY-də istifadə edə biləcəyimiz bir neçə aparat yaddaş bölməsi var.

  1. 320KiB RAM
  2. Şəkil üçün 1MiB flash yaddaş
  3. 8MiB SDRAM
  4. 16MiB QSPI NAND flaş
  5. microSD kartı üçün girişi

SD kartını şəkillərin saxlanması üçün istifadə etmək olar, lakin minimal nümunənin işə salınması kontekstində bu çox da faydalı deyil.
Ekranın çözünürlüğü 480×272-dir, bu isə frame buffer üçün 522 240 bayt yaddaş tələb edir, 32 bit dərinlikdə, yəni bu, RAM ölçüsündən daha çoxdur, beləliklə frame buffer və heap (OpenCV üçün məlumatları və köməkçi strukturları saxlamaq üçün lazım olacaq) SDRAM-da yerləşəcək, qalan hər şey (stack və digər sistem ehtiyacları üçün yaddaş) RAM-a yönləndiriləcək.

STM32F7Discovery üçün minimal konfiqurasiyanı (bütün şəbəkəni çıxarmaq, bütün komandaları, stakları mümkün qədər kiçik etmək və s.) götürsək və oraya OpenCV nümunələrini əlavə etsək, tələb olunan yaddaş aşağıdakı kimi olacaq:

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

Hansı bölmələrin haraya yerləşdiyinə çox da aşina olmayanlar üçün izah edim: burada .text.rodata instruction və konstantaların (qısaca, oxunmaz verilərin) olduğu yerdir, burada .data dəyişdirilə bilən verilərin olduğu yerdir, burada .bss "sıfırlanmış" dəyişkənlər yerləşir ki, buna baxmayaraq yerə ehtiyac var (bu bölmə RAM-a "gedəcək").

Yaxşı xəbər odur ki, .data/.bss yerləşməlidirlər, amma .text burası çətinlikdir — imic üçün yalnız 1MiB yaddaş var. Nümunəni istifadə edilən şəkli çıxarmaq və onu SD kartdan yükləmək mümkündür, amma fruits.png təxminən 330KiB-dir, buna görə bu problem çözülmür: əksər hissəsi .text OpenCV kodundan ibarətdir. .text Ümumi olaraq, yalnız bir şey qalır — kodun bir hissəsini QSPI flaşına yükləmək (onun sistem avtobusuna yaddaşı xəritələmə üçün xüsusi iş rejimi var, beləliklə prosessor bu məlumatlara birbaşa müraciət edə bilər). Bu zaman bir problem ortaya çıxır: birincisi, QSPI flaş yaddaşı cihazın yenidən başladılmasından dərhal sonra istifadə edilə bilmir (xüsusi memory-mapped rejimini ayrıca işə salmaq lazımdır), ikincisi, bu yaddaşı adi yükləyici ilə "yazmaq" olmaz.

По большому счёту, остаётся только одно — загрузка части кода на QSPI-флэшку (у неё есть спец. режим работы для мэпирования памяти на системную шину, так что процессор сможет обращаться к этим данным напрямую). При этом возникает проблема: во-первых, память QSPI-флэшки недоступна сразу после перезагрузки устройства (нужно отдельно инициализировать memory-mapped-режим), во-вторых, нельзя «прошить» эту память привычным загрузчиком.

Nəticədə, bütün kodu QSPI-yə bağlamaq qərarına gəldik və onu TFTP-dən lazımi binar faylı alacaq öz yükləyici proqramımızla yükləyəcəyik.

Nəticə

Bu kitabxananı Embox-a port etmək ideyası təxminən bir il əvvəl ortaya çıxdı, amma bir neçə səbəbə görə başdan-ayağa təxirə salındı. Bunlardan biri - libstdc++ və standart şablon kitabxanasının dəstəyi. C++-ın Embox-da dəstəklənməsi bu yazının çərçivəsindən kənardır, ona görə də yalnız deyim ki, bu kitabxana üçün lazım olan səviyyədə bu dəstəyi qazana bildik 🙂

Nəticədə, bu problemlər həll olundu (ən azı OpenCV nümunəsinin işləməsi üçün kifayət qədər), və nümunə işə düşdü. 40 uzun saniyə platanın Kənni filtrindən sərhədləri tapması üçün sərf olunur. Bu, əlbəttə ki, çox uzundur (bu məsələni optimallaşdırmaq üçün fikirlər var, uğur qazanarsaq, bununla bağlı ayrıca bir yazı yazmaq olar).

STM32F7-Discovery-də OpenCV

Yəni, müvəqqəti məqsəd OpenCV-nin STM32-də işlədiyini göstərən prototip yaratmaq idi, buna görə də bu məqsəd əldə edildi, yaşasın!

tl;dr: addım-addım təlimat

0: Embox-un mənbələrini yükləyirik, məsələn belə:

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

1: QSPI-flash üçün yükləyicinin yığılmasına başlayacağıq.

    make confload-arm/stm32f7cube

İndi şəbəkəni tənzimləmək lazımdır, çünki imici TFTP ilə yükləyəcəyik. Platanın və hostun IP ünvanlarını ayarlamaq üçün conf/rootfs/network faylını dəyişdirmək lazımdır.

Konfiqurasiya nümunəsi:

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 — imicin yüklənəcəyi hostun ünvanı, address — platanın ünvanı.

Bundan sonra yükləyicini yığırıq:

    make

2: Yükləyicinin (bu ifadəyə görə üzr istəyirəm) platanın üzərinə göndərilməsi — burada xüsusi bir şey yoxdur, bunu STM32F7Discovery üçün hər hansı digər tətbiq kimi etmək lazımdır. Əgər bunu necə edə biləcəyinizi bilmirsinizsə, bununla bağlı oxumaq olar. burada.
3: OpenCV üçün konfiqurasiya ilə imicin tərtibi.

    make confload-platform/opencv/stm32f7discovery
    make

4: QSPI-yə yazılacaq ELF bölmələrinin çıxarılması, qspi.bin faylına.

    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

conf qovluğunda bunu edən bir skript var, ona görə də onu işə sala bilərsiniz.

    ./conf/qspi_objcopy.sh # Lazım olan binar fayl -- build/base/bin/qspi.bin

5: TFTP ilə qspi.bin.bin faylını QSPI-flash-a yükləyirik. Hostda, bunun üçün qspi.bin faylını tftp serverinin kök qovluğuna (adi olaraq /srv/tftp/ və ya /var/lib/tftpboot/; müvafiq server üçün paketlər bir çox populyar distributivdə mövcuddur, adətən tftpd ya da tftp-hpa adlanır, bəzən başlamaq üçün bu əmri vermək lazımdır: systemctl start tftpd.service bunun üçün).

    # вариант для tftpd
    sudo cp build/base/bin/qspi.bin /srv/tftp
    # вариант для tftp-hpa
    sudo cp build/base/bin/qspi.bin /var/lib/tftpboot

Embox-da (yəni yükləyicidə) belə bir əmri yerinə yetirmək lazımdır (serverin ünvanının 192.168.2.1 olduğunu güman edirik):

    embox> qspi_loader qspi.bin 192.168.2.1

6: Bu əmrlə goto QSPI-memoriya ilə "atlamaq" lazımdır. Konkret yer, şəkilin necə bağlandığına bağlı olaraq dəyişəcək, bu adresə baxmaq üçün komandanı istifadə edin. mem 0x90000000 (başlanğıc adresi görüntünün ikinci 32-bit sözünə yerləşir); həmçinin, yığın bayrağını təyin etmək lazım olacaq. -s, yığın adresi 0x90000000 ünvanında yerləşir, nümunə:

    embox>mem 0x90000000
    0x90000000:     0x20023200  0x9000c27f  0x9000c275  0x9000c275
                      ↑           ↑
              bu adres    bu  adres 
                yığın        ilk
                           əmrin

    embox>goto -i 0x9000c27f -s 0x20023200 # -i bayrağı, sistemi başlatarkən kəsilmələri qadağan etmək üçün lazımdır.

7: Başlasaq

    embox> edges 20

və 40 saniyəlik sərhədlərin axtarışından həzz alırıq 🙂

Əgər bir şey səhv olarsa — bizim məsələlər sistemimizdə yaza bilərsiniz. bizim depozitimizdə, ya embox-devel@googlegroups.com ünvanına, ya da burada şərhlərdə.

Mənbə: habr.com

DDoS qoruması olan saytlara etibarlı hosting satın alın, VPS VDS serverlər 🔥 DDoS qoruması olan saytlara etibarlı hosting satın alın, VPS VDS serverlər | ProHoster