Hãy tưởng tượng bạn yêu cầu một robot cầm lấy đúng cái tai phải của một con thú nhồi bông hình sâu bướm. Không phải tai trái, không phải thân, mà đúng cái tai phải. Robot chưa bao giờ nhìn thấy con sâu bướm này trước đây.
Nghe như khoa học viễn tưởng? Không — đây là kết quả thực tế của một nghiên cứu từ MIT CSAIL năm 2018, và nó được thực hiện nhờ một khái niệm gọi là mô hình Dense (Dense Models) trong robotics.
Bài viết này sẽ đưa bạn từ nền tảng lý thuyết đến code thực tế, đi qua ba công trình quan trọng nhất trong lĩnh vực dense visual representation cho robot: Dense Object Nets (DON), DenseFusion, và DenseMatcher.
Dense là gì? Tại sao lại quan trọng?
Trước khi vào chi tiết, hãy hiểu rõ "dense" nghĩa là gì trong ngữ cảnh này.
Trong computer vision, có hai cách tiếp cận chính:
Sparse (thưa): Trích xuất một số ít điểm đặc trưng nổi bật từ ảnh — ví dụ như góc cạnh, cạnh, hoặc keypoint theo kiểu SIFT/ORB. Nhanh, nhưng bỏ qua nhiều thông tin.
Dense (dày đặc): Tính toán một đặc trưng (feature vector) cho mỗi pixel trong ảnh. Chậm hơn, tốn tài nguyên hơn, nhưng cực kỳ phong phú về thông tin.
Sparse: [ * , * , * , * ]
keypoint keypoint ...
Dense: [p₁, p₂, p₃, ..., pₙ] ← mỗi pixel có một feature vector
Với robot, dense representation mở ra những khả năng không thể làm được với sparse:
- Nhận dạng điểm cụ thể trên vật thể: "Cầm vào đây, không phải chỗ kia"
- Generalize sang vật thể chưa thấy: Học từ một con giày → cầm được mọi đôi giày
- Robust với partial occlusion: Vẫn hoạt động khi vật thể bị che một phần
- Không cần CAD model: Không cần bản vẽ kỹ thuật của vật thể
Dense Object Nets (DON) — Nền tảng của mọi thứ
Paper: Dense Object Nets: Learning Dense Visual Object Descriptors By and For Robotic Manipulation
Tác giả: Peter R. Florence, Lucas Manuelli, Russ Tedrake — MIT CSAIL
Hội nghị: CoRL 2018 (Best Paper Award)
GitHub: RobotLocomotion/pytorch-dense-correspondence
Ý tưởng cốt lõi
DON học một hàm ánh xạ: mỗi pixel (u, v) trong ảnh → một vector đặc trưng D ∈ ℝᵈ (thường d = 3 hoặc d = 16).
Các vector này được học sao cho:
- Cùng điểm trên vật thể → vector gần nhau trong không gian đặc trưng
- Điểm khác nhau → vector xa nhau
Điều kỳ diệu: vector này không phụ thuộc vào góc nhìn. Nghĩa là cái tai phải của con sâu bướm sẽ luôn có cùng vector đặc trưng dù bạn nhìn nó từ phía trước, bên hông, hay từ trên xuống.
Kiến trúc DON
RGB Image (H×W×3)
│
▼
FCN Backbone (ResNet-34 hoặc VGG-16)
│
▼
Dense Feature Map (H×W×D)
← mỗi pixel có D-dimensional descriptor
DON dùng Fully Convolutional Network (FCN) — không có fully connected layers, nên output giữ nguyên kích thước spatial với ảnh input.
Training: Self-supervised với RGB-D
Điều thú vị nhất về DON là nó hoàn toàn self-supervised — không cần nhãn thủ công. Training data được tạo tự động từ camera RGB-D:
1. Chụp nhiều ảnh vật thể từ nhiều góc độ
2. Dùng depth + camera pose để project điểm 3D
3. Tự tạo correspondence: pixel A trong ảnh 1 ↔ pixel B trong ảnh 2
(cùng điểm 3D trên vật thể)
4. Train với contrastive loss
Contrastive Loss:
# Match loss: descriptor của matching pair phải gần nhau
L_match = ||D(u_a) - D(u_b)||²
# Non-match loss: descriptor khác pair phải xa hơn margin M
L_non_match = max(0, M - ||D(u_a) - D(u_c)||)²
# Total loss
L = L_match + α * L_non_match
Ứng dụng thực tế: Robot grasping theo điểm
import torch
import numpy as np
from dense_correspondence.network.dense_correspondence_network import DenseCorrespondenceNetwork
# Load model đã train
dcn = DenseCorrespondenceNetwork.from_model_folder('path/to/trained_model')
dcn.eval()
# Ảnh reference: người dùng chỉ vào điểm cần cầm
img_ref = load_image('caterpillar_reference.png') # H×W×3
target_pixel = (120, 85) # pixel tay chỉ vào
# Lấy descriptor của điểm target
with torch.no_grad():
descriptor_map_ref = dcn.forward_single_image(img_ref)
target_descriptor = descriptor_map_ref[target_pixel[0], target_pixel[1]] # D-dim vector
# Ảnh live từ camera robot
img_live = get_camera_frame() # ảnh mới của vật thể (vị trí/góc khác)
# Tìm điểm tương ứng trong ảnh live
with torch.no_grad():
descriptor_map_live = dcn.forward_single_image(img_live)
# L2 distance với toàn bộ map
diff = descriptor_map_live - target_descriptor # H×W×D
dist = torch.norm(diff, dim=-1) # H×W
# Best match
best_pixel = torch.argmin(dist.view(-1))
best_y = best_pixel // img_live.shape[1]
best_x = best_pixel % img_live.shape[1]
print(f"Điểm cần cầm trong ảnh live: ({best_x}, {best_y})")
Kết quả DON
MIT thử nghiệm DON với cánh tay robot Kuka LBR iiwa:
- Grasping accuracy: 87.4% success rate khi cầm đúng điểm chỉ định
- Cross-instance: Học từ 1 chiếc giày → cầm được giày khác chưa từng thấy
- Non-rigid objects: Hoạt động với vải, túi, đồ mềm
DenseFusion — 6D Pose Estimation với RGB-D Fusion
Paper: DenseFusion: 6D Object Pose Estimation by Iterative Dense Fusion
Tác giả: Chen Wang, Danfei Xu, Yuke Zhu, et al. — Stanford University
Hội nghị: CVPR 2019
GitHub: j96w/DenseFusion
Vấn đề: 6D Pose Estimation là gì?
Khi robot cầm một vật thể, nó cần biết chính xác:
- Translation (3D): Vật thể đang ở đâu trong không gian (x, y, z)
- Rotation (3D): Vật thể xoay theo hướng nào (roll, pitch, yaw)
Tổng cộng 6 bậc tự do — gọi là 6D pose.
Tại sao DON không đủ?
DON tốt cho việc tìm điểm tương ứng, nhưng để có 6D pose chính xác, ta cần:
- Kết hợp thông tin màu sắc (RGB) và độ sâu (Depth)
- Xử lý ở mức pixel (dense) thay vì sparse keypoints
DenseFusion làm điều này bằng cách fusion dense features từ cả RGB và point cloud.
Kiến trúc DenseFusion
RGB Image ──────────────────────► RGB Feature Extractor (PSPNet)
│ │
│ ▼ per-pixel color features
│
Depth Image → Point Cloud ───────► PointNet Feature Extractor
│
▼ per-point geometry features
[Fusion Layer: RGB + Geometry per point]
│
▼
Pose Estimation Head
→ (R, t) per object instance
→ Confidence score per prediction
Điểm mấu chốt: DenseFusion không fusion ở global level — nó fusion tại mỗi điểm trong point cloud với pixel tương ứng trong ảnh RGB. Điều này giữ lại spatial information cực kỳ chi tiết.
Setup và chạy DenseFusion
# Cài đặt dependencies
conda create -n densefusion python=3.7
conda activate densefusion
pip install torch==1.7.1 torchvision==0.8.2
pip install scipy==1.2.0 opencv-python transforms3d
# Clone repo
git clone https://github.com/j96w/DenseFusion.git
cd DenseFusion
# Download YCB-Video dataset (training)
# Dataset: 80 training videos + synthetic data + 2949 test frames
wget https://rse-lab.cs.washington.edu/projects/posecnn/dataset.html
# (theo hướng dẫn trên trang chủ YCB-Video)
# Training trên YCB-Video dataset
python tools/train.py \
--dataset ycb \
--dataset_root path/to/YCB_Video_Dataset \
--batch_size 8 \
--workers 10 \
--lr 0.0001 \
--start_epoch 0
Iterative Refinement — Bước quan trọng thứ hai
DenseFusion không chỉ predict pose một lần — nó có thêm bước Iterative Refinement:
# Bước 1: Dự đoán pose ban đầu
initial_pose = densefusion_model(rgb, depth, roi)
# Bước 2: Refine lặp đi lặp lại
current_pose = initial_pose
for i in range(num_iterations):
# Dùng pose hiện tại để transform point cloud
transformed_cloud = transform_point_cloud(depth_cloud, current_pose)
# Predict refinement (delta R, delta t)
delta = refinement_model(rgb, transformed_cloud, roi)
# Cập nhật pose
current_pose = compose_pose(current_pose, delta)
final_pose = current_pose
Mỗi vòng lặp, pose được cải thiện dần dần — giống như bạn căn chỉnh một đồ vật cho đến khi vừa khớp.
Kết quả DenseFusion
Thử nghiệm trên YCB-Video và LineMOD datasets:
| Metric | DenseFusion (no refine) | DenseFusion (iterative) |
|---|---|---|
| ADD(-S) AUC trên YCB | 86.2% | 91.8% |
| ADD trên LineMOD | 79.7% | 86.2% |
So với các phương pháp trước đó (PoseCNN, DeepIM), DenseFusion cải thiện ~12-15% với thời gian inference nhanh hơn.
DenseMatcher — Generalize từ Một Demo
Paper: DenseMatcher: Learning 3D Semantic Correspondence for Category-Level Manipulation from a Single Demo
Tác giả: Junzhe Zhu et al. — TEA Lab
Hội nghị: ICLR 2025
GitHub: TEA-Lab/DenseMatcher
Project: https://tea-lab.github.io/DenseMatcher/
Vấn đề mới: Category-level generalization
DON và DenseFusion hoạt động tốt cho instance-level — tức là vật thể cụ thể mà robot đã thấy. Nhưng nếu muốn robot học từ một demo và áp dụng lên mọi loại cốc (dù khác hình dạng, kích thước), đó là category-level generalization — và đây là bài toán khó hơn nhiều.
DenseMatcher giải quyết bài toán này bằng cách học dense 3D correspondence giữa các vật thể trong cùng category.
Kiến trúc DenseMatcher
Object Mesh A Object Mesh B
│ │
▼ ▼
Multi-view Rendering Multi-view Rendering
(nhiều góc nhìn) (nhiều góc nhìn)
│ │
▼ ▼
2D Foundation Model 2D Foundation Model
(DINO / Stable Diffusion) (DINO / Stable Diffusion)
│ │
▼ ▼
Project features → Mesh Vertices Project features → Mesh Vertices
│ │
▼ ▼
3D GNN Refinement 3D GNN Refinement
│ │
└──────────────────┬─────────────────┘
▼
Functional Map Layer
(tìm correspondence function)
│
▼
Dense 3D Correspondence
(mọi vertex A ↔ vertex B)
Bước 1 — Project 2D features lên 3D mesh:
Render vật thể từ nhiều góc (16-32 views), dùng DINO hoặc Stable Diffusion để trích xuất 2D features, sau đó project ngược lên mesh vertices theo weighted averaging.
Bước 2 — 3D GNN refinement:
Graph Neural Network chạy trên mesh graph để làm mượt và nhất quán hóa features, tận dụng cấu trúc 3D của vật thể.
Bước 3 — Functional Maps:
Thay vì tìm correspondence trực tiếp (cực kỳ tốn kém với mesh lớn), DenseMatcher dùng Functional Maps — biểu diễn correspondence dưới dạng ma trận ánh xạ giữa không gian spectral của hai mesh. Sau đó convert ngược về point-to-point correspondence.
Setup DenseMatcher
# Clone và setup
git clone https://github.com/TEA-Lab/DenseMatcher.git
cd DenseMatcher
conda create -n densematcher python=3.9
conda activate densematcher
pip install -r requirements.txt
# Download pre-trained model
python scripts/download_model.py
# Thử nghiệm với 2 object mesh
python demo.py \
--mesh_a data/example/cup_A.obj \
--mesh_b data/example/cup_B.obj \
--output_dir results/
Áp dụng vào robot manipulation
from densematcher import DenseMatcher
import numpy as np
# Load model
matcher = DenseMatcher.from_pretrained('densematcher-v1')
# Demo: robot học cách cầm cốc A
# Grasp point trên cốc A (từ human demo)
demo_mesh = load_mesh('cup_A.obj')
demo_grasp_vertex = 1247 # index của vertex ở vị trí tay cầm
# Target: cốc B (chưa từng thấy, hình dạng khác)
target_mesh = load_mesh('cup_B.obj')
# Tìm correspondence
correspondence = matcher.compute_correspondence(demo_mesh, target_mesh)
# Tìm vertex tương ứng trên cốc B
target_grasp_vertex = correspondence[demo_grasp_vertex]
target_grasp_position = target_mesh.vertices[target_grasp_vertex]
print(f"Điểm cầm trên target cup: {target_grasp_position}")
# → Robot dùng điểm này để thực hiện grasp
Kết quả DenseMatcher
- Outperforms baselines: +43.5% so với phương pháp 3D matching tốt nhất trước đó
- Cross-category: Học từ cốc → cầm được bình nước, hộp, dù khác category
- Long-horizon tasks: Thực hiện được chuỗi thao tác phức tạp (mở nắp → rót → đóng) chỉ từ 1 demo
- Zero-shot: Không cần fine-tune cho vật thể mới
So sánh ba phương pháp
| Tiêu chí | DON (2018) | DenseFusion (2019) | DenseMatcher (2025) |
|---|---|---|---|
| Input | RGB-D images | RGB + Point Cloud | 3D Mesh |
| Output | 2D pixel descriptors | 6D pose (R, t) | 3D vertex correspondence |
| Generalization | Cross-instance (rigid) | Instance-level | Category-level (cross-instance) |
| Supervision | Self-supervised | Fully supervised | Self-supervised (via foundation models) |
| Foundation model | Không | Không | Có (DINO, SD) |
| Real-time | Có (~10ms) | Có (~20ms) | Không (offline) |
| Ứng dụng | Grasping specific points | Pick-and-place chính xác | One-shot imitation learning |
Pipeline thực tế cho robot manipulation
Trên thực tế, các hệ thống robot hiện đại kết hợp cả ba phương pháp:
Camera (RGB-D)
│
├──► Segmentation (Mask R-CNN / SAM) → object ROI
│
├──► DenseFusion ─────────────────────► 6D Pose (để plan trajectory)
│
└──► DON / DenseMatcher ───────────────► Grasp point (để xác định điểm cầm)
│
Motion Planner
│
Robot Execution
Hướng phát triển tiếp theo
Sau DenseMatcher, nghiên cứu đang đi theo hướng:
1. Dense features từ Foundation Models:
DINOBot (2024) và các công trình tương tự dùng trực tiếp features từ DINO-ViT — không cần train thêm. Features này đã đủ "dense" và "semantic" để matching.
2. Dense World Models:
Thay vì predict pose rời rạc, predict toàn bộ scene representation dưới dạng dense feature map — cho phép planning dài hạn chính xác hơn.
3. 4D Dense Tracking:
Theo dõi dense correspondence qua thời gian (không chỉ spatial) — biết mỗi điểm trên vật thể đã di chuyển thế nào, thay đổi thế nào trong quá trình robot tương tác.
4. Kết hợp với VLA models:
Dùng dense visual features làm visual tokens cho Vision-Language-Action models, thay vì global image embedding — giúp model "nhìn" chi tiết hơn.
Cài đặt và thử nghiệm nhanh (DON)
Nếu bạn muốn bắt đầu với DON ngay hôm nay:
# Yêu cầu: Ubuntu 20.04+, CUDA 11+, Python 3.8+
git clone https://github.com/RobotLocomotion/pytorch-dense-correspondence.git
cd pytorch-dense-correspondence
# Cài dependencies
pip install torch torchvision
pip install -r requirements.txt
# Download pre-trained model (shoes dataset)
python scripts/download_models.py --model shoes
# Run demo: tìm correspondence giữa 2 ảnh
python scripts/find_correspondences.py \
--model_path trained_models/shoes \
--image_a data/shoes/image_a.png \
--image_b data/shoes/image_b.png \
--pixel_a 150 120 # pixel bạn quan tâm trong image A
Output: một ảnh với điểm tương ứng được vẽ trong image B — bạn có thể thấy ngay descriptor matching hoạt động thế nào.
Kết luận
Dense models đã thay đổi căn bản cách robot hiểu và tương tác với vật thể:
- DON (2018) đặt nền móng: mỗi pixel có nghĩa, không phải chỉ toàn bộ ảnh
- DenseFusion (2019) fusion RGB + Depth ở mức pixel → 6D pose chính xác
- DenseMatcher (2025) tổng quát hóa lên category-level với foundation models
Xu hướng rõ ràng: dense representation ngày càng mạnh hơn khi kết hợp với foundation models (DINO, Stable Diffusion). Một robot năm 2026 không cần hàng ngàn demo — vài chục demo với dense matching đủ để generalize rộng.
Nếu bạn đang xây dựng hệ thống manipulation, đây là stack được khuyến nghị:
- Segmentation: SAM (Segment Anything Model) để tách object
- Pose: DenseFusion hoặc FoundationPose cho 6D pose
- Grasp point: DenseMatcher cho category-level generalization
- Policy: ACT hoặc Diffusion Policy cho motion planning