OpenCV STM32F7-Discovery-ում

OpenCV STM32F7-Discovery-ում Ես օպերացիոն համակարգի մշակողներից եմ Embox, և այս հոդվածում ես կխոսեմ այն ​​մասին, թե ինչպես կարողացա գործարկել OpenCV-ն STM32746G տախտակի վրա։

Եթե ​​որոնման համակարգում մուտքագրեք «OpenCV on STM32 տախտակի» պես մի բան, կարող եք գտնել բավականին շատ մարդկանց, ովքեր հետաքրքրված են օգտագործել այս գրադարանը STM32 տախտակների կամ այլ միկրոկառավարիչների վրա:
Կան մի քանի տեսանյութեր, որոնք, դատելով անունից, պետք է ցույց տան, թե ինչ է անհրաժեշտ, բայց սովորաբար (բոլոր տեսանյութերում, որոնք ես տեսա) STM32 տախտակի վրա միայն պատկերն էր ստացվում տեսախցիկից և արդյունքը ցուցադրվում էր էկրանին, իսկ պատկերի մշակումն ինքնին կատարվել է կամ սովորական համակարգչի վրա, կամ ավելի հզոր տախտակների վրա (օրինակ՝ Raspberry Pi):

Ինչու՞ է դա դժվար:

Որոնման հարցումների հանրաճանաչությունը բացատրվում է նրանով, որ OpenCV-ն համակարգչային տեսողության ամենատարածված գրադարանն է, ինչը նշանակում է, որ ավելի շատ ծրագրավորողներ ծանոթ են դրան, իսկ աշխատասեղանի համար պատրաստի ծածկագիրը միկրոկոնտրոլերի վրա գործարկելու հնարավորությունը զգալիորեն հեշտացնում է զարգացման գործընթացը: Բայց ինչու դեռևս չկան այս խնդիրը լուծելու հայտնի պատրաստի բաղադրատոմսեր:

Փոքր շալերի վրա OpenCV-ի օգտագործման խնդիրը կապված է երկու առանձնահատկությունների հետ.

  • Եթե ​​գրադարանը կազմեք նույնիսկ մոդուլների նվազագույն հավաքածուով, ապա այն պարզապես չի տեղավորվի նույն STM32F7Discovery-ի ֆլեշ հիշողության մեջ (նույնիսկ առանց OS-ն հաշվի առնելու) շատ մեծ կոդի պատճառով (մի քանի մեգաբայթ հրահանգներ):
  • Գրադարանը ինքնին գրված է C++-ով, ինչը նշանակում է
    • Պահանջվում է աջակցություն դրական գործարկման համար (բացառություններ և այլն)
    • LibC/Posix-ի փոքր աջակցություն, որը սովորաբար հայտնաբերվում է ներկառուցված համակարգերի ՕՀ-ում. Ձեզ անհրաժեշտ է ստանդարտ գումարած գրադարան և ստանդարտ STL ձևանմուշ գրադարան (վեկտոր և այլն):

Տեղափոխում Embox

Ինչպես միշտ, նախքան որևէ ծրագիր օպերացիոն համակարգ տեղափոխելը, լավ գաղափար է փորձել այն կառուցել այն ձևով, որով մշակողները նախատեսել են: Մեր դեպքում դրա հետ կապված խնդիրներ չկան. սկզբնաղբյուրը կարելի է գտնել այստեղ github, գրադարանը կառուցված է GNU/Linux-ի ներքո՝ սովորական cmake-ով։

Լավ նորությունն այն է, որ OpenCV-ն կարող է ստեղծվել որպես ստատիկ գրադարան, ինչը հեշտացնում է տեղափոխումը: Մենք հավաքում ենք գրադարան ստանդարտ կոնֆիգուրով և տեսնում ենք, թե որքան տեղ են դրանք զբաղեցնում: Յուրաքանչյուր մոդուլ հավաքվում է առանձին գրադարանում:

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

Ինչպես տեսնում եք վերջին տողից, .bss-ը և .data-ն շատ տեղ չեն զբաղեցնում, բայց կոդը 70 ՄԲ-ից ավելի է: Հասկանալի է, որ եթե սա ստատիկորեն կապված է կոնկրետ հավելվածի հետ, կոդը կպակասի։

Եկեք փորձենք հնարավորինս շատ մոդուլներ դուրս գցել, որպեսզի նվազագույն օրինակ հավաքվի (որը, օրինակ, պարզապես թողարկի OpenCV տարբերակը), այնպես որ մենք նայում ենք. 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 ՄԲ կոդը դեռ բավականին շատ է, բայց արդեն հաջողության հույս է տալիս:

Գործարկեք էմուլյատորում

Էմուլյատորի վրա վրիպազերծելը շատ ավելի հեշտ է, ուստի նախ համոզվեք, որ գրադարանն աշխատում է qemu-ի վրա: Որպես ընդօրինակված հարթակ, ես ընտրեցի Integrator / CP, քանի որ նախ՝ այն նաև ARM է, և երկրորդ՝ Embox-ն աջակցում է այս հարթակի գրաֆիկական ելքին։

Embox-ն ունի արտաքին գրադարաններ կառուցելու մեխանիզմ, որի միջոցով մենք ավելացնում ենք OpenCV-ն որպես մոդուլ (անցնելով «նվազագույն» կառուցման բոլոր նույն տարբերակները՝ ստատիկ գրադարանների տեսքով), որից հետո ես ավելացնում եմ պարզ հավելված, որն ունի հետևյալ տեսքը.

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() կարող է նկարներ նկարել QT, GTK և Windows ինտերֆեյսների միջոցով, որոնք, իհարկե, հաստատ չեն լինի STM32-ի կոնֆիգուրացիայի մեջ։ Փաստորեն, QT-ն կարող է գործարկվել նաև STM32F7Discovery-ով, բայց դա կքննարկվի մեկ այլ հոդվածում 🙂

Կարճ պարզաբանումից հետո, թե որ ձևաչափով է պահվում եզրային դետեկտորի արդյունքը, ստանում ենք պատկեր։

OpenCV STM32F7-Discovery-ում

օրիգինալ նկար

OpenCV STM32F7-Discovery-ում

Արդյունք

Աշխատում է STM32F7Discovery-ով

32F746GDISCOVERY-ում կան ապարատային հիշողության մի քանի բաժիններ, որոնք մենք կարող ենք օգտագործել այս կամ այն ​​կերպ

  1. 320 ԿԲ RAM
  2. 1 ՄԲ ֆլեշ պատկերի համար
  3. 8 ՄԲ SDRAM
  4. 16 MiB QSPI NAND Flash
  5. microSD քարտի բնիկ

SD քարտը կարող է օգտագործվել պատկերներ պահելու համար, բայց նվազագույն օրինակ գործարկելու համատեքստում դա այնքան էլ օգտակար չէ:
Էկրանի թույլատրելիությունը 480×272 է, ինչը նշանակում է, որ շրջանակային բուֆերային հիշողությունը կլինի 522 բայթ 240 բիթ խորության վրա, այսինքն. սա ավելին է, քան RAM-ի չափը, ուստի framebuffer-ը և կույտը (որը կպահանջվի, ներառյալ OpenCV-ի համար, պատկերների և օժանդակ կառույցների տվյալները պահելու համար) կտեղակայվեն SDRAM-ում, մնացած ամեն ինչ (կույտերի հիշողություն և համակարգի այլ կարիքներ): ) կգնա RAM:

Եթե ​​վերցնենք STM32F7Discovery-ի նվազագույն կոնֆիգուրգը (դուրս նետենք ամբողջ ցանցը, բոլոր հրամանները, հնարավորինս փոքրացնել կույտերը և այլն) և այնտեղ ավելացնել OpenCV օրինակներով, ապա պահանջվող հիշողությունը կլինի հետևյալը.

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

Նրանց համար, ովքեր այնքան էլ ծանոթ չեն, թե որ բաժինները որտեղ են գնում, ես կբացատրեմ .text и .rodata հրահանգները և հաստատունները (կոպիտ ասած, միայն կարդալու տվյալներ) գտնվում են .data տվյալները փոփոխական են, .bss կան «զրոյացված» փոփոխականներ, որոնց, այնուամենայնիվ, տեղ է պետք (այս բաժինը «կգնա» RAM):

Լավ նորությունն այն է, որ .data/.bss պետք է համապատասխանի, բայց հետ .text Խնդիրն այն է, որ պատկերի համար կա ընդամենը 1 ՄԲ հիշողություն: Կարող է դուրս նետվել .text նկարը օրինակից և կարդացեք այն, օրինակ, SD քարտից հիշողության մեջ գործարկման պահին, բայց fruits.png-ը կշռում է մոտ 330 ԿԲ, ուստի դա չի լուծի խնդիրը. .text բաղկացած է OpenCV կոդից:

Մեծ հաշվով, մնում է միայն մեկ բան՝ կոդի մի մասը բեռնել QSPI ֆլեշի վրա (այն ունի աշխատանքի հատուկ ռեժիմ՝ հիշողությունը համակարգային ավտոբուսին քարտեզագրելու համար, որպեսզի պրոցեսորը կարողանա ուղղակիորեն մուտք գործել այս տվյալներ): Այս դեպքում խնդիր է առաջանում. նախ, QSPI ֆլեշ կրիչի հիշողությունը հասանելի չէ սարքը վերագործարկելուց անմիջապես հետո (դուք պետք է առանձին նախաստորագրեք հիշողության քարտեզագրված ռեժիմը), և երկրորդ, դուք չեք կարող «թարթել» այս հիշողությունը: ծանոթ bootloader.

Արդյունքում որոշվեց կապել բոլոր ծածկագրերը QSPI-ում և այն թարթել ինքնուրույն գրված բեռնիչով, որը կստանա անհրաժեշտ երկուականը TFTP-ի միջոցով։

Արդյունք

Այս գրադարանը Embox-ում տեղափոխելու գաղափարը ի հայտ եկավ մոտ մեկ տարի առաջ, բայց նորից ու նորից այն հետաձգվում էր տարբեր պատճառներով։ Դրանցից մեկը libstdc++-ի և ստանդարտ ձևանմուշների գրադարանի աջակցությունն է։ Embox-ում C++-ի աջակցության խնդիրը դուրս է այս հոդվածի շրջանակներից, ուստի այստեղ ես միայն կասեմ, որ մեզ հաջողվեց հասնել այս աջակցությանը ճիշտ չափով, որպեսզի այս գրադարանն աշխատի 🙂

Ի վերջո, այս խնդիրները հաղթահարվեցին (գոնե բավարար է OpenCV օրինակի համար), և օրինակը վազեց: Տախտակի համար պահանջվում է 40 երկար վայրկյան՝ Canny ֆիլտրի միջոցով սահմաններ որոնելու համար: Սա, իհարկե, չափազանց երկար է (կան նկատառումներ, թե ինչպես կարելի է օպտիմալացնել այս հարցը, հաջողության դեպքում հնարավոր կլինի առանձին հոդված գրել այս մասին):

OpenCV STM32F7-Discovery-ում

Այնուամենայնիվ, միջանկյալ նպատակն էր ստեղծել նախատիպ, որը ցույց կտա OpenCV-ն STM32-ի վրա գործարկելու հիմնարար հնարավորությունը, համապատասխանաբար, այս նպատակը իրականացավ, հուր:

tl;dr: քայլ առ քայլ հրահանգներ

0: Ներբեռնեք Embox աղբյուրները, այսպես.

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

1. Սկսենք հավաքելով bootloader, որը «կթափի» QSPI ֆլեշ կրիչը:

    make confload-arm/stm32f7cube

Այժմ դուք պետք է կարգավորեք ցանցը, քանի որ. Մենք կվերբեռնենք պատկերը TFTP-ի միջոցով: Տախտակի և հոսթի IP հասցեները սահմանելու համար հարկավոր է խմբագրել conf/rootfs/ցանցը։

Կազմաձևման օրինակ.

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 - խորհրդի հասցեն.

Դրանից հետո մենք հավաքում ենք bootloader.

    make

2. Բեռնախցիկի սովորական բեռնումը (կներեք բառախաղի համար) տախտակի վրա. այստեղ որևէ կոնկրետ բան չկա, դուք պետք է դա անեք այնպես, ինչպես STM32F7Discovery-ի ցանկացած այլ հավելվածի համար: Եթե ​​չգիտեք, թե ինչպես դա անել, կարող եք կարդալ դրա մասին այստեղ.
3. OpenCV-ի համար կոնֆիգուրով պատկերի կազմում:

    make confload-platform/opencv/stm32f7discovery
    make

4. Քաղվածք ELF բաժիններից, որը պետք է գրվի QSPI-ին 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

Conf գրացուցակում կա սկրիպտ, որն անում է դա, այնպես որ կարող եք գործարկել այն

    ./conf/qspi_objcopy.sh # Нужный бинарник -- build/base/bin/qspi.bin

5. Օգտագործելով tftp, ներբեռնեք qspi.bin.bin-ը QSPI ֆլեշ կրիչում: Հոսթում, դա անելու համար, qspi.bin-ը պատճենեք tftp սերվերի արմատային թղթապանակում (սովորաբար /srv/tftp/ կամ /var/lib/tftpboot/; համապատասխան սերվերի փաթեթները հասանելի են ամենատարածված բաշխումներում, սովորաբար կոչվում են. tftpd կամ tftp-hpa, երբեմն դուք պետք է անեք 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

Embox-ում (այսինքն՝ bootloader-ում), դուք պետք է կատարեք հետևյալ հրամանը (ենթադրում ենք, որ սերվերն ունի 192.168.2.1 հասցեն).

    embox> qspi_loader qspi.bin 192.168.2.1

6: Հրամանով goto դուք պետք է «ցատկեք» QSPI հիշողության մեջ: Կոնկրետ գտնվելու վայրը կտարբերվի՝ կախված նրանից, թե ինչպես է կապված պատկերը, դուք կարող եք տեսնել այս հասցեն հրամանով mem 0x90000000 (սկզբնական հասցեն տեղավորվում է պատկերի երկրորդ 32-բիթանոց բառի մեջ); Ձեզ անհրաժեշտ կլինի նաև դրոշակավորել կույտը -s, դարակի հասցեն է 0x90000000, օրինակ՝

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

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

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

7: Գործարկում

    embox> edges 20

և վայելեք 40 վայրկյան սահմանային որոնումը 🙂

Եթե ​​ինչ-որ բան սխալ է, գրեք խնդիրը մեր պահոցը, կամ փոստային ցուցակում [էլեկտրոնային փոստով պաշտպանված], կամ մեկնաբանությունում այստեղ։

Source: www.habr.com

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