OpenCV على اكتشاف STM32F7

أنا واحد من مطوري نظام التشغيل Embox ، وفي هذه المقالة سأتحدث عن كيف تمكنت من تشغيل OpenCV على لوحة STM32746G.


إذا كنت تقود محرك البحث إلى شيء مثل "OpenCV على لوحة STM32" ، فيمكنك العثور على عدد غير قليل ممن يرغبون في استخدام هذه المكتبة على لوحات STM32 أو وحدات تحكم دقيقة أخرى.
هناك العديد من مقاطع الفيديو التي ، بناءً على الاسم ، يجب أن توضح ما هو مطلوب ، ولكن عادة (في جميع مقاطع الفيديو التي رأيتها) على لوحة STM32 ، تم استلام الصورة فقط من الكاميرا وتم عرض النتيجة على الشاشة ، وتمت معالجة الصور إما على على جهاز كمبيوتر عادي ، أو على لوحات أكثر قوة (على سبيل المثال ، Raspberry Pi).


لماذا هو صعب؟


تفسر شعبية استعلامات البحث من خلال حقيقة أن OpenCV هي مكتبة رؤية الكمبيوتر الأكثر شيوعًا ، مما يعني أن المزيد من المطورين على دراية بها ، كما أن القدرة على تشغيل التعليمات البرمجية الجاهزة لسطح المكتب على المتحكم الدقيق تسهل عملية التطوير إلى حد كبير. ولكن لماذا لا توجد حتى الآن وصفات شعبية جاهزة لحل هذه المشكلة؟


ترتبط مشكلة استخدام OpenCV على اللوحات الصغيرة بميزتين:


  • إذا قمت بتجميع المكتبة حتى مع وجود مجموعة صغيرة من الوحدات ، فإنها ببساطة لن تتلاءم مع ذاكرة الفلاش الخاصة بنفس STM32F7Discovery (حتى بدون مراعاة نظام التشغيل) بسبب الكود الكبير جدًا (عدة ميغابايت من التعليمات)
  • المكتبة نفسها مكتوبة بلغة C ++ ، وهذا يعني
    • بحاجة إلى دعم لوقت تشغيل إيجابي (باستثناء ، إلخ)
    • يوجد القليل من الدعم لـ LibC / Posix ، والذي يوجد عادةً في نظام التشغيل للأنظمة المدمجة - تحتاج إلى مكتبة قياسية من الإيجابيات ومكتبة قياسية من قوالب STL (ناقل ، إلخ)

ترقية إلى Embox


كالمعتاد ، قبل نقل أي برامج إلى نظام التشغيل ، من المستحسن محاولة تجميعها بالشكل الذي قصده المطورون. في حالتنا ، لا توجد مشاكل في هذا - يمكن العثور على المصادر على جيثب ، المكتبة مبنية تحت جنو / لينكس مع 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 ميجابايت. من الواضح أنه إذا تم ربط ذلك بشكل ثابت بتطبيق معين ، فسيصبح الرمز أصغر.


دعونا نحاول التخلص من أكبر عدد ممكن من الوحدات النمطية بحيث يتم إنشاء مثال cmake .. -LA (والذي ، على سبيل المثال ، يعرض فقط إصدار 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 ، ولكن سيتم مناقشة ذلك في مقال آخر :)


بعد توضيح قصير في أي تنسيق يتم تخزين نتيجة كاشف الحدود ، نحصل على صورة.



الصورة الأصلية



يؤدي


يعمل على STM32F7Discovery


هناك العديد من أقسام الأجهزة على 32F746GDISCOVERY التي يمكننا استخدامها على أي حال


  1. ذاكرة الوصول العشوائي 320 كيلو بايت
  2. 1MiB فلاش للصورة
  3. 8MiB SDRAM
  4. محرك فلاش 16 ميجابايت QSPI NAND
  5. فتحة بطاقة MicroSD

يمكن استخدام بطاقة SD لتخزين الصور ، ولكن في سياق تشغيل مثال بسيط ، هذا ليس مفيدًا للغاية.
تبلغ دقة الشاشة 480 × 272 ، مما يعني أن ذاكرة أداة إلغاء الإطارات ستكون 52240 بايت على عمق 32 بت ، أي هذا أكثر من حجم ذاكرة الوصول العشوائي ، لذلك سنضع أداة تثبيت الإطارات ومجموعة (التي ستكون ضرورية لـ OpenCV لتخزين البيانات للصور والهياكل المساعدة) في SDRAM ، وكل شيء آخر (ذاكرة للأكوام واحتياجات النظام الأخرى) سينتقل إلى ذاكرة الوصول العشوائي .


إذا أخذنا الحد الأدنى من التهيئة لـ STM32F7Discovery (طرد الشبكة بالكامل ، وجميع الأوامر ، وجعل المكدسات أصغر ما يمكن ، وما إلى ذلك) وأضف OpenCV مع أمثلة هناك ، مع الذاكرة المطلوبة ، سيكون التالي:


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

بالنسبة لأولئك الذين ليسوا على دراية بالأقسام التي يتم طيها ، سأشرح لك: التعليمات والثوابت (تقريبًا ، البيانات للقراءة فقط) في .rodata و .rodata ، البيانات قابلة للتغيير في .data ، و "صفر" في .bss المتغيرات التي ، مع ذلك ، تحتاج إلى مكان (هذا القسم سوف "يذهب" إلى ذاكرة الوصول العشوائي).


والخبر السار هو أن .data / .bss يجب أن يتناسب ، لكن مع .text المشكلة هي أن هناك فقط 1 ميغا بايت من الذاكرة للصورة. يمكنك .text الصورة من المثال من النص .text وقراءتها ، على سبيل المثال ، من بطاقة SD إلى الذاكرة عند بدء التشغيل ، ولكن يزن ثمرات png حوالي 330 كيلوبايت ، لذلك لن يحل هذا المشكلة: يتكون معظم .text من رمز OpenCV.


بشكل عام ، لا يوجد سوى شيء واحد وهو تحميل جزء من الشفرة على محرك أقراص فلاش QSPI (يحتوي على وضع تشغيل خاص لتعيين الذاكرة إلى ناقل النظام ، بحيث يمكن للمعالج الوصول إلى هذه البيانات مباشرة). في هذه الحالة ، تنشأ مشكلة: أولاً ، لا تتوفر ذاكرة محرك أقراص فلاش QSPI فور إعادة تشغيل الجهاز (تحتاج إلى تهيئة وضع الذاكرة المعين بشكل منفصل) ، وثانياً ، لا يمكنك فلاش هذه الذاكرة باستخدام أداة تحميل التشغيل المعتادة.


نتيجة لذلك ، تقرر ربط جميع الشفرات في QSPI ، وفلاشها مع أداة تحميل ، والتي ستتلقى الثنائية اللازمة عبر TFTP.


يؤدي


جاءت فكرة نقل هذه المكتبة إلى Embox قبل حوالي عام ، ولكن مرارًا وتكرارًا تأخرت لأسباب متعددة. واحد منهم هو دعم libstdc ++ ومكتبة قالب ستاندارت. إن مشكلة دعم C ++ في Embox تتجاوز نطاق هذه المقالة ، لذلك أنا فقط أقول إننا تمكنا من تحقيق هذا الدعم بالقدر المناسب لكي تعمل هذه المكتبة :)


في النهاية ، تم التغلب على هذه المشكلات (على الأقل بما يكفي لمثال OpenCV للعمل) ، وبدأ المثال. 40 ثانية طويلة تأخذ اللوحة للبحث عن الحدود بواسطة مرشح Canny. هذا ، بالطبع ، طويل جدًا (هناك اعتبارات حول كيفية تحسين هذه المسألة ، سيكون من الممكن كتابة مقالة منفصلة حول هذا الموضوع إذا نجحت).




ومع ذلك ، كان الهدف الوسيط هو إنشاء نموذج أولي يوضح الإمكانية الأساسية لتشغيل OpenCV على STM32 ، على التوالي ، تم تحقيق هذا الهدف ، هتافات!

tl ؛ د: تعليمات خطوة بخطوة


0: قم بتنزيل مصادر Embox ، على سبيل المثال مثل هذا:


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

1: لنبدأ بإنشاء أداة تحميل التشغيل التي "تومض" محرك فلاش QSPI.


  make confload-arm/stm32f7cube 

الآن تحتاج إلى تكوين الشبكة ، لأن سنقوم بتحميل الصورة عبر TFTP. من أجل تعيين عناوين IP للوحة والمضيف ، تحتاج إلى تعديل ملف conf / rootfs / network.


مثال التكوين:


 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: تحميل أداة تحميل الإقلاع العادية (آسف للتورية) على السبورة - لا يوجد شيء محدد هنا ، تحتاج إلى القيام بذلك كما هو الحال مع أي تطبيق آخر لـ 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 (على سبيل المثال ، في أداة تحميل التشغيل) ، تحتاج إلى تشغيل الأمر التالي (نفترض أن لدى الخادم العنوان 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 ثانية :)


إذا حدث خطأ ما - اكتب مشكلة في مستودعنا أو في القائمة البريدية embox-devel@googlegroups.com أو في التعليقات هنا.

Source: https://habr.com/ru/post/ar457724/


All Articles