You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++环境下将非摄像头视频流接入Mediapipe手部识别?

MediaPipe C++ 手部识别自定义输入输出流实现方案

官方C++端的计算图本身就支持手动传入输入流、读取输出流,不需要依赖默认的摄像头采集、屏幕渲染组件,仅需少量修改即可实现需求,以下是可直接落地的实现方案:

第一步:修改手部识别计算图配置

只需要修改官方默认的计算图pbtxt配置,删除绑定摄像头、屏幕输出的节点,保留核心识别逻辑,新增对外暴露的输入输出流声明即可:

  • 删除默认配置里绑定摄像头的PacketGenerator组件
  • 删除默认配置里负责渲染到屏幕的OpenCvPreviewSink组件
  • 新增自定义输入输出流声明,中间所有手部识别核心节点的配置完全不需要调整

修改后的配置片段示例:

# 对外暴露的输入流,用于接收外部传入的图像
input_stream: "input_frames"
# 对外暴露的输出流,用于输出识别结果,可按需添加多个
output_stream: "hand_landmarks"
output_stream: "handedness"

# 中间保留官方手部识别的所有核心节点配置,直接复用官方原有参数即可
node {
  calculator: "HandLandmarkCpu"
  input_stream: "IMAGE:input_frames"
  output_stream: "LANDMARKS:hand_landmarks"
  output_stream: "HANDEDNESS:handedness"
  options: {
    [mediapipe.HandLandmarkCpuOptions.ext] {
      num_hands: 2
      min_detection_confidence: 0.5
    }
  }
}

第二步:C++ 核心代码实现

整体逻辑只有3个环节:初始化计算图、传入自定义输入帧、读取输出结果,示例代码如下:

1. 头文件引入

#include "mediapipe/framework/calculator_graph.h"
#include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/formats/image_frame_opencv.h"
#include "mediapipe/framework/formats/landmark.pb.h"
#include "mediapipe/framework/port/opencv_highgui_inc.h"
#include "mediapipe/framework/port/opencv_imgproc_inc.h"
#include "mediapipe/framework/port/parse_text_proto.h"

2. 计算图初始化

// 加载修改完成的计算图配置
mediapipe::CalculatorGraphConfig config = 
  mediapipe::ParseTextProtoOrDie<mediapipe::CalculatorGraphConfig>(R"(
  // 此处粘贴第一步修改完成的完整pbtxt配置
)");

mediapipe::CalculatorGraph graph;
MP_ASSERT_OK(graph.Initialize(config));

// 存储输出的手部关键点结果
std::vector<mediapipe::NormalizedLandmarkList> hand_landmark_results;
// 注册输出流观测回调,计算完成后会自动触发回调返回结果
MP_ASSERT_OK(graph.ObserveOutputStream("hand_landmarks", 
  [&hand_landmark_results](const mediapipe::Packet& packet) -> mediapipe::Status {
    hand_landmark_results.push_back(packet.Get<mediapipe::NormalizedLandmarkList>());
    return mediapipe::OkStatus();
  }));

// 启动计算图
MP_ASSERT_OK(graph.StartRun({}));

3. 手动传入自定义输入流

你可以从任意来源(视频文件、RTSP流、内存图像数据等)获取图像,转换为MediaPipe支持的格式传入即可,以下是传入OpenCV Mat格式帧的示例:

cv::Mat frame;
// 此处可以替换为任意图像读取逻辑,比如读本地图片、拉流解码后的数据等
cv::VideoCapture cap("your_input_source.mp4");
// 时间戳必须严格单调递增,单位为微秒
int64_t timestamp = 0;

while (cap.read(frame)) {
  // 转换OpenCV BGR格式为MediaPipe要求的RGB格式
  auto input_frame = absl::make_unique<mediapipe::ImageFrame>(
    mediapipe::ImageFormat::SRGB, frame.cols, frame.rows,
    mediapipe::ImageFrame::kDefaultAlignmentBoundary);
  cv::cvtColor(frame, mediapipe::formats::MatView(input_frame.get()), cv::COLOR_BGR2RGB);

  // 将图像包传入计算图输入流
  MP_ASSERT_OK(graph.AddPacketToInputStream(
    "input_frames",
    mediapipe::Adopt(input_frame.release())
      .At(mediapipe::Timestamp(timestamp))
  ));

  // 按实际帧率调整时间戳增量,30fps对应每帧间隔33000微秒
  timestamp += 33000;
}

4. 停止计算图并获取完整结果

// 关闭输入流,等待所有计算任务完成
MP_ASSERT_OK(graph.CloseInputStream("input_frames"));
MP_ASSERT_OK(graph.WaitUntilDone());

// 此时hand_landmark_results中已经存储了所有输入帧的手部关键点结果,可自行处理

注意事项

  • 输入流的时间戳必须严格单调递增,不能重复或回退,否则计算图会直接报错
  • 如果需要同时获取多类输出(比如手势分类结果、手部掩码),只需要在计算图配置里新增对应的output_stream,再分别注册观测回调即可
  • 切换CPU/GPU运行模式仅需要替换Calculator的后缀(HandLandmarkCpu改为HandLandmarkGpu),输入输出逻辑完全不需要修改

内容的提问来源于stack exchange,提问作者DirenD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 06:27:03