1.android代碼,從創建activity說起.
facedetectioncpu(我們暫時講cpu版本) 下的MainActivity.java文件.
a. 毫無疑問,我們來看看.
protected void onCreate(Bundle savedInstanceState);
在創建activity的時候,做了些什麼工作呢?
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
previewDisplayView = new SurfaceView(this);
setupPreviewDisplayView();
// Initialize asset manager so that MediaPipe native libraries can access the app assets, e.g.,
// binary graphs.
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);
以上是 部分代碼.
b.加載了 layout文件夾下的 activity_main.xml 文件.
c.創建了 SurfaceView ..
然後設置一下 預覽的視圖 參數. 下面是代碼:
previewDisplayView.setVisibility(View.GONE);
ViewGroup viewGroup = findViewById(R.id.preview_display_layout);
viewGroup.addView(previewDisplayView);
只是 部分代碼.
只是剛開始,控件是不可見的,
然後去xml 文件 去找這個控件,添加之.
Surface的 三種狀態 回調代碼就 不貼出了, A.創建,B. 改變 C. 銷燬 (這三個)
2.接着我們繼續看
AndroidAssetUtil.initializeNativeAssetManager(this);
從 字面本意上看,是初始化本地assert 文件管理.
跟蹤進去看,原來這個是靜態函數,實際上調用的是 native 寫的.
public static boolean initializeNativeAssetManager(Context androidContext) {
return nativeInitializeAssetManager(
androidContext, androidContext.getCacheDir().getAbsolutePath());
}
至於這個c/c++代碼,實現了啥,這裏暫時不跟下去.
3.接着我們繼續往下看.
eglManager = new EglManager(null);
哦,這個原來是 OpenGL 的 初始化地方.
那它做了神嘛呢?
點進去看了下.
原來 EglManager(null),只是它其中的一個構造函數.調用了下面這個
public EglManager(@Nullable Object parentContext, @Nullable int[] additionalConfigAttributes) {
singleIntArray = new int[1];
egl = (EGL10) EGLContext.getEGL();
eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
if (eglDisplay == EGL10.EGL_NO_DISPLAY) {
throw new RuntimeException("eglGetDisplay failed");
}
int[] version = new int[2];
if (!egl.eglInitialize(eglDisplay, version)) {
throw new RuntimeException("eglInitialize failed");
}
....
}
這裏,我們不過多介紹了,我們理解它 可以正確完成初始化就好.
4.繼續往下看...
processor =
new FrameProcessor(
this,
eglManager.getNativeContext(),
BINARY_GRAPH_NAME,
INPUT_VIDEO_STREAM_NAME,
OUTPUT_VIDEO_STREAM_NAME);
其中的 BINRAY_GRAPH_NAME 變量是: facedetectioncpu.binarypb
從代碼上看 是要加載這個文件.(估計這個是核心部分)
事實上,在我們創建app 時,bazel build的時候,做了一些預處理.
來看我麼的BUILD 文件.
genrule(
name = "binary_graph",
srcs = ["//mediapipe/graphs/face_detection:mobile_cpu_binary_graph"],
outs = ["facedetectioncpu.binarypb"],
cmd = "cp $< $@",
)
android_library(
name = "mediapipe_lib",
srcs = glob(["*.java"]),
assets = [
":binary_graph",
"//mediapipe/models:face_detection_front.tflite",
"//mediapipe/models:face_detection_front_labelmap.txt",
],
...
)
在 graphs下的 face_detection下的BUILD 文件裏
mediapipe_binary_graph(
name = "mobile_cpu_binary_graph",
graph = "face_detection_mobile_cpu.pbtxt",
output_name = "mobile_cpu.binarypb",
deps = [":mobile_calculators"],
)
恩?
那麼face_detection_mobile_cpu.pbtxt 這個文件是幹嘛的呢?
難道就是上面 兩三段代碼,將定義的 xx.pbtxt 與 xx_front.tflite 和 xx_front_labelmap.txt 相關聯的?
5.進去看了看(face_detection_mobile_cpu.pbtxt)
定義了一些Node,還有算子,(包括配置算子參數等)
難道這裏面 就是真正實現了 檢測人臉算法的過程?(一系列,甚至包括,人臉檢測出來信息,框體位置轉化,甚至繪製在表面都在這裏完成? )
然後 就初始化了,跑起來了?
(是這樣的,看完代碼之後才知道,原來檢測速度流暢是有原因的)
後面沒什麼代碼了 (就是打開攝像頭.(如果權限有的話,就打開攝像頭...))
代碼是:
@Override
protected void onResume() {
super.onResume();
converter = new ExternalTextureConverter(eglManager.getContext());
converter.setFlipY(FLIP_FRAMES_VERTICALLY);
converter.setConsumer(processor);
if (PermissionHelper.cameraPermissionsGranted(this)) {
startCamera();
}
}
作者對加載過程還是不太明白,如有正在研究這框架的夥伴,歡迎 各位大佬 指點迷津:
留言即可.謝謝啦