--- id: "0036" title: "C++ image_canvas + webcam_texture" status: pendiente type: feature domain: - cpp-stack scope: multi-app priority: baja depends: [] blocks: [] related: [] created: 2026-05-17 updated: 2026-05-17 tags: [] --- # 0036 — C++ image_canvas + webcam_texture ## APP Metadata | Campo | Valor | |-------|-------| | **ID** | 0036 | | **Estado** | pendiente | | **Prioridad** | baja | | **Tipo** | feature — C++ core/gfx (cpp/functions/core, cpp/functions/gfx) | ## Dependencias `gl_texture_load_cpp_gfx` (issue 0026) — recomendado. `tokens_cpp_core`. Independiente de los demas. **Desbloquea:** UIs para etiquetado/anotacion de imagenes (CV, OCR debugging) y entrada de webcam para `shaders_lab` reactivo a video. --- ## Objetivo Dos primitivos: 1. **`image_canvas_cpp_core`** — viewer de imagen con pan/zoom + capa de anotaciones (rectangulos, puntos, polilineas, texto). Drag para crear nuevas anotaciones; click para seleccionar; tecla Del para borrar. 2. **`webcam_texture_cpp_gfx`** — captura de webcam (V4L2 en Linux, Media Foundation en Windows) → GL texture actualizada cada frame. API parejo a `audio_capture`. ## Contexto Casos de uso identificados: - Inspeccionar resultados de un detector (rectangulos overlay). - Etiquetar manualmente datasets pequeños in-app. - Pasar webcam a shaders en `shaders_lab` (filtros video en tiempo real). Ningun primitivo del registry actual cubre estos casos. ## Arquitectura ``` cpp/functions/core/ ├── image_canvas.h # NEW ├── image_canvas.cpp # NEW └── image_canvas.md # NEW (impure component) cpp/functions/gfx/ ├── webcam_texture.h # NEW ├── webcam_texture.cpp # NEW └── webcam_texture.md # NEW (impure) cpp/apps/primitives_gallery/ ├── demos_image_webcam.cpp # NEW ├── demos.h # MOD ├── main.cpp # MOD └── CMakeLists.txt # MOD ``` ### API propuesta ```cpp namespace fn { // --- image_canvas --- struct Annotation { enum Kind { Rect, Point, Polyline, Text } kind; std::vector points; // image-space coords (no screen) ImU32 color = IM_COL32(255, 80, 80, 255); std::string label; }; struct ImageCanvasState { GLuint texture = 0; // caller-owned int img_w = 0, img_h = 0; float zoom = 1.f; ImVec2 pan = {0, 0}; std::vector annotations; int selected = -1; enum Tool { ToolNone, ToolRect, ToolPoint, ToolPolyline } tool = ToolNone; }; void image_canvas(const char* id, ImageCanvasState&, ImVec2 size = {-1, -1}); // --- webcam_texture --- struct WebcamTextureConfig { int width = 640; int height = 480; int fps = 30; int device = 0; }; struct WebcamTexture { GLuint id = 0; int w = 0; int h = 0; bool ok() const { return id != 0; } }; WebcamTexture webcam_texture_start(const WebcamTextureConfig&); void webcam_texture_stop(WebcamTexture&); bool webcam_texture_update(WebcamTexture&); // copia ultimo frame a GPU; true si hubo nuevo const char* webcam_texture_last_error(); } ``` ## Tareas ### Fase 1 — image_canvas - 1.1 Render: `ImGui::Image(texture, ...)` con transform por pan/zoom. Drag con MMB para pan, wheel para zoom. - 1.2 Tool == Rect: drag con LMB en image-space crea anotacion `Rect` con 2 puntos. - 1.3 Tool == Point: click LMB anade un Point. - 1.4 Tool == Polyline: click anade puntos; doble-click cierra. - 1.5 Hit-test para selection; Del key elimina la seleccionada. - 1.6 `.md`. ### Fase 2 — webcam_texture (Linux V4L2) - 2.1 Abrir `/dev/video`, MMAP buffers, VIDIOC_STREAMON. - 2.2 En `update`, dequeue buffer, convert YUYV → RGBA (CPU), upload a GL texture, requeue. - 2.3 `.md` (`kind: function`, `purity: impure`, `error_type`). ### Fase 3 — webcam_texture (Windows Media Foundation, opcional) - 3.1 Si `_WIN32`, usar `IMFSourceReader`. Convert NV12 → RGBA. - 3.2 Documentar que macOS no se soporta en MVP. ### Fase 4 — Gallery demo - 4.1 `demos_image_webcam.cpp`: - `demo_image_canvas()`: carga `assets/sample.png` (si existe — fallback a rendered placeholder), permite pintar rectangulos. - `demo_webcam_texture()`: start cam, mostrar preview + sliders RGB sobre un shader fullscreen que samplea la cam. - 4.2 Registrar. ### Fase 5 — Tests + docs - 5.1 Tests puros de transform image-space ↔ screen-space. - 5.2 Smoke test webcam (skip si no hay /dev/video0). - 5.3 `./fn index`. ## Ejemplo de uso ```cpp auto cam = fn::webcam_texture_start({}); if (!cam.ok()) std::fprintf(stderr, "%s\n", fn::webcam_texture_last_error()); fn::run_app("cam", [&]{ fn::webcam_texture_update(cam); ImGui::Image((ImTextureID)(intptr_t)cam.id, {cam.w*1.f, cam.h*1.f}); }); ``` ## Decisiones de diseño - **Anotaciones en image-space**: pan/zoom no afectan coordenadas guardadas. Permite serializar a JSON (issue futuro). - **YUYV → RGBA en CPU**: simple, ~5ms/frame a 640×480. Si hace falta, hacer un compute shader (issue 0027). - **macOS sin webcam por ahora**: AVFoundation requiere ObjC++; no compensa en MVP. ## Riesgos - **Permisos webcam**: documentar troubleshooting (`/dev/video0` permisos en Linux). - **Driver V4L2 raro**: algunos formatos de pixel no son YUYV. Documentar fallback a MJPEG (con stb_image decode) o error claro. - **`ImTextureID` semantics** entre backends: documentar.