Estimación de pose y OBB
Lee los puntos clave y las cajas rotadas de YOLO26, escribe una regla sobre cada uno y reconoce cuándo la señal real es la postura o el ángulo.
Una residencia de mayores necesita saber cuándo alguien se ha caído; un puerto necesita contar los barcos que aparecen abarrotados y uno junto a otro en una imagen de dron. Las cajas normales no sirven para ninguno de los dos casos: una caja no indica si una persona está erguida, y una caja vertical alrededor de un barco en diagonal contiene sobre todo agua. La estimación de pose y las OBB están diseñadas precisamente para estos dos problemas.
Práctico
Pose: cuando la señal es la postura#

Un modelo de pose devuelve una caja para cada persona y una lista fija de puntos clave. Los modelos entrenados con COCO-Pose predicen 17 por persona —nariz, ojos, orejas, hombros, codos, muñecas, caderas, rodillas y tobillos—, siempre en el mismo orden; así, el índice 0 es la nariz, el 11 la cadera izquierda y el 15 el tobillo izquierdo. Cada punto clave también tiene un valor de confianza.
La regla útil más sencilla: un cuerpo de pie es más alto que ancho; un cuerpo tumbado en el suelo es más ancho que alto. Aquí se aplica a la imagen del autobús, usando solo los puntos clave en los que el modelo tiene confianza:
from ultralytics import YOLO
model = YOLO("yolo26n-pose.pt")
result = model("https://ultralytics.com/images/bus.jpg", verbose=False)[0]
for xy, conf in zip(result.keypoints.xy, result.keypoints.conf):
visible = xy[conf > 0.5] # drop keypoints the model couldn't see
width = float(visible[:, 0].max() - visible[:, 0].min())
height = float(visible[:, 1].max() - visible[:, 1].min())
posture = "unknown" if len(visible) < 5 else "lying" if width > height else "upright"
print(f"{len(visible):2d}/17 keypoints visible, body {width:3.0f} px wide x {height:3.0f} px tall -> {posture}")16/17 keypoints visible, body 117 px wide x 427 px tall -> upright
6/17 keypoints visible, body 80 px wide x 359 px tall -> upright
16/17 keypoints visible, body 91 px wide x 384 px tall -> upright
1/17 keypoints visible, body 0 px wide x 0 px tall -> unknown
2/17 keypoints visible, body 3 px wide x 6 px tall -> unknownTres personas están claramente erguidas. Las dos últimas filas corresponden a la persona cortada por el borde izquierdo y a un duplicado con baja confianza: con uno o dos puntos clave visibles no hay nada que evaluar, así que la regla indica «desconocido» en vez de hacer una suposición. Un detector de caídas para producción añade el tiempo —estar tumbado durante más de unos segundos después de una caída rápida— mediante seguimiento.
Síntoma: esqueletos con muñecas suspendidas en el aire y reglas de postura que se activan con personas parcialmente visibles. Causa: keypoints.xy devuelve una posición para los 17 puntos clave, incluso los que el modelo no ha podido ver. Solución: filtra con keypoints.conf, como antes, y exige un número mínimo de puntos clave visibles antes de decidir nada.
La pose es útil cuando la respuesta depende de lo que hace el cuerpo: caídas o levantamientos con la espalda encorvada por seguridad, ángulos articulares y recuento de repeticiones en el deporte, como en la supervisión de entrenamientos, o la postura del ganado y los puntos de referencia fijos en piezas con una disposición personalizada de puntos clave. Para responder «¿hay aquí una persona?», usa detección normal.
OBB: cuando importa el ángulo#

Una caja normal tiene los bordes paralelos a la imagen. Una caja delimitadora orientada añade una rotación, almacenada como centro, anchura, altura y ángulo (xywhr). En imágenes cenitales —de satélite, dron o cámaras sobre una cinta transportadora—, los objetos aparecen en cualquier ángulo, y una caja vertical alrededor de un objeto diagonal contiene sobre todo fondo, como ocurriría con los yates de arriba. Mide cuánto cambia en una imagen de dron de un puerto deportivo:
from ultralytics import YOLO
model = YOLO("yolo26n-obb.pt")
result = model("https://ultralytics.com/images/boats.jpg", verbose=False)[0]
obb = result.obb
rotated_area = obb.xywhr[:, 2] * obb.xywhr[:, 3] # width x height of each rotated box
x1, y1, x2, y2 = obb.xyxy.T # the axis-aligned box that would enclose the same object
upright_area = (x2 - x1) * (y2 - y1)
print(f"{len(obb)} objects, classes: {sorted({result.names[int(c)] for c in obb.cls})}")
cx, cy, w, h, angle = obb.xywhr[0].tolist()
print(f"first box: center=({cx:.0f}, {cy:.0f}) size={w:.0f}x{h:.0f} angle={angle:.2f} rad")
ratio = float((upright_area / rotated_area).median())
print(f"an axis-aligned box would be {ratio:.1f}x larger (median)")173 objects, classes: ['harbor', 'ship']
first box: center=(619, 850) size=33x108 angle=-0.25 rad
an axis-aligned box would be 2.1x larger (median)Una caja vertical cubre aproximadamente el doble de superficie que la caja rotada alrededor del mismo barco, y esa superficie adicional es agua. Esto perjudica por partida doble: NMS detecta que las cajas verticales de barcos vecinos se solapan y puede suprimir detecciones reales, y cualquier estimación del tamaño queda inflada. Los modelos OBB entrenados con conjuntos de datos aéreos como DOTA procesan estas escenas directamente. Ten en cuenta que el ángulo está en radianes: -0.25 rad son aproximadamente -14°.
Cómo elegir entre detección, pose y OBB#
| Escenario | Tarea más adecuada | Por qué |
|---|---|---|
| Contar personas en una acera | Detección | La respuesta es su presencia y ubicación |
| Detectar una caída en una residencia de mayores | Pose | La señal es la orientación del cuerpo |
| Contar sentadillas en un gimnasio | Pose | La señal son los ángulos de rodillas y caderas |
| Contar barcos amarrados desde un dron | OBB | Los barcos están en diagonal y muy juntos |
| Paquetes en una cinta transportadora, vistos desde arriba | OBB | La orientación varía y los objetos vecinos se tocan |
| Coches a pie de calle | Detección | Los coches aparecen más o menos verticales en el encuadre |
La pose añade puntos clave a cada caja; OBB añade un ángulo. Si tu código nunca lee los puntos clave ni el ángulo, un detector estándar es más rápido de etiquetar y ejecutar, y más fácil de depurar.
Mostrar solución
from ultralytics import YOLO
image = "https://ultralytics.com/images/boats.jpg"
upright = YOLO("yolo26n.pt")(image, verbose=False)[0]
rotated = YOLO("yolo26n-obb.pt")(image, verbose=False)[0]
print(f"axis-aligned detector: {len(upright.boxes)} boxes")
print(f"OBB model: {len(rotated.obb)} rotated boxes")axis-aligned detector: 0 boxes
OBB model: 173 rotated boxesLa mayor parte de la diferencia se debe a los datos de entrenamiento, no a la geometría. yolo26n.pt se entrenó con COCO, donde la mayoría de los barcos se fotografían de lado; desde arriba no detecta nada con el umbral predeterminado (baja conf a 0.05 y clasificará algunos como botellas). El modelo OBB se entrenó con imágenes aéreas. La geometría también importa: incluso un detector entrenado con imágenes aéreas de barcos dibujaría cajas aproximadamente el doble de grandes y tendría problemas con NMS en filas muy apretadas. Tanto la tarea como los datos de entrenamiento deben ajustarse a la vista de despliegue.