{"id":37914,"date":"2019-10-31T22:20:31","date_gmt":"2019-10-31T19:20:31","guid":{"rendered":"https:\/\/prohoster.info\/blog\/opencv-na-stm32f7-discovery\/"},"modified":"2019-10-31T22:20:31","modified_gmt":"2019-10-31T19:20:31","slug":"opencv-na-stm32f7-discovery","status":"publish","type":"post","link":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/opencv-na-stm32f7-discovery","title":{"rendered":"OpenCV en STM32F7-Discovery","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"OpenCV en STM32F7-Discovery\" src=\"\/wp-content\/uploads\/2019\/09\/a2248ee685ee210ce8f7781435dd1d5a.jpg\" style=\"display:block;margin: 0 auto;\" \/> Soy uno de los desarrolladores del sistema operativo <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/embox\/embox\">Embox<\/a><\/noindex>, y en este art\u00edculo hablar\u00e9 sobre c\u00f3mo logr\u00e9 ejecutar OpenCV en la placa STM32746G.<\/p>\n<p><\/p>\n<p>Si buscas en un motor de b\u00fasqueda algo como \u00abOpenCV en la placa STM32\u00bb, encontrar\u00e1s muchas personas interesadas en usar esta biblioteca en placas STM32 u otros microcontroladores.<br \/>\nHay varios videos que, seg\u00fan el t\u00edtulo, deber\u00edan demostrar lo que se necesita, pero generalmente (en todos los videos que he visto) en la placa STM32 solo se capturaba la imagen de la c\u00e1mara y se mostraba el resultado en la pantalla, mientras que el procesamiento de la imagen se hac\u00eda en una computadora com\u00fan o en placas m\u00e1s potentes (por ejemplo, Raspberry Pi).<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h1 id=\"pochemu-eto-slozhno\">\u00bfPor qu\u00e9 es complicado?<\/h1>\n<p><\/p>\n<p>La popularidad de las b\u00fasquedas se explica porque OpenCV es la biblioteca de visi\u00f3n por computadora m\u00e1s popular, lo que significa que m\u00e1s desarrolladores est\u00e1n familiarizados con ella, y la posibilidad de ejecutar c\u00f3digo dise\u00f1ado para escritorio en un microcontrolador simplifica mucho el proceso de desarrollo. Pero, \u00bfpor qu\u00e9 todav\u00eda no hay recetas populares listas para resolver este problema?<\/p>\n<p><\/p>\n<p>El problema de usar OpenCV en placas peque\u00f1as se debe a dos caracter\u00edsticas:<\/p>\n<p><\/p>\n<ul>\n<li>Si se compila la biblioteca incluso con un conjunto m\u00ednimo de m\u00f3dulos, en la memoria flash de la STM32F7Discovery no cabe (incluso sin tener en cuenta el sistema operativo) debido al gran tama\u00f1o del c\u00f3digo (varios megabytes de instrucciones)<\/li>\n<li>La propia biblioteca est\u00e1 escrita en C++, por lo que\n<ul>\n<li>Se necesita soporte para el tiempo de ejecuci\u00f3n de C++ (excepciones, etc.)<\/li>\n<li>Hay poco soporte para LibC\/Posix, que normalmente existe en los sistemas operativos para sistemas embebidos: se necesita una biblioteca est\u00e1ndar de C++ y la biblioteca est\u00e1ndar de plantillas STL (vector, etc.)<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><\/p>\n<h1 id=\"portirovanie-na-embox\">Portando a Embox<\/h1>\n<p><\/p>\n<p>Como de costumbre, antes de portar cualquier programa a un sistema operativo, es buena idea intentar compilarlo en la forma en que lo idearon los desarrolladores. En nuestro caso, no hay problemas con esto: se pueden encontrar los fuentes en <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/opencv\/opencv\">github<\/a><\/noindex>, la biblioteca se compila en GNU\/Linux f\u00e1cilmente con cmake.<\/p>\n<p><\/p>\n<p>De las buenas noticias \u2014 OpenCV se puede compilar como una biblioteca est\u00e1tica directamente, lo que hace que el puerto sea m\u00e1s f\u00e1cil. Compilamos la biblioteca con la configuraci\u00f3n est\u00e1ndar y vemos cu\u00e1nto espacio ocupa. Cada m\u00f3dulo se compila en una biblioteca separada.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">&gt; tama\u00f1o lib\/*so --totales\n   texto    datos     bss     dec     hex nombre del archivo\n1945822   15431     960 1962213  1df0e5 lib\/libopencv_calib3d.so\n17081885     170312   25640 17277837    107a38d lib\/libopencv_core.so\n10928229     137640   20192 11086061     a928ed lib\/libopencv_dnn.so\n 842311   25680    1968  869959   d4647 lib\/libopencv_features2d.so\n 423660    8552     184  432396   6990c lib\/libopencv_flann.so\n8034733   54872    1416 8091021  7b758d lib\/libopencv_gapi.so\n  90741    3452     304   94497   17121 lib\/libopencv_highgui.so\n6338414   53152     968 6392534  618ad6 lib\/libopencv_imgcodecs.so\n21323564     155912  652056 22131532    151b34c lib\/libopencv_imgproc.so\n 724323   12176     376  736875   b3e6b lib\/libopencv_ml.so\n 429036    6864     464  436364   6a88c lib\/libopencv_objdetect.so\n6866973   50176    1064 6918213  699045 lib\/libopencv_photo.so\n 698531   13640     160  712331   ade8b lib\/libopencv_stitching.so\n 466295    6688     168  473151   7383f lib\/libopencv_video.so\n 315858    6972   11576  334406   51a46 lib\/libopencv_videoio.so\n76510375     721519  717496 77949390    4a569ce (TOTALES)<\/code><\/pre>\n<p><\/p>\n<p>Como se puede ver en la \u00faltima l\u00ednea, .bss y .data no ocupan mucho espacio, mientras que el c\u00f3digo supera los 70 MiB. Es evidente que si esto se vincula est\u00e1ticamente con una aplicaci\u00f3n espec\u00edfica, el tama\u00f1o del c\u00f3digo ser\u00e1 menor.<\/p>\n<p><\/p>\n<p>Intentaremos eliminar tantos m\u00f3dulos como sea posible para compilar un ejemplo m\u00ednimo (que, por ejemplo, simplemente muestre la versi\u00f3n de OpenCV), as\u00ed que prestemos atenci\u00f3n. <code>cmake .. -LA<\/code> y desactivamos en las opciones todo lo que se puede desactivar.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">        -DBUILD_opencv_java_bindings_generator=OFF \n        -DBUILD_opencv_stitching=OFF \n        -DWITH_PROTOBUF=OFF \n        -DWITH_PTHREADS_PF=OFF \n        -DWITH_QUIRC=OFF \n        -DWITH_TIFF=OFF \n        -DWITH_V4L=OFF \n        -DWITH_VTK=OFF \n        -DWITH_WEBP=OFF<\/code><\/pre>\n<p><\/p>\n<pre><code class=\"plaintext\">&gt; tama\u00f1o lib\/libopencv_core.a --totales\n   texto    datos     bss     dec     hex nombre del archivo\n3317069   36425   17987 3371481  3371d9 (TOTALES)<\/code><\/pre>\n<p><\/p>\n<p>Por un lado, este es solo un m\u00f3dulo de la biblioteca, pero por otro lado, esto es sin optimizaci\u00f3n del compilador por tama\u00f1o de c\u00f3digo (<code>-Os<\/code>). ~3 MiB de c\u00f3digo a\u00fan es bastante, pero ya da esperanzas de \u00e9xito.<\/p>\n<p><\/p>\n<h2 id=\"zapusk-v-emulyatore\">Ejecutar en un emulador<\/h2>\n<p><\/p>\n<p>Es mucho m\u00e1s f\u00e1cil depurarse en un emulador, as\u00ed que primero nos aseguraremos de que la biblioteca funcione en qemu. Como plataforma emulada, eleg\u00ed Integrator\/CP, ya que, por un lado, tambi\u00e9n es ARM, y por otro, Embox soporta salida gr\u00e1fica para esta plataforma.<\/p>\n<p><\/p>\n<p>Embox tiene un mecanismo para ensamblar bibliotecas externas, con el que a\u00f1adimos OpenCV como un m\u00f3dulo (pasando todas las mismas opciones para la \u2018compilaci\u00f3n m\u00ednima\u2019 en forma de bibliotecas est\u00e1ticas), despu\u00e9s de esto a\u00f1ado una aplicaci\u00f3n simple que se ve as\u00ed:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">version.cpp:\n\n#include \n#include \n\nint main() {\n    printf(\"OpenCV: %s\", cv::getBuildInformation().c_str());\n\n    return 0;\n}<\/code><\/pre>\n<p><\/p>\n<p>Compilamos el sistema, ejecutamos \u2014 obtenemos la salida esperada.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">root@embox: \/#opencv_version\nOpenCV:\nConfiguraci\u00f3n general para OpenCV 4.0.1 =====================================\n  Control de versi\u00f3n:               bd6927bdf-dirty\n\n  Plataforma:\n    Marca de tiempo:                   2019-06-21T10:02:18Z\n    Host:                        Linux 5.1.7-arch1-1-ARCH x86_64\n    Objetivo:                      Generic arm-unknown-none\n    CMake:                       3.14.5\n    Generador de CMake:             Unix Makefiles\n    Herramienta de construcci\u00f3n de CMake:            \/usr\/bin\/make\n    Configuraci\u00f3n:               Debug\n\n  Caracter\u00edsticas de CPU\/HW:\n    Baseline:\n      solicitado:                 DETECT\n      deshabilitado:                  VFPV3 NEON\n\n  C\/C++:\n    \u00bfConstruido como bibliotecas din\u00e1micas?:      NO\n<A><\/code><\/pre>\n<p><\/p>\n<p>El siguiente paso es ejecutar alg\u00fan ejemplo, lo mejor es uno est\u00e1ndar que ofrezcan los propios desarrolladores <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.opencv.org\/4.1.0\/examples.html\">en su sitio<\/a><\/noindex>. Eleg\u00ed <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.opencv.org\/4.1.0\/d6\/d56\/samples_2cpp_2edge_8cpp-example.html\">el detector de bordes de Canny<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Tuve que modificar un poco el ejemplo para mostrar la imagen con el resultado directamente en el frame buffer. Hice esto porque la funci\u00f3n <code>imshow()<\/code> puede dibujar im\u00e1genes a trav\u00e9s de interfaces QT, GTK y Windows, las cuales, evidentemente, no estar\u00e1n en la configuraci\u00f3n para STM32. En realidad, tambi\u00e9n se puede ejecutar QT en STM32F7Discovery, pero eso se abordar\u00e1 en otro art\u00edculo \ud83d\ude42<\/p>\n<p><\/p>\n<p>Despu\u00e9s de investigar brevemente en qu\u00e9 formato se almacena el resultado del trabajo del detector de bordes, obtenemos la imagen.<\/p>\n<p>\n<img decoding=\"async\" alt=\"OpenCV en STM32F7-Discovery\" src=\"\/wp-content\/uploads\/2019\/09\/127f90ad8008340d73feb6ece02e52b2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>La imagen original<\/p>\n<p>\n<img decoding=\"async\" alt=\"OpenCV en STM32F7-Discovery\" src=\"\/wp-content\/uploads\/2019\/09\/da34b3ac2561ae9f223acc5c4fe2a597.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><em>Resultado<\/em><\/p>\n<p><\/p>\n<h2 id=\"zapusk-na-stm32f7discovery\">Ejecuci\u00f3n en STM32F7Discovery<\/h2>\n<p><\/p>\n<p>En 32F746GDISCOVERY hay varias secciones de memoria que podemos utilizar de alguna manera<\/p>\n<p><\/p>\n<ol>\n<li>320KiB de RAM<\/li>\n<li>1MiB de memoria flash para la imagen<\/li>\n<li>8MiB de SDRAM<\/li>\n<li>16MiB de memoria flash QSPI NAND<\/li>\n<li>Conector para tarjeta microSD<\/li>\n<\/ol>\n<p><\/p>\n<p>La tarjeta SD se puede usar para almacenar im\u00e1genes, pero en el contexto de ejecutar un ejemplo m\u00ednimo, no es muy \u00fatil.<br \/>\nLa pantalla tiene una resoluci\u00f3n de 480\u00d7272, lo que significa que la memoria para el framebuffer ser\u00e1 de 522,240 bytes con una profundidad de 32 bits, es decir, esto es m\u00e1s que el tama\u00f1o de la memoria RAM, por lo que el framebuffer y la memoria (que ser\u00e1 necesaria tambi\u00e9n para OpenCV, para almacenar datos de im\u00e1genes y estructuras auxiliares) se ubicar\u00e1n en SDRAM, todo lo dem\u00e1s (memoria para pilas y otras necesidades del sistema) ir\u00e1 a RAM.<\/p>\n<p><\/p>\n<p>Si tomas la configuraci\u00f3n m\u00ednima para STM32F7Discovery (eliminando toda la red, todos los comandos, haciendo las pilas lo m\u00e1s peque\u00f1as posible, etc.) y agregas OpenCV con ejemplos, la memoria requerida ser\u00e1 la siguiente:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">   text    data     bss     dec     hex filename\n2876890  459208  312736 3648834  37ad42 build\/base\/bin\/embox<\/code><\/pre>\n<p><\/p>\n<p>Para aquellos que no est\u00e1n muy familiarizados con las secciones a d\u00f3nde se asignan, aclaro: en <code>.text<\/code> y <code>.rodata<\/code> se encuentran instrucciones y constantes (en t\u00e9rminos simples, datos de solo lectura), en <code>.data<\/code> se encuentran datos modificables, en <code>.bss<\/code> se encuentran las \u2018variables nulas\u2019, que, sin embargo, necesitan espacio (esta secci\u00f3n \u2018ir\u00e1\u2019 a RAM).<\/p>\n<p><\/p>\n<p>La buena noticia es que <code>.data<\/code>\/<code>.bss<\/code> deben caber, pero el problema es que <code>.text<\/code> hay solo 1MiB de memoria disponible para la imagen. Se puede eliminar la imagen del ejemplo y leerla, por ejemplo, desde una tarjeta SD a la memoria al iniciar, pero fruits.png pesa aproximadamente 330KiB, as\u00ed que eso no resolver\u00e1 el problema: la mayor parte <code>.text<\/code> consiste precisamente en el c\u00f3digo de OpenCV. <code>.text<\/code> En gran medida, solo queda una opci\u00f3n: cargar parte del c\u00f3digo en una memoria QSPI (tiene un modo de operaci\u00f3n especial para mapear memoria en el bus del sistema, as\u00ed que el procesador podr\u00e1 acceder a esos datos directamente). Sin embargo, surge un problema: primero, la memoria de la memoria flash QSPI no est\u00e1 disponible inmediatamente despu\u00e9s de reiniciar el dispositivo (es necesario inicializar por separado el modo de memoria mapeada); segundo, no se puede 'flashear' esta memoria con un gestor de arranque habitual.<\/p>\n<p><\/p>\n<p>En resumen, solo queda una cosa: cargar parte del c\u00f3digo en la memoria flash QSPI (tiene un modo especial de operaci\u00f3n para mapear la memoria en el bus del sistema, de modo que el procesador pueda acceder a estos datos directamente). Sin embargo, surge un problema: en primer lugar, la memoria flash QSPI no est\u00e1 disponible inmediatamente despu\u00e9s de reiniciar el dispositivo (es necesario inicializar por separado el modo de memoria mapeada), en segundo lugar, no es posible \u2018programar\u2019 esta memoria con el cargador de arranque habitual.<\/p>\n<p><\/p>\n<p>La idea de portar esta biblioteca a Embox surgi\u00f3 hace aproximadamente un a\u00f1o, pero una y otra vez se pospuso por varias razones. Una de ellas es el soporte de libstdc++ y de la biblioteca est\u00e1ndar de plantillas. El problema del soporte de C++ en Embox est\u00e1 m\u00e1s all\u00e1 del alcance de este art\u00edculo, as\u00ed que solo dir\u00e9 aqu\u00ed que logramos obtener este soporte en el volumen necesario para trabajar con esta biblioteca \ud83d\ude42<\/p>\n<p><\/p>\n<h1 id=\"rezultat\">Resultado<\/h1>\n<p><\/p>\n<p>Como resultado, estos problemas fueron superados (al menos en medida suficiente para que funcione el ejemplo de OpenCV), y el ejemplo se ejecut\u00f3. El procesamiento que lleva m\u00e1s tiempo en la placa para buscar los bordes con el filtro de Canny toma 40 segundos. Esto es, por supuesto, demasiado tiempo (hay consideraciones sobre c\u00f3mo optimizar esto, se podr\u00eda escribir un art\u00edculo separado en caso de \u00e9xito).<\/p>\n<p><\/p>\n<p>Sin embargo, el objetivo intermedio era crear un prototipo que mostrara la posibilidad fundamental de ejecutar OpenCV en STM32, y, por lo tanto, este objetivo se logr\u00f3, \u00a1hurra! <\/p>\n<p>\n<img decoding=\"async\" alt=\"OpenCV en STM32F7-Discovery\" src=\"\/wp-content\/uploads\/2019\/09\/a400c72865ec17094efc985908914463.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>tl;dr: gu\u00eda paso a paso<\/p>\n<h4 id=\"tldr-poshagovaya-instrukciya\">0: Descargamos los fuentes de Embox, por ejemplo, as\u00ed:<\/h4>\n<p><\/p>\n<p>git clone https:\/\/github.com\/embox\/embox &amp;&amp; cd .\/embox<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    1: Comencemos con la construcci\u00f3n del gestor de arranque que 'flashear\u00e1' la memoria flash QSPI.<\/code><\/pre>\n<p><\/p>\n<p>1: Comencemos con la construcci\u00f3n del cargador de arranque, que \u2018programar\u00e1\u2019 la memoria flash QSPI.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    hacer confload-arm\/stm32f7cube<\/code><\/pre>\n<p><\/p>\n<p>Ahora necesitamos configurar la red, ya que cargaremos la imagen a trav\u00e9s de TFTP. Para establecer las direcciones IP de la placa y del host, se debe modificar el archivo conf\/rootfs\/network.<\/p>\n<p><\/p>\n<p>Ejemplo de configuraci\u00f3n:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">iface eth0 inet static\n    address 192.168.2.2\n    netmask 255.255.255.0\n    gateway 192.168.2.1\n    hwaddress aa:bb:cc:dd:ee:02<\/code><\/pre>\n<p><\/p>\n<p><code>gateway<\/code> \u2014 direcci\u00f3n del host desde donde se cargar\u00e1 la imagen, <code>address<\/code> \u2014 direcci\u00f3n de la placa.<\/p>\n<p><\/p>\n<p>Despu\u00e9s de esto, compilamos el cargador:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    make<\/code><\/pre>\n<p><\/p>\n<p>2: Carga normal del cargador (disculpen el juego de palabras) en la placa \u2014 aqu\u00ed no hay nada espec\u00edfico, debe hacerse como para cualquier otra aplicaci\u00f3n para STM32F7Discovery. Si no sabe c\u00f3mo hacerlo, puede leer sobre esto. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/embox\/blog\/349034\/\">aqu\u00ed<\/a><\/noindex>.<br \/>\n3: Compilaci\u00f3n de la imagen con la configuraci\u00f3n para OpenCV.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    make confload-platform\/opencv\/stm32f7discovery\n    make<\/code><\/pre>\n<p><\/p>\n<p>4: Extracci\u00f3n de las secciones ELF que se deben escribir en QSPI, en qspi.bin<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    arm-none-eabi-objcopy -O binary build\/base\/bin\/embox build\/base\/bin\/qspi.bin \n        --only-section=.text --only-section=.rodata \n        --only-section='.ARM.ex*' \n        --only-section=.data<\/code><\/pre>\n<p><\/p>\n<p>En el directorio conf hay un script que hace esto, as\u00ed que se puede ejecutar.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    .\/conf\/qspi_objcopy.sh # El binario necesario -- build\/base\/bin\/qspi.bin<\/code><\/pre>\n<p><\/p>\n<p>5: Con tftp cargamos qspi.bin.bin en la memoria flash QSPI. En el host, para esto, hay que copiar qspi.bin en la carpeta ra\u00edz del servidor tftp (normalmente es \/srv\/tftp\/ o \/var\/lib\/tftpboot\/; los paquetes para el servidor correspondiente est\u00e1n en la mayor\u00eda de las distribuciones populares, generalmente se llama tftpd o tftp-hpa, a veces hay que hacer <code>systemctl start tftpd.service<\/code> para iniciar).<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    # \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0434\u043b\u044f tftpd\n    sudo cp build\/base\/bin\/qspi.bin \/srv\/tftp\n    # \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0434\u043b\u044f tftp-hpa\n    sudo cp build\/base\/bin\/qspi.bin \/var\/lib\/tftpboot<\/code><\/pre>\n<p><\/p>\n<p>En Embox (es decir, en el cargador) hay que ejecutar el siguiente comando (suponiendo que la direcci\u00f3n del servidor es 192.168.2.1):<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    embox&gt; qspi_loader qspi.bin 192.168.2.1<\/code><\/pre>\n<p><\/p>\n<p>6: Con el comando <code>goto<\/code> es necesario \u2018saltar\u2019 a la memoria QSPI. La ubicaci\u00f3n espec\u00edfica variar\u00e1 dependiendo de c\u00f3mo se enlace la imagen, esta direcci\u00f3n se puede ver con el comando <code>mem 0x90000000<\/code> (la direcci\u00f3n de inicio se encuentra en la segunda palabra de 32 bits de la imagen); tambi\u00e9n ser\u00e1 necesario establecer la pila con la bandera. <code>-s<\/code>, la direcci\u00f3n de la pila se encuentra en 0x90000000, ejemplo:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    embox&gt;mem 0x90000000\n    0x90000000:     0x20023200  0x9000c27f  0x9000c275  0x9000c275\n                      \u2191           \u2191\n              esta direcci\u00f3n    esta direcci\u00f3n \n                de la pila        de la primera\n                           instrucci\u00f3n\n\n    embox&gt;goto -i 0x9000c27f -s 0x20023200 # La bandera -i es necesaria para prohibir interrupciones durante la inicializaci\u00f3n del sistema\n\n    <A><\/code><\/pre>\n<p><\/p>\n<p>7: Iniciamos<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    embox&gt; edges 20<\/code><\/pre>\n<p><\/p>\n<p>y disfrutamos de una b\u00fasqueda de bordes de 40 segundos \ud83d\ude42<\/p>\n<p><\/p>\n<p>Si algo sale mal, escriba un issue en <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/embox\/embox\">nuestro repositorio<\/a><\/noindex>, o en la lista de correo embox-devel@googlegroups.com, o en los comentarios aqu\u00ed.<\/p>\n<p>Fuente: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/embox\/blog\/457724\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u042f \u043e\u0434\u0438\u043d \u0438\u0437 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b Embox, \u0438 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043f\u0440\u043e \u0442\u043e, \u043a\u0430\u043a \u0443 \u043c\u0435\u043d\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c OpenCV \u043d\u0430 \u043f\u043b\u0430\u0442\u0435 STM32746G. \u0415\u0441\u043b\u0438 \u0432\u0431\u0438\u0442\u044c \u0432 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0438\u043a \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435 &#171;OpenCV on STM32 board&#187;, \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0442\u0435\u0445, \u043a\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u044d\u0442\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043d\u0430 \u043f\u043b\u0430\u0442\u0430\u0445 STM32 \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u043c\u0438\u043a\u0440\u043e\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u0445. \u0415\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0438\u0434\u0435\u043e, \u043a\u043e\u0442\u043e\u0440\u044b\u0435, \u0441\u0443\u0434\u044f [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":28450,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-37914","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u042f \u043e\u0434\u0438\u043d \u0438\u0437 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/opencv-na-stm32f7-discovery\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"es_ES\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47OpenCV \u043d\u0430 STM32F7-Discovery | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u042f \u043e\u0434\u0438\u043d \u0438\u0437 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/opencv-na-stm32f7-discovery\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:20:31+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:20:31+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47OpenCV en STM32F7-Discovery | ProHoster","description":"Soy uno de los desarrolladores del sistema operativo","canonical_url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/opencv-na-stm32f7-discovery","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"es_ES","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47OpenCV \u043d\u0430 STM32F7-Discovery | ProHoster","og:description":"\u042f \u043e\u0434\u0438\u043d \u0438\u0437 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b","og:url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/opencv-na-stm32f7-discovery","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:20:31+00:00","article:modified_time":"2019-10-31T19:20:31+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"37914","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-23 19:45:21","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:18:22","updated":"2026-01-23 19:45:21","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/37914","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/comments?post=37914"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/37914\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media\/28450"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=37914"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=37914"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=37914"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}