STM32F7-Discovery-də OpenCV

STM32F7-Discovery-də OpenCV Mən əməliyyat sisteminin tərtibatçılarından biriyəm Emboks, və bu məqalədə STM32746G lövhəsində OpenCV-ni necə idarə etməyi bacardığımdan danışacağam.

Axtarış motoruna “STM32 lövhəsində OpenCV” kimi bir şey yazsanız, bu kitabxanadan STM32 lövhələrində və ya digər mikrokontrolörlərdə istifadə etməkdə maraqlı olan kifayət qədər adam tapa bilərsiniz.
Bir neçə video var ki, adından asılı olaraq nəyin lazım olduğunu nümayiş etdirməlidir, lakin adətən (gördüyüm bütün videolarda) STM32 lövhəsində yalnız kameradan görüntü alınır və nəticə ekranda göstərilirdi, və görüntünün işlənməsi ya adi kompüterdə, ya da daha güclü lövhələrdə (məsələn, Raspberry Pi) həyata keçirilirdi.

Niyə çətindir?

Axtarış sorğularının populyarlığı onunla izah olunur ki, OpenCV ən populyar kompüter görmə kitabxanasıdır, bu isə o deməkdir ki, onunla daha çox tərtibatçı tanışdır və mikrokontrollerdə iş masası üçün hazır kodu işlətmək imkanı inkişaf prosesini xeyli asanlaşdırır. Bəs niyə bu problemi həll etmək üçün hələ də populyar hazır reseptlər yoxdur?

Kiçik şallarda OpenCV-dən istifadə problemi iki xüsusiyyətlə bağlıdır:

  • Kitabxananı hətta minimal modul dəsti ilə tərtib etsəniz, o, çox böyük kod (bir neçə meqabayt təlimat) səbəbindən eyni STM32F7Discovery-nin fləş yaddaşına (ƏS-ni nəzərə almadan belə) uyğun gəlməyəcək.
  • Kitabxananın özü C++ dilində yazılmışdır, yəni
    • Müsbət iş vaxtı üçün dəstəyə ehtiyac var (istisnalar və s.)
    • Adətən quraşdırılmış sistemlər üçün ƏS-də tapılan LibC/Posix üçün az dəstək - sizə standart plus kitabxanası və standart STL şablon kitabxanası (vektor və s.) lazımdır.

Embox-a daşınır

Həmişə olduğu kimi, hər hansı bir proqramı əməliyyat sisteminə köçürməzdən əvvəl onu tərtibatçıların nəzərdə tutduğu formada qurmağa çalışmaq yaxşı olar. Bizim vəziyyətimizdə bununla bağlı heç bir problem yoxdur - mənbə kodu burada tapıla bilər github, kitabxana adi cmake ilə GNU/Linux altında qurulur.

Yaxşı xəbər budur ki, OpenCV qutudan kənarda statik kitabxana kimi qurula bilər, bu da daşımağı asanlaşdırır. Standart konfiqurasiya ilə bir kitabxana toplayırıq və onların nə qədər yer tutduğunu görürük. Hər bir modul ayrıca kitabxanada toplanır.

> 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)

Sonuncu sətirdən göründüyü kimi, .bss və .data çox yer tutmur, lakin kod 70 MiB-dən çoxdur. Aydındır ki, bu, müəyyən bir tətbiqə statik olaraq bağlıdırsa, kod daha az olacaq.

Mümkün qədər çox modul atmağa çalışaq ki, minimal bir nümunə yığılsın (məsələn, sadəcə OpenCV versiyasını çıxaracaq), ona görə də baxırıq. cmake .. -LA və sönən hər şeyi seçimlərdə söndürün.

        -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)

Bir tərəfdən, bu, kitabxananın yalnız bir moduludur, digər tərəfdən, kod ölçüsü üçün kompilyator optimallaşdırması olmadan (-Os). ~3 MiB kod hələ də kifayət qədər çoxdur, lakin artıq uğur üçün ümid verir.

Emulatorda işə salın

Emulatorda debug etmək daha asandır, ona görə də əvvəlcə kitabxananın qemu üzərində işlədiyinə əmin olun. Təqlid edilmiş bir platforma olaraq Integrator / CP-ni seçdim, çünki birincisi, o, həm də ARM-dir, ikincisi, Embox bu platforma üçün qrafik çıxışı dəstəkləyir.

Embox-da xarici kitabxanaların qurulması mexanizmi var, ondan istifadə edərək biz OpenCV-ni modul kimi əlavə edirik (statik kitabxanalar şəklində "minimal" qurmaq üçün bütün eyni variantları keçərək), bundan sonra bu kimi görünən sadə bir proqram əlavə edirəm:

version.cpp:

#include <stdio.h>
#include <opencv2/core/utility.hpp>

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

    return 0;
}

Sistemi yığırıq, işə salırıq - gözlənilən nəticəni alırıq.

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 включены в сборку и т.п.>

Növbəti addım bəzi nümunələri, tercihen tərtibatçıların özləri tərəfindən təklif olunan standart nümunələrdən birini işə salmaqdır. saytınızda. Mən seçdim sərhəd detektoru canny.

Nəticəni birbaşa çərçivə buferində göstərmək üçün nümunə bir qədər yenidən yazılmalıdır. Bunu etməli idim, çünki. funksiyası imshow() QT, GTK və Windows interfeysləri vasitəsilə şəkillər çəkə bilər, bu, əlbəttə ki, STM32 üçün konfiqurasiyada olmayacaqdır. Əslində, QT STM32F7Discovery-də də işlədilə bilər, lakin bu başqa məqalədə müzakirə olunacaq 🙂

Kənar detektorun nəticəsinin hansı formatda saxlandığını qısa bir şəkildə aydınlaşdırdıqdan sonra bir şəkil alırıq.

STM32F7-Discovery-də OpenCV

orijinal şəkil

STM32F7-Discovery-də OpenCV

Nəticə

STM32F7Discovery üzərində işləyir

32F746GDISCOVERY-də bu və ya digər şəkildə istifadə edə biləcəyimiz bir neçə hardware yaddaş bölməsi var.

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

Şəkilləri saxlamaq üçün SD kartdan istifadə etmək olar, lakin minimal nümunəni işə salmaq kontekstində bu çox faydalı deyil.
Displey 480×272 təsvir ölçüsünə malikdir, yəni çərçivə buferinin yaddaşı 522 bit dərinlikdə 240 32 bayt olacaq, yəni. bu, RAM-ın ölçüsündən çoxdur, buna görə də çərçivə buferi və yığın (o cümlədən, OpenCV üçün təsvirlər və köməkçi strukturlar üçün məlumatların saxlanması üçün tələb olunacaq) SDRAM-da yerləşəcək, qalan hər şey (stoklar üçün yaddaş və digər sistem ehtiyacları) ) RAM-a gedəcək.

STM32F7Discovery üçün minimum konfiqurasiyanı götürsək (bütün şəbəkəni, bütün əmrləri atın, yığınları mümkün qədər kiçik edin və s.) və orada nümunələrlə OpenCV ə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 hara getdiyi ilə çox tanış olmayanlar üçün izah edəcəyəm: in .text и .rodata təlimatlar və sabitlər (təxminən desək, yalnız oxunan məlumatlar) yatır .data məlumat dəyişkəndir, .bss "nulled" dəyişənlər var, buna baxmayaraq, bir yerə ehtiyac var (bu bölmə RAM-a "gedəcək").

Yaxşı xəbər budur .data/.bss uyğun olmalıdır, lakin ilə .text problem ondadır ki, görüntü üçün cəmi 1MiB yaddaş var. Çölə atmaq olar .text nümunədəki şəkli və onu oxuyun, məsələn, başlanğıc zamanı SD kartdan yaddaşa köçürün, lakin fruits.png təxminən 330KiB ağırlığındadır, buna görə də bu problemi həll etməyəcək: çoxu .text OpenCV kodundan ibarətdir.

Ümumiyyətlə, yalnız bir şey qalır - kodun bir hissəsini QSPI flaşına yükləmək (o, yaddaşı sistem avtobusuna köçürmək üçün xüsusi iş rejiminə malikdir ki, prosessor bu məlumatlara birbaşa daxil ola bilsin). Bu halda problem yaranır: birincisi, QSPI fləş sürücüsünün yaddaşı cihaz yenidən işə salındıqdan dərhal sonra mövcud deyil (yaddaş xəritəli rejimini ayrıca işə salmalısınız), ikincisi, bu yaddaşı "yanıb-söndürə" bilməzsiniz. tanış bootloader.

Nəticədə, QSPI-də bütün kodu əlaqələndirmək və TFTP vasitəsilə tələb olunan ikili faylı alacaq öz-özünə yazılmış yükləyici ilə flaş etmək qərara alındı.

Nəticə

Bu kitabxananı Embox-a köçürmək ideyası təxminən bir il əvvəl ortaya çıxdı, lakin müxtəlif səbəblərə görə dəfələrlə təxirə salındı. Onlardan biri libstdc++ və standart şablon kitabxanasına dəstəkdir. Embox-da C++ dəstəyi problemi bu məqalənin əhatə dairəsi xaricindədir, ona görə də burada yalnız deyəcəm ki, biz bu dəstəyi bu kitabxananın işləməsi üçün lazımi miqdarda əldə edə bilmişik 🙂

Sonda bu problemlər aradan qaldırıldı (ən azı OpenCV nümunəsinin işləməsi üçün kifayətdir) və nümunə işə salındı. Lövhənin Canny filtrindən istifadə edərək sərhədləri axtarması 40 uzun saniyə çəkir. Bu, əlbəttə ki, çox uzundur (bu məsələnin optimallaşdırılmasına dair mülahizələr var, uğur qazanacağı təqdirdə bu barədə ayrıca məqalə yazmaq mümkün olacaq).

STM32F7-Discovery-də OpenCV

Bununla belə, aralıq məqsəd OpenCV-nin STM32-də işləməsinin fundamental imkanlarını göstərəcək prototip yaratmaq idi, müvafiq olaraq bu məqsədə nail olundu, yaş!

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

0: Embox mənbələrini bu kimi yükləyin:

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

1: QSPI flash sürücüsünü "yandıracaq" yükləyicini yığmaqla başlayaq.

    make confload-arm/stm32f7cube

İndi şəbəkəni konfiqurasiya etməlisiniz, çünki. Şəkili TFTP vasitəsilə yükləyəcəyik. Lövhə və host IP ünvanlarını təyin etmək üçün siz conf/rootfs/şəbəkəni redaktə etməlisiniz.

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 - şəklin yüklənəcəyi host ünvanı, address - şuranın ünvanı.

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

    make

2: Bootloaderin adi lövhədə yüklənməsi (söz üçün üzr istəyirik) - burada konkret heç nə yoxdur, bunu STM32F7Discovery üçün hər hansı digər proqram kimi etmək lazımdır. Bunu necə edəcəyinizi bilmirsinizsə, bu barədə oxuya bilərsiniz burada.
3: OpenCV üçün konfiqurasiya ilə təsvirin tərtib edilməsi.

    make confload-platform/opencv/stm32f7discovery
    make

4: QSPI-yə qspi.bin-ə yazılacaq ELF bölmələrindən çıxarış

    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 # Нужный бинарник -- build/base/bin/qspi.bin

5: tftp istifadə edərək, qspi.bin.bin faylını QSPI flash sürücüsünə endirin. Bunu etmək üçün hostda qspi.bin faylını tftp serverinin kök qovluğuna kopyalayın (adətən /srv/tftp/ və ya /var/lib/tftpboot/; müvafiq server üçün paketlər adətən adlanan ən populyar paylamalarda mövcuddur. tftpd və ya tftp-hpa, bəzən etməlisən systemctl start tftpd.service başlamaq).

    # вариант для 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ə) aşağıdakı əmri yerinə yetirməlisiniz (biz güman edirik ki, server 192.168.2.1 ünvanına malikdir):

    embox> qspi_loader qspi.bin 192.168.2.1

6: Əmrlə goto siz QSPI yaddaşına "atlamalısınız". Xüsusi yer şəklin necə bağlanmasından asılı olaraq dəyişəcək, bu ünvanı əmrlə görə bilərsiniz mem 0x90000000 (başlanğıc ünvanı şəklin ikinci 32 bitlik sözünə uyğun gəlir); siz həmçinin yığını işarələməlisiniz -s, yığın ünvanı 0x90000000-dadır, məsələn:

    embox>mem 0x90000000
    0x90000000:     0x20023200  0x9000c27f  0x9000c275  0x9000c275
                      ↑           ↑
              это адрес    это  адрес 
                стэка        первой
                           инструкции

    embox>goto -i 0x9000c27f -s 0x20023200 # Флаг -i нужен чтобы запретить прерывания во время инициализации системы

    < Начиная отсюда будет вывод не загрузчика, а образа с OpenCV >

7: işə salın

    embox> edges 20

və 40 saniyəlik sərhəd axtarışından həzz alın 🙂

Bir şey səhv olarsa - bir problem yazın anbarımız, və ya poçt siyahısına [e-poçt qorunur], və ya burada şərhdə.

Mənbə: www.habr.com

Добавить комментарий