FaceHubPipeline¶
FaceHubPipeline 是 FaceHub 的核心流水线,它把摄像头、检测器、识别器、追踪器和数据库串联成一个完整的处理循环。
它负责: - 启动和停止摄像头 - 将识别器缓存与数据库同步 - 完成检测 → 识别 → 追踪的完整流程 - 实时 FPS 统计 - 线程安全的帧处理
构造参数¶
| 参数 | 类型 | 说明 |
|---|---|---|
camera |
CameraThread |
摄像头采集线程 |
detector |
DetectorProtocol |
检测器(可用内置 FaceDetector 或自定义实现) |
recognizer |
FaceRecognizer |
识别器 |
tracker |
FaceTracker |
追踪器 |
db |
FaceDatabase |
人脸数据库 |
属性¶
| 属性 | 类型 | 说明 |
|---|---|---|
is_running |
bool |
流水线是否已启动 |
方法¶
start()¶
启动流水线。如果摄像头尚未运行,会自动启动。
stop()¶
停止流水线并释放摄像头。
process_frame(frame=None)¶
处理一帧图像,走完整流水线(检测 → 特征提取 → 识别 → 追踪)。
参数:
- frame (np.ndarray | None): 显式传入的 BGR 帧;为 None 时自动从摄像头获取。
返回:
- PipelineResult | None:如果无帧可取则返回 None。
update_database_cache()¶
同步识别器缓存与数据库。
返回:
- bool: 缓存是否被重建。
detect_only(frame)¶
仅运行检测(不提取特征、不识别、不追踪)。
参数:
- frame (np.ndarray): BGR 图像。
返回:
- List[DetectionResult]
extract_embeddings(frame)¶
运行检测 + 特征提取(不追踪)。
参数:
- frame (np.ndarray): BGR 图像。
返回:
- List[DetectionWithEmbedding]
reset_tracker()¶
重置追踪器,清除所有活跃追踪。
完整实时摄像头示例¶
这是 FaceHub 最典型的使用方式——打开摄像头实时识别人脸:
import cv2
from face_hub import (
FaceHubPipeline,
FaceDetector,
FaceRecognizer,
FaceTracker,
FaceDatabase,
CameraThread,
)
# 1. 初始化各组件
camera = CameraThread(camera_id=0, width=640, height=360)
detector = FaceDetector(device="auto", det_size=640)
recognizer = FaceRecognizer(tolerance=0.45)
tracker = FaceTracker(smooth_frames=5)
db = FaceDatabase(db_path="face_db.json")
# 2. 创建并启动流水线
pipeline = FaceHubPipeline(camera, detector, recognizer, tracker, db)
pipeline.start()
try:
while True:
result = pipeline.process_frame()
if result is None:
continue
# 遍历已识别的人脸
for face in result.known_faces:
print(f"{face.name} 置信度={face.confidence:.0%}")
# 绘制结果
for face in result.tracked_faces:
x1, y1, x2, y2 = face.bbox.to_tuple()
if face.is_known:
color = (0, 255, 0)
label = f"{face.name} {face.confidence:.0%}"
else:
color = (0, 165, 255)
label = "unknown"
cv2.rectangle(result.frame, (x1, y1), (x2, y2), color, 2)
cv2.putText(result.frame, label, (x1, y1 - 8),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
# 显示 FPS 和人脸数量
cv2.putText(result.frame, f"FPS: {result.fps:.1f}",
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2)
cv2.putText(result.frame, f"Faces: {result.total_faces}",
(10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2)
cv2.imshow("FaceHub", result.frame)
if cv2.waitKey(1) == 27: # 按 ESC 退出
break
finally:
pipeline.stop()
cv2.destroyAllWindows()
处理静态图片¶
import cv2
from face_hub import (
FaceHubPipeline, FaceDetector, FaceRecognizer,
FaceTracker, FaceDatabase, CameraThread,
)
camera = CameraThread()
pipeline = FaceHubPipeline(
camera,
FaceDetector(device="cpu"),
FaceRecognizer(),
FaceTracker(),
FaceDatabase(),
)
pipeline.start()
frame = cv2.imread("group_photo.jpg")
result = pipeline.process_frame(frame=frame)
if result:
print(f"共检测到 {result.total_faces} 张人脸")
print(f"已识别: {len(result.known_faces)} 人")
print(f"未识别: {result.unknown_count} 人")
for face in result.known_faces:
print(f" {face.name}: 置信度 {face.confidence:.0%}")
pipeline.stop()
用 OpenCV 绘制识别结果¶
result = pipeline.process_frame()
if result is None:
return
frame = result.frame
for face in result.tracked_faces:
x1, y1, x2, y2 = face.bbox.to_tuple()
# 已确认身份用绿色,未确认用橙色
if face.is_known:
color = (0, 255, 0) # 绿色
elif face.is_confirmed:
color = (0, 165, 255) # 橙色(追踪已确认但无匹配)
else:
color = (0, 0, 255) # 红色(未确认)
label = f"{face.name} {face.confidence:.0%}"
cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
cv2.rectangle(frame, (x1, y1 - 25), (x1 + 120, y1), color, -1)
cv2.putText(frame, label, (x1 + 5, y1 - 8),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
仅检测(不做识别/追踪)¶
当只需要知道人脸在哪里,不需要知道是谁时:
pipeline = FaceHubPipeline(camera, detector, recognizer, tracker, db)
pipeline.start()
frame = cv2.imread("crowd.jpg")
detections = pipeline.detect_only(frame)
print(f"检测到 {len(detections)} 张人脸")
for det in detections:
x1, y1, x2, y2 = det.bbox.to_tuple()
print(f" 人脸框: ({x1},{y1},{x2},{y2}) 置信度={det.confidence:.2f}")
提取特征但不追踪¶
适合批量处理照片、建立人脸库:
frame = cv2.imread("photo.jpg")
faces = pipeline.extract_embeddings(frame)
for face in faces:
if face.has_embedding:
print(f"特征维度: {face.embedding.shape}") # (512,)
print(f"数据类型: {face.embedding.dtype}") # float32
print(f"L2 范数: {np.linalg.norm(face.embedding):.4f}") # ≈ 1.0
# 可将特征存入数据库
if faces and faces[0].has_embedding:
db.add_person("Alice", "alice.jpg", faces[0].embedding)
pipeline.update_database_cache() # 刷新识别器缓存
动态注册新用户¶
运行时实时注册新用户:
import cv2
def register_person(pipeline, db, name, photo_path):
"""从照片中提取人脸特征并注册到数据库"""
frame = cv2.imread(photo_path)
if frame is None:
print(f"无法读取图片: {photo_path}")
return False
faces = pipeline.extract_embeddings(frame)
if not faces:
print("未检测到人脸")
return False
face = faces[0] # 取置信度最高的人脸
if not face.has_embedding:
print("特征提取失败")
return False
ok, msg = db.add_person(name, photo_path, face.embedding)
if ok:
pipeline.update_database_cache()
print(f"成功注册: {name}")
else:
print(f"注册失败: {msg}")
return ok
# 用法
register_person(pipeline, db, "Alice", "photos/alice.jpg")
register_person(pipeline, db, "Bob", "photos/bob.jpg")
调整追踪器参数后重置¶
错误处理¶
from face_hub.exceptions import FaceHubError
from face_hub import FaceHubPipeline
pipeline = FaceHubPipeline(camera, detector, recognizer, tracker, db)
pipeline.start()
try:
while True:
try:
result = pipeline.process_frame()
except FaceHubError as e:
print(f"流水线错误(已跳过本帧): {e}")
continue
if result is None:
continue
# 处理 result ...
finally:
pipeline.stop()
完整应用模版¶
将以上所有功能整合到一个完整的应用程序中:
import cv2
from face_hub import (
FaceHubPipeline, FaceDetector, FaceRecognizer,
FaceTracker, FaceDatabase, CameraThread,
)
from face_hub.exceptions import FaceHubError
def main():
# === 初始化 ===
camera = CameraThread(camera_id=0, width=640, height=360, fps=30)
detector = FaceDetector(device="auto", det_size=640, confidence=0.50)
recognizer = FaceRecognizer(tolerance=0.45)
tracker = FaceTracker(smooth_frames=5)
db = FaceDatabase()
# 加载已有的人脸库(如果存在)
try:
encodings, names = db.get_encodings_and_names()
recognizer.update_cache(encodings, names, db.version)
print(f"已加载 {len(names)} 个注册用户: {names}")
except FaceHubError:
print("人脸库为空或加载失败")
# === 启动流水线 ===
pipeline = FaceHubPipeline(camera, detector, recognizer, tracker, db)
pipeline.start()
print("FaceHub 已启动,按 ESC 退出,按 'r' 重新同步数据库...")
print(f"实际 FPS: {camera.actual_fps:.1f}")
try:
while True:
result = pipeline.process_frame()
if result is None:
continue
# 绘制结果
draw_results(result)
# 显示
cv2.imshow("FaceHub", result.frame)
key = cv2.waitKey(1) & 0xFF
if key == 27: # ESC
break
elif key == ord('r'):
pipeline.update_database_cache()
print("已刷新识别器缓存")
except KeyboardInterrupt:
pass
finally:
pipeline.stop()
cv2.destroyAllWindows()
print("FaceHub 已停止")
def draw_results(result):
"""在帧上绘制识别结果"""
for face in result.tracked_faces:
x1, y1, x2, y2 = face.bbox.to_tuple()
if face.is_known:
color = (0, 255, 0)
label = f"{face.name} {face.confidence:.0%}"
else:
color = (0, 165, 255)
label = face.name
cv2.rectangle(result.frame, (x1, y1), (x2, y2), color, 2)
cv2.putText(result.frame, label, (x1, y1 - 8),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
cv2.putText(result.frame, f"FPS: {result.fps:.1f}",
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2)
if __name__ == "__main__":
main()
注意事项¶
- 首次调用
FaceDetector()时会自动下载 insightface 的buffalo_l模型(约 200 MB)。 process_frame()返回None表示当前没有新帧,可直接跳过继续循环。- 追踪器会在人脸离开画面
max_missed帧后自动移除该追踪。 known_faces是tracked_faces的子集,仅包含is_known=True的人脸。