ОпенЦВ на СТМ32Ф7-Дисцовери

ОпенЦВ на СТМ32Ф7-Дисцовери Ја сам један од програмера оперативног система Ембок, а у овом чланку ћу говорити о томе како сам успео да покренем ОпенЦВ на СТМ32746Г плочи.

Ако унесете нешто попут „ОпенЦВ на СТМ32 плочи“ у претраживач, можете пронаћи доста људи који су заинтересовани да користе ову библиотеку на СТМ32 плочама или другим микроконтролерима.
Постоји неколико видео снимака који би, судећи по називу, требало да покажу шта је потребно, али обично (у свим видео записима које сам видео) на СТМ32 плочи само је слика примљена са камере и резултат је приказан на екрану, а сама обрада слике је вршена или на обичном рачунару, или на моћнијим плочама (на пример Распберри Пи).

Зашто је тешко?

Популарност упита за претрагу се објашњава чињеницом да је ОпенЦВ најпопуларнија библиотека компјутерског вида, што значи да је више програмера упознато са њом, а могућност покретања кода спремног за радну површину на микроконтролеру у великој мери поједностављује процес развоја. Али зашто још увек нема популарних готових рецепата за решавање овог проблема?

Проблем коришћења ОпенЦВ-а на малим шаловима је повезан са две карактеристике:

  • Ако компајлирате библиотеку чак и са минималним скупом модула, она једноставно неће стати у флеш меморију истог СТМ32Ф7Дисцовери (чак и без узимања у обзир ОС) због веома великог кода (неколико мегабајта инструкција)
  • Сама библиотека је написана у Ц++, што значи
    • Потребна је подршка за позитивно време рада (изузеци, итд.)
    • Мала подршка за ЛибЦ/Посик, која се обично налази у ОС-у за уграђене системе - потребна вам је стандардна плус библиотека и стандардна библиотека СТЛ шаблона (вектор, итд.)

Пренос у Ембок

Као и обично, пре него што пренесете било који програм на оперативни систем, добра је идеја да покушате да га направите у облику у којем су га програмери замислили. У нашем случају, нема проблема са овим - изворни код се може наћи на гитхуб, библиотека је изграђена под ГНУ/Линук-ом са уобичајеним цмаке-ом.

Добра вест је да ОпенЦВ може бити направљен као статична библиотека без употребе, што олакшава пренос. Сакупљамо библиотеку са стандардном конфигурацијом и видимо колико простора заузимају. Сваки модул се прикупља у посебној библиотеци.

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

Као што видите из последњег реда, .бсс и .дата не заузимају много простора, али код је већи од 70 МиБ. Јасно је да ако је ово статички повезано са одређеном апликацијом, код ће постати мањи.

Хајде да покушамо да избацимо што више модула како би се саставио минимални пример (који ће, на пример, једноставно избацити ОпенЦВ верзију), па погледамо cmake .. -LA и искључите у опцијама све што се искључује.

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

С једне стране, ово је само један модул библиотеке, са друге стране, ово је без оптимизације компајлера за величину кода (-Os). ~3 МиБ кода је још увек доста, али већ даје наду за успех.

Покрените у емулатору

Много је лакше отклонити грешке на емулатору, па се прво уверите да библиотека ради на кему-у. Као емулирану платформу, изабрао сам Интегратор / ЦП, јер прво, то је такође АРМ, а друго, Ембок подржава графички излаз за ову платформу.

Ембок има механизам за прављење екстерних библиотека, помоћу њега додајемо ОпенЦВ као модул (пропуштајући све исте опције за „минимални“ буилд у облику статичких библиотека), након тога додајем једноставну апликацију која изгледа овако:

version.cpp:

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

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

    return 0;
}

Састављамо систем, покрећемо га - добијамо очекивани излаз.

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

Следећи корак је да покренете неки пример, по могућности један од стандардних које нуде сами програмери. на вашем сајту. ја бирам гранични детектор цанни.

Пример је морао бити мало преписан да би се слика са резултатом приказала директно у баферу оквира. Морао сам ово да урадим, јер. функција imshow() може да црта слике преко КТ, ГТК и Виндовс интерфејса, што, наравно, сигурно неће бити у конфигурацији за СТМ32. У ствари, КТ се такође може покренути на СТМ32Ф7Дисцовери, али о томе ће бити речи у другом чланку 🙂

Након кратког појашњења у ком формату се чува резултат детектора ивица, добијамо слику.

ОпенЦВ на СТМ32Ф7-Дисцовери

оригинална слика

ОпенЦВ на СТМ32Ф7-Дисцовери

Резултат

Ради на СТМ32Ф7Дисцовери

На 32Ф746ГДИСЦОВЕРИ постоји неколико секција хардверске меморије које можемо користити на овај или онај начин

  1. 320КиБ РАМ
  2. 1МиБ флеш за слику
  3. 8МиБ СДРАМ
  4. 16МиБ КСПИ НАНД Фласх
  5. слот за мицроСД картицу

СД картица се може користити за чување слика, али у контексту покретања минималног примера, ово није од велике користи.
Екран има резолуцију 480×272, што значи да ће меморија фрамебуффера бити 522 бајтова на дубини од 240 бита, тј. ово је више од величине РАМ-а, тако да ће фрамебуффер и хеап (који ће бити потребни, укључујући и ОпенЦВ, за складиштење података за слике и помоћне структуре) бити смештени у СДРАМ, све остало (меморија за стекове и друге системске потребе ) ће ићи у РАМ.

Ако узмемо минималну конфигурацију за СТМ32Ф7Дисцовери (избацимо целу мрежу, све команде, направимо стокове што је могуће мање, итд.) и додамо ОпенЦВ са примерима тамо, потребна меморија ће бити следећа:

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

За оне који нису баш упознати са тим који делови где иду, објаснићу: у .text и .rodata упутства и константе (грубо речено, подаци само за читање) леже у .data подаци су променљиви, .bss постоје "нуллед" променљиве, којима је, ипак, потребно место (овај одељак ће "ићи" у РАМ).

Добра вест је да .data/.bss требало би да одговара, али са .text проблем је што постоји само 1МиБ меморије за слику. Може се избацити .text слику из примера и прочитајте је, на пример, са СД картице у меморију при покретању, али фруитс.пнг је тежак око 330КиБ, тако да ово неће решити проблем: већина .text састоји се од ОпенЦВ кода.

Углавном, преостаје само једно - учитавање дела кода на КСПИ флеш (има посебан режим рада за мапирање меморије на системску магистралу, тако да процесор може директно да приступи овим подацима). У овом случају настаје проблем: прво, меморија КСПИ флеш диска није доступна одмах након поновног покретања уређаја (морате посебно да иницијализујете режим мапирања меморије), и друго, не можете да „флешујете“ ову меморију са познати покретач.

Као резултат тога, одлучено је да се повеже сав код у КСПИ, и флешује га самописаним учитавачем који ће примати потребну бинарну датотеку преко ТФТП-а.

Резултат

Идеја да се ова библиотека пренесе у Ембок појавила се пре око годину дана, али је изнова и изнова одлагана из разних разлога. Једна од њих је подршка за либстдц++ и стандардну библиотеку шаблона. Проблем подршке за Ц++ у Ембок-у је ван оквира овог чланка, па ћу овде само рећи да смо успели да остваримо ову подршку у правом износу да би ова библиотека функционисала 🙂

На крају, ови проблеми су превазиђени (барем довољно да ОпенЦВ пример ради) и пример је покренут. Потребно је 40 дугих секунди да плоча тражи границе користећи Цанни филтер. Ово је, наравно, предуго (постоји размишљање о томе како да се ово питање оптимизује, у случају успеха биће могуће написати посебан чланак о томе).

ОпенЦВ на СТМ32Ф7-Дисцовери

Међутим, средњи циљ је био да се направи прототип који ће показати фундаменталну могућност покретања ОпенЦВ-а на СТМ32, односно овај циљ је постигнут, ура!

тл;др: упутства корак по корак

0: Преузмите Ембок изворе, овако:

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

1: Почнимо са склапањем покретачког програма који ће "флешовати" КСПИ флеш диск.

    make confload-arm/stm32f7cube

Сада треба да конфигуришете мрежу, јер. Слику ћемо отпремити преко ТФТП-а. Да бисте подесили ИП адресе плоче и хоста, потребно је да уредите цонф/роотфс/нетворк.

Пример конфигурације:

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 - адресу домаћина са које ће се слика учитати, address - адреса одбора.

Након тога сакупљамо покретач:

    make

2: Уобичајено учитавање боотлоадер-а (извините на игри речи) на плочи - овде нема ничег специфичног, морате то да урадите као и за било коју другу апликацију за СТМ32Ф7Дисцовери. Ако не знате како то да урадите, можете прочитати о томе овде.
3: Састављање слике са конфигурацијом за ОпенЦВ.

    make confload-platform/opencv/stm32f7discovery
    make

4: Извод из ЕЛФ одељака за писање у КСПИ у кспи.бин

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

5: Користећи тфтп, преузмите кспи.бин.бин на КСПИ флеш диск. На хосту, да бисте то урадили, копирајте кспи.бин у основну фасциклу тфтп сервера (обично /срв/тфтп/ или /вар/либ/тфтпбоот/; пакети за одговарајући сервер су доступни у већини популарних дистрибуција, обично се називају тфтпд или тфтп-хпа, понекад морате да урадите systemctl start tftpd.service за почетак).

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

На Ембок-у (тј. у покретачу) потребно је да извршите следећу команду (претпостављамо да сервер има адресу 192.168.2.1):

    embox> qspi_loader qspi.bin 192.168.2.1

6: Са командом goto потребно је да "скочите" у КСПИ меморију. Конкретна локација ће се разликовати у зависности од тога како је слика повезана, ову адресу можете видети помоћу команде mem 0x90000000 (почетна адреса се уклапа у другу 32-битну реч слике); такође ћете морати да означите стек -s, адреса стека је на 0к90000000, пример:

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

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

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

7: Лансирање

    embox> edges 20

и уживајте у претрази границе од 40 секунди 🙂

Ако нешто крене наопако - напишите проблем наше складиште, или на маилинг листу [емаил заштићен], или у коментару овде.

Извор: ввв.хабр.цом

Додај коментар