如何在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绘制,完全控制颜色和样式:
- 在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); }
- 自定义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
相关产品推荐
相关产品推荐

