15.3 Android姿势预测器
在准备好TensorFlow Lite模型后,接下来将使用这个模型开发一个Android身体姿势识别器系统。
15.3.1 准备工作
(1)打开app模块中的文件build.gradle,分别设置Android的编译版本和运行版本,设置需要使用的库文件,添加对TensorFlow Lite模型库的引用。代码如下:
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "org.tensorflow.lite.examples.poseestimation"
minSdkVersion 23
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
//下载tflite模型
apply from:"download.gradle"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.5.0'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation "androidx.activity:activity-ktx:1.2.3"
implementation 'androidx.fragment:fragment-ktx:1.3.5'
implementation 'org.tensorflow:tensorflow-lite:2.5.0'
implementation 'org.tensorflow:tensorflow-lite-gpu:2.5.0'
implementation 'org.tensorflow:tensorflow-lite-support:0.2.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation "com.google.truth:truth:1.1.3"
}
(2)在文件download.gradle中设置下载TensorFlow Lite模型文件的链接,代码如下:
task downloadPosenetModel(type: DownloadUrlTask) {
def modelPosenetDownloadUrl = "https://storage.googleapis.com/download.tensorflow.org/models/tflite/posenet_mobilenet_v1_100_257x257_multi_kpt_stripped.tflite"
doFirst {
println "Downloading ${modelPosenetDownloadUrl}"
}
sourceUrl = "${modelPosenetDownloadUrl}"
target = file("src/main/assets/posenet_model.tflite")
}
task downloadMovenetLightningModel(type: DownloadUrlTask) {
def modelMovenetLightningDownloadUrl = "https://tfhub.dev/google/lite-model/movenet/singlepose/lightning/3?lite-format=tflite"
doFirst {
println "Downloading ${modelMovenetLightningDownloadUrl}"
}
sourceUrl = "${modelMovenetLightningDownloadUrl}"
target = file("src/main/assets/movenet_lightning_v3.tflite")
}
task downloadMovenetThunderModel(type: DownloadUrlTask) {
def modelMovenetThunderDownloadUrl = "https://tfhub.dev/google/lite-model/movenet/singlepose/thunder/3?lite-format=tflite"
doFirst {
println "Downloading ${modelMovenetThunderDownloadUrl}"
}
sourceUrl = "${modelMovenetThunderDownloadUrl}"
target = file("src/main/assets/movenet_thunder_v3.tflite")
}
task downloadModel {
dependsOn downloadPosenetModel
dependsOn downloadMovenetLightningModel
dependsOn downloadMovenetThunderModel
}
class DownloadUrlTask extends DefaultTask {
@Input
String sourceUrl
@OutputFile
File target
@TaskAction
void download() {
ant.get(src: sourceUrl, dest: target)
}
}
preBuild.dependsOn downloadModel
15.3.2 页面布局
本项目的页面布局文件是activity_main.xml,功能是在Android界面中显示相机预览框视图,主要实现代码如下:
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#66000000">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"
android:src="@drawable/tfl2_logo" />
</androidx.appcompat.widget.Toolbar>
<include layout="@layout/bottom_sheet_layout"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
在上述代码中,调用了文件bottom_sheet_layout.xml中的布局信息,功能是在相机预览界面下方显示一个滑动面板,在面板中显示识别得分,还可以设置设备的类型和模型文件的类型。文件bottom_sheet_layout.xml的主要实现代码如下所示:
<ImageView
android:contentDescription="@null"
android:id="@+id/bottom_sheet_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/icn_chevron_up" />
<TextView
android:id="@+id/tvTime"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tvScore"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tfe_pe_tv_device" />
<Spinner
android:id="@+id/spnDevice"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tfe_pe_tv_model" />
<Spinner
android:id="@+id/spnModel"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>