Ước tính tư thế và OBB
Đọc keypoint và hộp xoay từ YOLO26, xây dựng quy tắc dựa trên từng loại, và nhận biết khi tư thế hoặc góc mới là tín hiệu thực sự.
Một cơ sở chăm sóc cần biết khi có người bị ngã; một cảng cần đếm số tàu nằm sát nhau trong ảnh chụp từ drone. Hộp thông thường không đáp ứng được cả hai: hộp không cho biết một người đang đứng thẳng hay không, còn hộp thẳng bao quanh một con tàu nằm chéo thì chủ yếu là mặt nước. Ước tính tư thế và OBB được thiết kế chính xác để giải quyết hai vấn đề này.
Thực hành
Pose: khi tư thế là tín hiệu#

Model pose trả về một hộp cho mỗi người, cùng với danh sách keypoint cố định. Các model được huấn luyện trên COCO-Pose dự đoán 17 keypoint cho mỗi người — mũi, mắt, tai, vai, khuỷu tay, cổ tay, hông, đầu gối và mắt cá chân — luôn theo cùng một thứ tự, vì vậy index 0 là mũi, 11 là hông trái và 15 là mắt cá chân trái. Mỗi keypoint cũng có độ tin cậy riêng.
Quy tắc hữu ích đơn giản nhất: cơ thể đứng thẳng cao hơn rộng; cơ thể nằm trên sàn rộng hơn cao. Đây là kết quả áp dụng trên ảnh xe buýt, chỉ sử dụng những keypoint mà model có độ tin cậy cao:
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 -> unknownBa người rõ ràng đang đứng thẳng. Hai hàng cuối là người bị cắt mất một phần ở mép trái và một bản phát hiện trùng có độ tin cậy thấp: chỉ với một hoặc hai keypoint nhìn thấy được thì không thể đánh giá, nên quy tắc trả về "không xác định" thay vì đoán. Hệ thống phát hiện té ngã dùng trong thực tế sẽ bổ sung yếu tố thời gian thông qua tracking — chẳng hạn nằm lâu hơn vài giây sau khi ngã nhanh.
Triệu chứng: skeleton có cổ tay lơ lửng giữa không trung và quy tắc tư thế được kích hoạt với người chỉ hiện một phần. Nguyên nhân: keypoints.xy trả về vị trí cho cả 17 keypoint, kể cả những điểm model không thể nhìn thấy. Cách khắc phục: lọc bằng keypoints.conf như trên, đồng thời yêu cầu số lượng keypoint nhìn thấy tối thiểu trước khi đưa ra bất kỳ quyết định nào.
Pose phát huy tác dụng khi câu trả lời phụ thuộc vào hành động của cơ thể: phát hiện té ngã hoặc nâng vật với lưng cong để đảm bảo an toàn, đo góc khớp và đếm số lần tập thể thao như trong giám sát bài tập, hoặc theo dõi tư thế vật nuôi và các điểm mốc cố định trên bộ phận bằng bố cục keypoint tùy chỉnh. Để trả lời câu hỏi "có người ở đây không?", hãy dùng detection thông thường.
OBB: khi góc quan trọng#

Các cạnh của hộp thông thường song song với ảnh. Hộp giới hạn có hướng bổ sung góc xoay, được lưu dưới dạng tâm, chiều rộng, chiều cao và góc (xywhr). Trong ảnh nhìn từ trên xuống — ảnh vệ tinh, drone, camera băng chuyền nhìn từ trên cao — vật thể nằm ở nhiều góc độ, còn hộp thẳng bao quanh một vật thể nằm chéo thì chủ yếu là phông nền, như trường hợp các du thuyền phía trên. Hãy đo mức chênh lệch trên ảnh chụp từ drone tại bến du thuyền:
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)Hộp thẳng bao phủ diện tích lớn gấp khoảng hai lần hộp xoay quanh cùng một chiếc thuyền, phần diện tích dư ra là mặt nước. Điều này gây ra hai vấn đề: NMS thấy các hộp thẳng của những chiếc thuyền gần nhau chồng lấn và có thể loại bỏ các đối tượng thực, đồng thời mọi ước tính kích thước đều bị phóng đại. Các model OBB được huấn luyện trên tập dữ liệu ảnh chụp từ trên cao như DOTA xử lý trực tiếp những cảnh này. Lưu ý góc tính bằng radian: -0.25 rad tương đương khoảng -14°.
Chọn giữa detection, pose và OBB#
| Tình huống | Tác vụ phù hợp nhất | Lý do |
|---|---|---|
| Đếm người trên vỉa hè | Phát hiện | Câu trả lời là sự hiện diện và vị trí |
| Phát hiện người bị ngã tại cơ sở chăm sóc | Pose | Hướng cơ thể là tín hiệu |
| Đếm số lần squat trong phòng tập | Pose | Góc đầu gối và hông là tín hiệu |
| Đếm thuyền neo tại bến bằng drone | OBB | Thuyền nằm chéo và đậu sát nhau |
| Các kiện hàng trên băng chuyền, nhìn từ trên cao | OBB | Hướng vật thể thay đổi và các vật thể sát nhau |
| Ô tô ở tầm đường phố | Phát hiện | Ô tô xuất hiện gần như thẳng đứng trong khung hình |
Pose bổ sung keypoint vào mỗi hộp; OBB bổ sung một góc. Nếu code của bạn không bao giờ đọc keypoint hoặc góc, detector thông thường sẽ nhanh gán nhãn hơn, chạy nhanh hơn và dễ debug hơn.
Hiển thị lời giải
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 boxesPhần lớn mức chênh lệch đến từ dữ liệu huấn luyện, không phải hình học. yolo26n.pt được huấn luyện trên COCO, nơi thuyền chủ yếu được chụp từ bên cạnh; khi nhìn từ trên cao, model không phát hiện được gì ở ngưỡng mặc định (giảm conf xuống 0.05 thì model nhận nhầm một số thuyền thành chai). Model OBB được huấn luyện trên ảnh chụp từ trên cao. Hình học vẫn quan trọng: ngay cả model detection được huấn luyện trên ảnh thuyền chụp từ trên cao cũng sẽ tạo hộp lớn gấp khoảng hai lần và gặp khó khăn với NMS trong các hàng thuyền đậu sát nhau. Cả tác vụ lẫn dữ liệu huấn luyện đều phải phù hợp với góc nhìn khi triển khai.