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

如何在Android端使用MediaPipe Pose修改追踪点与连接线颜色

修改MediaPipe Pose身体关键点与连接线颜色

方案一:通过PoseLandmarker配置直接修改(推荐)

如果使用MediaPipe的PoseLandmarker组件,可在初始化时通过配置类直接指定关键点和连接线的颜色:

// 初始化PoseLandmarkerOptions
PoseLandmarkerOptions options =
    PoseLandmarkerOptions.builder(this)
        .setPoseLandmarksColor(Color.RED) // 设置关键点颜色
        .setPoseConnectionsColor(Color.BLUE) // 设置连接线颜色
        .setPoseLandmarksRadius(8.0f) // 可选:调整关键点大小
        .setPoseConnectionsThickness(5.0f) // 可选:调整连接线粗细
        .build();

// 创建PoseLandmarker实例
PoseLandmarker poseLandmarker =
    PoseLandmarker.createFromOptions(this, options);

方案二:手动绘制关键点与连接线(适合自定义需求)

从你的代码来看,已经通过FrameProcessor获取到了NormalizedLandmarkList,这种情况下可以自行使用Canvas绘制,完全控制颜色和样式:

  1. 在Activity中初始化绘制画笔并保存关键点数据:
private Paint landmarkPaint = new Paint();
private Paint connectionPaint = new Paint();
private NormalizedLandmarkList currentLandmarks; // 保存当前帧的关键点数据

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 初始化绘制画笔
    landmarkPaint.setColor(Color.GREEN);
    landmarkPaint.setStyle(Paint.Style.FILL);
    landmarkPaint.setStrokeWidth(12f);

    connectionPaint.setColor(Color.YELLOW);
    connectionPaint.setStyle(Paint.Style.STROKE);
    connectionPaint.setStrokeWidth(6f);

    // 原有代码...
    previewDisplayView = new SurfaceView(this);
    setupPreviewDisplayView();

    AndroidAssetUtil.initializeNativeAssetManager(this);
    eglManager = new EglManager(null);
    processor = new FrameProcessor(
                    this,
                    eglManager.getNativeContext(),
                    BINARY_GRAPH_NAME,
                    INPUT_VIDEO_STREAM_NAME,
                    OUTPUT_VIDEO_STREAM_NAME);
    
    processor.getVideoSurfaceOutput().setFlipY(FLIP_FRAMES_VERTICALLY);

    processor.addPacketCallback(
            OUTPUT_LANDMARKS_STREAM_NAME,
            (packet) -> {
                Log.v(TAG, "Received Pose landmarks packet.");
                byte[] landmarksRaw = PacketGetter.getProtoBytes(packet);
                currentLandmarks = NormalizedLandmarkList.parseFrom(landmarksRaw);
                
                // 触发UI线程重绘
                runOnUiThread(() -> previewDisplayView.invalidate());
            }
    );
    PermissionHelper.checkAndRequestCameraPermissions(this);
}
  1. 自定义SurfaceView的绘制逻辑,覆盖在预览层上绘制关键点和连接线:
private class PoseDrawSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder holder;

    public PoseDrawSurfaceView(Context context) {
        super(context);
        holder = getHolder();
        holder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        drawPose();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        drawPose();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {}

    private void drawPose() {
        if (currentLandmarks == null) return;
        Canvas canvas = holder.lockCanvas();
        if (canvas == null) return;

        int viewWidth = getWidth();
        int viewHeight = getHeight();

        // 绘制连接线(使用MediaPipe预定义的Pose连接关系)
        for (Connection connection : PoseLandmarker.POSE_CONNECTIONS) {
            NormalizedLandmark start = currentLandmarks.getLandmark(connection.start());
            NormalizedLandmark end = currentLandmarks.getLandmark(connection.end());
            
            float startX = start.getX() * viewWidth;
            float startY = start.getY() * viewHeight;
            float endX = end.getX() * viewWidth;
            float endY = end.getY() * viewHeight;
            
            canvas.drawLine(startX, startY, endX, endY, connectionPaint);
        }

        // 绘制关键点
        for (NormalizedLandmark landmark : currentLandmarks.getLandmarkList()) {
            float x = landmark.getX() * viewWidth;
            float y = landmark.getY() * viewHeight;
            canvas.drawCircle(x, y, 8f, landmarkPaint);
        }

        holder.unlockCanvasAndPost(canvas);
    }
}

注意事项

  • 若使用PoseDetection而非PoseLandmarker,逻辑类似,需找到对应配置类或手动绘制。
  • 手动绘制时,MediaPipe的归一化坐标以图像左上角为原点,x向右、y向下,需转换为屏幕坐标后再绘制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 13:27:24