{"id":11853,"date":"2026-05-17T08:10:15","date_gmt":"2026-05-17T06:10:15","guid":{"rendered":"https:\/\/bitacora.eniac2000.com\/?p=11853"},"modified":"2026-05-17T10:08:40","modified_gmt":"2026-05-17T08:08:40","slug":"generacion-automatica-de-indicadores-para-videos-deportivos-con-ia-generativa","status":"publish","type":"post","link":"https:\/\/bitacora.eniac2000.com\/?p=11853","title":{"rendered":"Generaci\u00f3n autom\u00e1tica de indicadores para v\u00eddeos deportivos con IA generativa"},"content":{"rendered":"\n<p>Otro de los proyectos en los que he aplicado de manera exitosa la IA generativa ha sido el de c\u00f3mo proporcionar informaci\u00f3n contextual en v\u00eddeos deportivos. Soy un aficionado al ciclismo de monta\u00f1a y gravel, y me gusta grabar v\u00eddeos deportivos con el dron y con la c\u00e1mara de acci\u00f3n, y subir el contenido a redes sociales. Uno de los problemas que ven\u00eda observando en este tipo de v\u00eddeos era la falta de informaci\u00f3n de contexto relativo al recorrido que est\u00e1s realizando: velocidad, altitud, perfil de la etapa&#8230; Algo que era una pena, dado que hay una gran cantidad de metainformaci\u00f3n a tu disposici\u00f3n por el mero hecho de grabar el v\u00eddeo. Y m\u00e1s si, como es mi caso, registrar el recorrido mediante GPS con alguna aplicaci\u00f3n deportiva.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/bitacora.eniac2000.com\/wp-content\/uploads\/2026\/05\/composite_preview-1024x576.jpg\" alt=\"\" class=\"wp-image-11854\" srcset=\"https:\/\/bitacora.eniac2000.com\/wp-content\/uploads\/2026\/05\/composite_preview-1024x576.jpg 1024w, https:\/\/bitacora.eniac2000.com\/wp-content\/uploads\/2026\/05\/composite_preview-300x169.jpg 300w, https:\/\/bitacora.eniac2000.com\/wp-content\/uploads\/2026\/05\/composite_preview-768x432.jpg 768w, https:\/\/bitacora.eniac2000.com\/wp-content\/uploads\/2026\/05\/composite_preview.jpg 1280w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Fotograma de una secuencia de v\u00eddeo con los indicadores<\/figcaption><\/figure>\n\n\n\n<p>As\u00ed fue c\u00f3mo me decid\u00ed a desarrollar una aplicaci\u00f3n con IA generativa que permitiera extraer esta metainformaci\u00f3n para enriquecer el contexto de los v\u00eddeos deportivos. La idea de partida era generar una serie de indicadores para mostrar la informaci\u00f3n m\u00e1s relevante de una etapa ciclista, a saber:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Veloc\u00edmetro semicircular<\/strong>, con indicaci\u00f3n de la velocidad actual con respecto al m\u00e1ximo de la etapa<\/li>\n\n\n\n<li><strong>Br\u00fajula<\/strong>, o mejor dicho, rosa de los vientos, para conocer el rumbo actual<\/li>\n\n\n\n<li><strong>Minimapa con traza GPS,<\/strong> para tener una indicaci\u00f3n visual del recorrido y el punto de progreso en el mismo. <\/li>\n\n\n\n<li>I<strong>ndicador vertical de altitud<\/strong>, con referencia del incremento\/decremento de altitud relativa, e indicaci\u00f3n de altitud absoluta con respecto al nivel del mar<\/li>\n\n\n\n<li><strong>Perfil de elevaci\u00f3n de etapa<\/strong> con progreso respecto al total de la etapa<\/li>\n\n\n\n<li><strong>Barra de distancia<\/strong>, igualmente con progreso respecto al total de la etapa<\/li>\n<\/ul>\n\n\n\n<p>En este sentido, he realizado una distinci\u00f3n entre indicadores de \u00abcontexto global\u00bb (minimapa, perfil de elevaci\u00f3n y barra de progreso), que est\u00e1n pensandos para mostrar informaci\u00f3n de la ruta completa si tienes registrado el recorrido en GPS, y que muestran esta informaci\u00f3n con el tramo del corte del dron destacado dentro de ella; y los indicadores \u00ablocales\u00bb (veloc\u00edmetro, br\u00fajula, barra de altitud), que siguen usando exclusivamente datos del del corte de v\u00eddeo.<\/p>\n\n\n\n<p>Adem\u00e1s, el objetivo era generar toda esta informaci\u00f3n de manera completamente autom\u00e1tica, y generar v\u00eddeos <em>overlay<\/em> ajustados al tama\u00f1o de los cortes de v\u00eddeo grabados, para facilitar la edici\u00f3n posterior. Hice un primer proceso de investigaci\u00f3n con Claude Code para evaluar la viabilidad del proyecto, lo que me confirm\u00f3 que era factible e, incluso, tras algunas iteraciones, me permiti\u00f3 incorporar algunas ideas adicionales al proyecto. EL origen de la informaci\u00f3n a utilizar ser\u00edan los ficheros SRT que los drones DJI generan de manera complementaria a la pista MP4, y donde almacenan toda la informaci\u00f3n de contexto que el dron genera. As\u00ed, prepar\u00e9 un CLAUDE.md y un prompt adecuados, y pude empezar a implementar la aplicaci\u00f3n.<\/p>\n\n\n\n<p>Enfoqu\u00e9 el desarrollo como un proceso estructurado en fases iterativas, en el que fui implementando distintos aspectos del proceso, a saber:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong><em>Parser<\/em> de telemetr\u00eda y estructura base<\/strong>: El punto de partida fue entender el formato SRT que generan los drones DJI, como es mi caso. Cada fotograma del v\u00eddeo tiene asociada una entrada con coordenadas GPS, altitud relativa y absoluta, e informaci\u00f3n de c\u00e1mara. El primer reto fue que los dos modelos de dron disponibles (DJI Neo y Mini 3 Pro) usan formatos ligeramente distintos: diferente nombre del contador de frames (FrameCnt vs SrtCnt), diferente espaciado en los campos y campos exclusivos de cada modelo. Se implement\u00f3 un <em>parser<\/em> flexible capaz de manejar ambos formatos y extraer los datos necesarios a un DataFrame de <em>pandas<\/em>. El punto clave de este paso es que ninguno de los dos modelos incluye velocidad en el SRT, as\u00ed que hubo que calcularla a partir de la distancia geod\u00e9sica entre coordenadas GPS consecutivas, teniendo en cuenta que el GPS del dron s\u00f3lo actualiza cada ~3 fotogramas. Lo mismo con el rumbo (bearing), calculado por trigonometr\u00eda esf\u00e9rica entre posiciones sucesivas.<\/li>\n\n\n\n<li><strong>Dise\u00f1o de widgets y composici\u00f3n visual<\/strong>: Se dise\u00f1aron seis indicadores estilo HUD, cada uno como m\u00f3dulo independiente renderizado con <em>matplotlib<\/em> sobre fondo transparente:\n<ul class=\"wp-block-list\">\n<li><strong>Veloc\u00edmetro semicircular con aguja animada<\/strong> y escala din\u00e1mica adaptada a la velocidad m\u00e1xima del recorrido.<\/li>\n\n\n\n<li><strong>Br\u00fajula con rosa de los vientos<\/strong> fija y flecha de direcci\u00f3n rotada seg\u00fan el rumbo calculado.<\/li>\n\n\n\n<li><strong>Minimapa con la traza GPS <\/strong>completa y un indicador de posici\u00f3n actual, coloreado por pendiente.<\/li>\n\n\n\n<li><strong>Barra vertical de altitud<\/strong> con degradado verde-naranja y marcador de posici\u00f3n.<\/li>\n\n\n\n<li><strong>Perfil de elevaci\u00f3n<\/strong> mostrando distancia vs. altitud con relleno de progreso y color por pendiente.<\/li>\n\n\n\n<li>B<strong>arra de progreso horizontal<\/strong> con distancia recorrida, total y tiempo transcurrido.<br><br>Se implement\u00f3 un compositor que instancia los indicadores, los posiciona sobre un lienzo RGBA transparente respetando m\u00e1rgenes y sin solapamientos, y escala autom\u00e1ticamente todo en funci\u00f3n de la resoluci\u00f3n del v\u00eddeo fuente (referencia base: 1920&#215;1080).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong><em>Pipeline<\/em> de renderizado con ffmpeg<\/strong>: El renderizado procesa fotograma a fotograma: para cada fotograma del v\u00eddeo se interpola la telemetr\u00eda al <em>timestamp<\/em> exacto, se componen los indicadores sobre un lienzo transparente y se env\u00eda el resultado como RGBA en bruto a ffmpeg por stdin. La salida es un v\u00eddeo con canal alpha(codec qtrle en MOV o PNG en MP4) listo para superponer como pista de <em>overlay<\/em> en DaVinci Resolve. El suavizado de la telemetr\u00eda fue clave para la calidad visual: media m\u00f3vil de 21 frames para velocidad y rumbo (con descomposici\u00f3n sen\/cos para manejar el cruce 360\u00b0\/0\u00b0), y ventanas m\u00e1s cortas para altitud y pendiente.<\/li>\n\n\n\n<li><strong>Integraci\u00f3n de GPX para ruta completa<\/strong>: Los cortes del dron cubren s\u00f3lo fragmentos de una ruta de ciclismo. Al a\u00f1adir soporte para ficheros GPX (exportados desde Strava, Garmin, etc.), los indicadores de \u00abcontexto global\u00bb (minimapa, perfil de elevaci\u00f3n y barra de progreso) pueden mostrar la ruta completa, con el tramo del corte del dron destacado dentro de ella. Los widgets \u00ablocales\u00bb (veloc\u00edmetro, br\u00fajula, barra de altitud) siguen usando exclusivamente datos del SRT.<\/li>\n\n\n\n<li><strong><em>Fallback<\/em> de GPS desde GPX<\/strong>: El DJI Neo tiene un problema frecuente: al inicio de cada clip, el GPS a\u00fan no ha fijado se\u00f1al y devuelve coordenadas (0, 0) durante decenas de frames. Se implement\u00f3 un sistema de <em>fallback<\/em> autom\u00e1tico que, cuando detecta frames sin GPS v\u00e1lido y hay un GPX disponible, rellena latitud, longitud y velocidad interpolando temporalmente desde el GPX. La velocidad se calcula a resoluci\u00f3n nativa del GPX (1 Hz) antes de interpolar, para evitar artefactos de precisi\u00f3n que surg\u00edan al calcularla entre posiciones interpoladas a 30 fps.<\/li>\n\n\n\n<li><strong>Detecci\u00f3n autom\u00e1tica de <em>offset<\/em> UTC: <\/strong>La correlaci\u00f3n temporal entre el SRT del dron y el GPX de la actividad requiere conocer la zona horaria: el SRT usa hora local sin indicador de zona, mientras que el GPX almacena timestamps en UTC. Inicialmente se usaba un offset fijo (CEST = UTC+2), pero esto<br>fallar\u00eda con grabaciones de invierno (CET = UTC+1) o en otras zonas horarias. Se implement\u00f3 una detecci\u00f3n autom\u00e1tica, comparando el creation_time UTC del MP4 (extra\u00eddo con ffprobe) con el primer <em>datetime<\/em> del SRT, eliminando cualquier dependencia de la zona horaria.<\/li>\n\n\n\n<li><strong>Soporte para DJI Osmo Action 5 Pro: <\/strong>Una peque\u00f1a evoluci\u00f3n sobre mi idea base. En mi caso, tambi\u00e9n grabo determinadas secuencias con una c\u00e1mara de acci\u00f3n, la DJI Osmo Action 5 Pro. \u00c9sta graba v\u00eddeo con un fichero LRF que contiene metadatos <em>protobuf<\/em> (aceler\u00f3metro, par\u00e1metros de exposici\u00f3n), pero sin ning\u00fan dato de posici\u00f3n GPS. Se a\u00f1adi\u00f3 un modo &#8211;origin action que genera telemetr\u00eda sint\u00e9tica completa a partir de un fichero GPX: usando el creation_time UTC del MP4 como referencia temporal, se interpola posici\u00f3n, altitud, distancia y velocidad del GPX a la frecuencia de frames del v\u00eddeo mediante np.interp vectorizado. La altitud relativa se calcula respecto al punto de inicio del v\u00eddeo, no del GPX. Un problema sutil surgi\u00f3 en esta fase: el procesador de telemetr\u00eda recalculaba la distancia acumulada desde cero a partir de las coordenadas, machacando las distancias originales del GPX. Esto hac\u00eda que el perfil de elevaci\u00f3n mostrara el progreso desde el inicio de la ruta en lugar de desde la posici\u00f3n real donde empieza el v\u00eddeo. Se resolvi\u00f3 preservando las distancias GPX originales cuando ya vienen calculadas en el DataFrame de entrada.<\/li>\n\n\n\n<li><strong>Documentaci\u00f3n del proyecto<\/strong><\/li>\n<\/ol>\n\n\n\n<p>Como resultado final, para un v\u00eddeo se generan los siguientes indicadores:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Indicador<\/th><th>Descripci\u00f3n<\/th><th>Posici\u00f3n<\/th><\/tr><\/thead><tbody><tr><td><strong>Veloc\u00edmetro<\/strong><\/td><td>Veloc\u00edmetro semicircular con aguja animada. Rango din\u00e1mico seg\u00fan la velocidad m\u00e1xima del SRT. Aguja naranja, roja a velocidades altas.<\/td><td>Inferior izquierda<\/td><\/tr><tr><td><strong>Br\u00fajula<\/strong><\/td><td>Indicador de rumbo con puntos cardinales. El rumbo se calcula a partir de transiciones GPS, suavizado para evitar saltos.<\/td><td>Lateral derecho<\/td><\/tr><tr><td><strong>Minimapa<\/strong><\/td><td>Traza GPS de la ruta con marcador de posici\u00f3n actual y color por pendiente.<\/td><td>Superior derecha<\/td><\/tr><tr><td><strong>Indicador de altitud<\/strong><\/td><td>Barra vertical que muestra la altitud relativa actual dentro del rango m\u00edn\/m\u00e1x del recorrido.<\/td><td>Centro izquierda<\/td><\/tr><tr><td><strong>Perfil de elevaci\u00f3n<\/strong><\/td><td>Gr\u00e1fica distancia frente altitud mostrando el perfil completo de la ruta con relleno de progreso.<\/td><td>Inferior centro<\/td><\/tr><tr><td><strong>Barra de progreso<\/strong><\/td><td>Barra horizontal con la distancia recorrida sobre la distancia total.<\/td><td>Superior centro<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Todos los indicadores se renderizan sobre fondo completamente transparente y se escalan autom\u00e1ticamente seg\u00fan la resoluci\u00f3n del v\u00eddeo de origen, ya sea 720p, 1080p o 4K, para que se vean correctamente independientemente del tama\u00f1o del v\u00eddeo.<\/p>\n\n\n\n<p>Posteriormente, el proceso para incorporar los indicadores a la secuencia de v\u00eddeo es muy simple, ya sea en DaVinci Resolve, KDEnlive o cualquier otro editor de v\u00eddeo similar:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Colocar el metraje original del DJI en la pista V1<\/li>\n\n\n\n<li>Colocar el v\u00eddeo overlay en la pista V2 (encima)<\/li>\n\n\n\n<li>El canal <em>alpha<\/em> se reconoce autom\u00e1ticamente: los indicadores de telemetr\u00eda aparecen sobre el metraje sin necesidad de <em>keying<\/em> ni efectos<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"580\" src=\"https:\/\/bitacora.eniac2000.com\/wp-content\/uploads\/2026\/05\/Captura-de-pantalla-2026-05-17-a-las-8.04.18-1024x580.png\" alt=\"\" class=\"wp-image-11855\" srcset=\"https:\/\/bitacora.eniac2000.com\/wp-content\/uploads\/2026\/05\/Captura-de-pantalla-2026-05-17-a-las-8.04.18-1024x580.png 1024w, https:\/\/bitacora.eniac2000.com\/wp-content\/uploads\/2026\/05\/Captura-de-pantalla-2026-05-17-a-las-8.04.18-300x170.png 300w, https:\/\/bitacora.eniac2000.com\/wp-content\/uploads\/2026\/05\/Captura-de-pantalla-2026-05-17-a-las-8.04.18-768x435.png 768w, https:\/\/bitacora.eniac2000.com\/wp-content\/uploads\/2026\/05\/Captura-de-pantalla-2026-05-17-a-las-8.04.18-1536x869.png 1536w, https:\/\/bitacora.eniac2000.com\/wp-content\/uploads\/2026\/05\/Captura-de-pantalla-2026-05-17-a-las-8.04.18.png 1629w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Interfaz de DaVinci Resolve, para un v\u00eddeo generado con la Osmo Action 5 Pro<\/figcaption><\/figure>\n\n\n\n<p>Este ha sido el primero de los v\u00eddeos donde he aplicado la generaci\u00f3n autom\u00e1tica de indicadores. Se trata de un breve recorrido gravel por las cercan\u00edas de Forcarey, realizado ayer, 16 de mayo de 2026. Estuve explorando viejos tramos de carretera abandonados, para volver a Forcarey por A M\u00e1moa y Li\u00f1ares:<\/p>\n\n\n\n<iframe loading=\"lazy\" width=\"800\" height=\"450\" src=\"https:\/\/www.youtube.com\/embed\/KtW4boaAWoY?si=X7zGbS07DgZ98UqI\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n\n\n\n<p>Tengo algunas mejoras en mente, pero el proyecto es actualmente completamente funcional, y permite, de una manera extremadamente sencilla, aprovechar toda esa informaci\u00f3n de contexto para enriquecer la visualizaci\u00f3n de v\u00eddeos deportivos. Informaci\u00f3n que, de otra manera, se desaprovechar\u00eda.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Otro de los proyectos en los que he aplicado de<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[24,8,13],"tags":[1959,507,537,538,1951,745,824,1361,1606],"series":[],"class_list":["post-11853","post","type-post","status-publish","format-standard","hentry","category-ciclismo","category-deporte","category-informatica","tag-claude-code","tag-davinci-resolve","tag-dji-mini-3-pro","tag-dji-neo","tag-dji-osmo-action-5-pro","tag-gps","tag-ia","tag-python","tag-telemetria"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=\/wp\/v2\/posts\/11853","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=11853"}],"version-history":[{"count":3,"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=\/wp\/v2\/posts\/11853\/revisions"}],"predecessor-version":[{"id":11859,"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=\/wp\/v2\/posts\/11853\/revisions\/11859"}],"wp:attachment":[{"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=11853"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=11853"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=11853"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=%2Fwp%2Fv2%2Fseries&post=11853"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}