物体识别是服务机器人感知世界的核心能力——知道"是什么"才能决定"怎么处理":
图像采集 → 预处理 → 特征提取 → 目标检测 → 分类定位
↓
多目标追踪 → 抓取姿态估计
↓
任务执行import math, random
class SimpleObjectDetector:
"""简易物体检测器模拟"""
def __init__(self):
self.classes = {
"cup": {"size": (0.08, 0.10), "color_range": ("白色","透明"), "shape": "圆柱"},
"bottle": {"size": (0.06, 0.25), "color_range": ("透明","绿色"), "shape": "圆柱"},
"document": {"size": (0.21, 0.30), "color_range": ("白色",), "shape": "矩形"},
"package": {"size": (0.20, 0.30), "color_range": ("棕色","黄色"), "shape": "立方体"},
"tray": {"size": (0.35, 0.02), "color_range": ("银色","黑色"), "shape": "扁平"},
"phone": {"size": (0.07, 0.15), "color_range": ("黑色","白色"), "shape": "矩形"},
"key": {"size": (0.03, 0.08), "color_range": ("银色","金色"), "shape": "不规则"},
"medicine": {"size": (0.05, 0.08), "color_range": ("白色","橙色"), "shape": "矩形"},
}
self.detection_accuracy = 0.85
self.confidence_range = (0.7, 0.99)
def detect(self, scene_objects):
"""模拟物体检测"""
results = []
for obj in scene_objects:
if random.random() < self.detection_accuracy:
cls = obj.get("class", "unknown")
x, y, w, h = obj.get("bbox", [0,0,0,0])
confidence = random.uniform(*self.confidence_range)
# 模拟误检
if random.random() < 0.05:
wrong_classes = [c for c in self.classes if c != cls]
cls = random.choice(wrong_classes) if wrong_classes else cls
confidence *= 0.7
results.append({
"class": cls,
"confidence": round(confidence, 3),
"bbox": [x, y, w, h],
"attributes": self.classes.get(cls, {})
})
return results
def filter_by_confidence(self, results, threshold=0.5):
return [r for r in results if r["confidence"] >= threshold]
random.seed(42)
detector = SimpleObjectDetector()
scene = [
{"class": "cup", "bbox": [100, 200, 50, 60]},
{"class": "document", "bbox": [300, 150, 80, 100]},
{"class": "package", "bbox": [500, 300, 120, 100]},
{"class": "bottle", "bbox": [200, 400, 40, 120]},
{"class": "key", "bbox": [400, 250, 25, 40]},
{"class": "medicine", "bbox": [600, 180, 30, 50]},
]
print("物体识别模拟")
print("=" * 55)
results = detector.detect(scene)
filtered = detector.filter_by_confidence(results)
for r in filtered:
attrs = r["attributes"]
size_info = f"尺寸{attrs['size']}" if attrs else ""
print(f" 📦 {r['class']} (置信度:{r['confidence']:.1%}) bbox:{r['bbox']} {size_info}")
print(f"\n检测: {len(results)}个, 过滤后: {len(filtered)}个")
print("✅ 物体识别验证通过")
在动态场景中,需要持续追踪多个目标:
class ObjectTracker:
"""多目标追踪器"""
def __init__(self):
self.tracks = {}
self.next_id = 0
self.max_lost = 5
self.iou_threshold = 0.3
def _iou(self, box1, box2):
"""计算IoU (交并比)"""
x1 = max(box1[0], box2[0])
y1 = max(box1[1], box2[1])
x2 = min(box1[0]+box1[2], box2[0]+box2[2])
y2 = min(box1[1]+box1[3], box2[1]+box2[3])
inter = max(0, x2-x1) * max(0, y2-y1)
area1 = box1[2] * box1[3]
area2 = box2[2] * box2[3]
union = area1 + area2 - inter
return inter / union if union > 0 else 0
def update(self, detections):
"""更新追踪"""
matched = set(); used_dets = set()
# 匈牙利匹配(简化:贪心)
for tid, track in list(self.tracks.items()):
best_det = None; best_iou = self.iou_threshold
for i, det in enumerate(detections):
if i in used_dets: continue
iou = self._iou(track["bbox"], det["bbox"])
if iou > best_iou:
best_iou = iou; best_det = i
if best_det is not None:
self.tracks[tid]["bbox"] = detections[best_det]["bbox"]
self.tracks[tid]["class"] = detections[best_det]["class"]
self.tracks[tid]["lost"] = 0
self.tracks[tid]["age"] += 1
matched.add(tid); used_dets.add(best_det)
else:
self.tracks[tid]["lost"] += 1
if self.tracks[tid]["lost"] > self.max_lost:
del self.tracks[tid]
# 新检测创建新轨迹
for i, det in enumerate(detections):
if i not in used_dets:
self.tracks[self.next_id] = {
"class": det["class"], "bbox": det["bbox"],
"lost": 0, "age": 1
}
self.next_id += 1
def get_tracks(self):
return {tid: t for tid, t in self.tracks.items() if t["lost"] == 0}
tracker = ObjectTracker()
print("多目标追踪模拟")
print("=" * 55)
frames = [
[{"class":"cup","bbox":[100,200,50,60]},{"class":"bottle","bbox":[200,400,40,120]}],
[{"class":"cup","bbox":[105,198,50,60]},{"class":"bottle","bbox":[203,395,40,120]},{"class":"document","bbox":[300,150,80,100]}],
[{"class":"cup","bbox":[110,195,50,60]},{"class":"bottle","bbox":[208,390,40,120]},{"class":"document","bbox":[302,148,80,100]}],
[{"class":"cup","bbox":[115,192,50,60]},{"class":"document","bbox":[305,146,80,100]}],
[{"class":"cup","bbox":[120,189,50,60]},{"class":"document","bbox":[308,144,80,100]},{"class":"package","bbox":[500,300,120,100]}],
]
for frame_i, detections in enumerate(frames):
tracker.update(detections)
active = tracker.get_tracks()
print(f"\n帧{frame_i+1}: 检测{len(detections)}个 → 追踪{len(active)}个")
for tid, t in active.items():
print(f" 轨迹{tid}: {t['class']} bbox{t['bbox']} age={t['age']}")
print("\n✅ 多目标追踪验证通过")
识别物体后,需要估计如何抓取——接近方向、夹爪宽度、旋转角度:
class GraspPoseEstimator:
"""抓取姿态估计"""
def __init__(self):
self.object_grasp_rules = {
"cup": {"approach": "top", "gripper_width": 0.08, "rotation": 0},
"bottle": {"approach": "side", "gripper_width": 0.06, "rotation": 90},
"document": {"approach": "top", "gripper_width": 0.02, "rotation": 0},
"package": {"approach": "side", "gripper_width": 0.20, "rotation": 0},
"key": {"approach": "top", "gripper_width": 0.03, "rotation": 45},
"medicine": {"approach": "top", "gripper_width": 0.05, "rotation": 0},
"tray": {"approach": "bottom", "gripper_width": 0.35, "rotation": 0},
}
self.gripper_max = 0.25
def estimate(self, obj_class, obj_bbox, obj_pose=None):
"""估计抓取姿态"""
rule = self.object_grasp_rules.get(obj_class)
if not rule:
return {"feasible": False, "reason": f"未知物体类型: {obj_class}"}
if rule["gripper_width"] > self.gripper_max:
return {"feasible": False, "reason": f"物体过大: 需要{rule['gripper_width']}m, 最大{self.gripper_max}m"}
x, y, w, h = obj_bbox
cx, cy = x + w/2, y + h/2
grasp_pose = {
"position": (cx, cy),
"approach": rule["approach"],
"rotation": rule["rotation"],
"gripper_width": rule["gripper_width"],
"feasible": True,
}
return grasp_pose
estimator = GraspPoseEstimator()
print("抓取姿态估计")
print("=" * 55)
objects = [
("cup", [100, 200, 50, 60]),
("bottle", [200, 400, 40, 120]),
("document", [300, 150, 80, 100]),
("package", [500, 300, 120, 100]),
("key", [400, 250, 25, 40]),
("tray", [150, 300, 200, 20]),
]
for cls, bbox in objects:
result = estimator.estimate(cls, bbox)
if result["feasible"]:
print(f"\n✅ {cls}: 方向={result['approach']} 旋转={result['rotation']}° 夹爪={result['gripper_width']}m")
else:
print(f"\n❌ {cls}: {result['reason']}")
print("\n✅ 抓取姿态估计验证通过")
| 模型 | 速度 | 精度 | 适用 |
|---|---|---|---|
| YOLOv8 | 快 | 高 | 实时检测 |
| DETR | 中 | 高 | 端到端检测 |
| GroundingDINO | 中 | 高 | 开放词汇检测 |
| SegmentAnything | 慢 | 极高 | 精细分割 |
| MediaPipe | 极快 | 中 | 边缘设备 |
实现开放词汇检测:支持用自然语言描述物体(如'红色的杯子'),结合颜色和形状特征进行检测。
实现3D物体姿态估计:从2D边界框和物体尺寸推断3D位置和朝向,用于抓取规划。
实现场景理解:不仅检测单个物体,还推断物体间关系('咖啡在杯子里'、'文件在桌上')。