Android版MediaPipe实战指南:从集成到性能优化
·
最近在Android项目里接入了MediaPipe做实时图像处理,踩了不少坑也积累了些经验。整理成这篇笔记,希望能帮到同样想用MediaPipe的开发者们。
一、为什么选MediaPipe?
Android上跑机器学习模型的选择不少,比如TensorFlow Lite和ML Kit。但MediaPipe有两个独特优势:
- 预制解决方案丰富:手部跟踪、姿态估计这些常见需求直接提供现成pipeline
- 跨平台一致性:同一套graph配置能在Android/iOS/桌面端运行
不过Android环境特有的碎片化问题还是带来了挑战:
- 不同CPU架构(armeabi-v7a/arm64-v8a)需要单独编译.so
- 低端机内存有限,直接跑官方demo容易出现OOM

二、快速集成指南
1. 环境准备
建议用Bazel构建,虽然学习曲线陡峭但灵活性更高。在WORKSPACE文件添加:
mediapipe_git = "https://github.com/google/mediapipe"
http_archive(
name = "mediapipe",
urls = [mediapipe_git + "/archive/%s.tar.gz" % "v0.9.3"],
strip_prefix = "mediapipe-0.9.3",
)
2. 构建Android AAR
关键命令(需要安装NDK):
bazel build -c opt \
--config=android_arm64 \
mediapipe/examples/android/src/java/com/google/mediapipe/apps/handtrackinggpu:handtrackinggpu
3. 代码集成
处理摄像头流的核心代码(Kotlin协程版):
class CameraActivity : AppCompatActivity() {
private val processor by lazy {
FrameProcessor(
this,
R.raw.hand_tracking_mobile_gpu, // 自定义graph
"hand_tracking_mobile_gpu.pbtxt"
).apply {
setConsumer { packet ->
val landmarks = PacketGetter.getProtoVector(packet, NormalizedLandmarkList.parser())
updateLandmarks(landmarks)
}
}
}
override fun onCameraStarted(surfaceTexture: SurfaceTexture) {
processor.videoSurfaceOutput.autoAttachToGLThread = true
processor.getVideoSurfaceOutput().setSurface(
Surface(surfaceTexture)
)
}
}
三、性能优化实战
1. 内存管理
MediaPipe默认使用GpuBuffer处理图像,但转Bitmap很耗性能。建议:
- 在graph里直接处理GpuBuffer避免转换
- 必须转换时复用Bitmap对象
// 错误示例:每帧new Bitmap
Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
// 正确做法:复用对象
if (cachedBitmap == null ||
cachedBitmap.getWidth() != width ||
cachedBitmap.getHeight() != height) {
cachedBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
}
2. 多线程策略
实测数据(Pixel 4 XL):
| 线程数 | 平均延迟(ms) | CPU占用率 | |--------|-------------|-----------| | 1 | 42.3 | 65% | | 2 | 38.1 | 82% | | 4 | 36.7 | 95% |
建议根据设备核心数动态调整:
val numThreads = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ->
Runtime.getRuntime().availableProcessors()
else -> 2
}
processor.setNumThreads(numThreads)

四、避坑经验
- ABI过滤:在app/build.gradle里指定需要的架构,减少APK体积
android {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
- SurfaceView vs TextureView:
- SurfaceView延迟更低(约低15-20ms)
-
TextureView支持动画和透明度
-
ProGuard规则:
-keep class com.google.mediapipe.** { *; }
-keep class com.google.protobuf.** { *; }
五、进阶方向
尝试结合CameraX的Analyzer API,可以进一步降低端到端延迟:
val analyzer = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
.also {
it.setAnalyzer(executor) { image ->
val gpuBuffer = imageToGpuBuffer(image) // 实现转换逻辑
processor.process(gpuBuffer)
image.close()
}
}
现在我的demo在Pixel 6上能做到1080p@30fps处理,端到端延迟控制在80ms以内。关键还是吃透了MediaPipe的pipeline设计,后续准备尝试把Hand Tracking和ARCore结合起来玩些新花样。
更多推荐


所有评论(0)