65.9K
CodeProject 正在变化。 阅读更多。
Home

使用深度学习和 Tensorflow 在 Android 上进行闪电检测:设置 TFLite 模型

starIconstarIconstarIconstarIconstarIcon

5.00/5 (5投票s)

2020 年 11 月 16 日

CPOL

3分钟阅读

viewsIcon

7261

downloadIcon

218

在本文中,我们将在 Android 环境中设置 TFLite 模型,并创建一个可用的演示应用程序。

引言

在前一篇文章中,我们介绍了基于模型的应用程序在 Android 环境中的基本设置。

MainActivity.java 文件

这是一个非常重要的文件,它促进了用户与我们的 Android 应用程序的交互。我们将逐行或逐块地浏览此文件。

该文件位于 com.ruturaj.detectlightning 包中。 com.ruturaj.detectlightning.mlkit 包含对象检测所需的所有类文件。

让我们从包开始

package com.ruturaj.detectlightning;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.google.mlkit.common.model.LocalModel;
import com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions;
import com.ruturaj.detectlightning.mlkit.CameraSource;
import com.ruturaj.detectlightning.mlkit.CameraSourcePreview;
import com.ruturaj.detectlightning.mlkit.GraphicOverlay;
import com.ruturaj.detectlightning.mlkit.ObjectDetectorProcessor;
import com.ruturaj.detectlightning.mlkit.PreferenceUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements ActivityCompat.OnRequestPermissionsResultCallback {

一些重要的变量和字符串在 class-globally 中定义

	private static final String OBJECT_DETECTION_CUSTOM = "Lightning";

	private static final String TAG = "MainActivity";
	private static final int PERMISSION_REQUESTS = 1;

	private CameraSource cameraSource = null;
	private CameraSourcePreview preview;
	private GraphicOverlay graphicOverlay;
	private String selectedModel = OBJECT_DETECTION_CUSTOM;

如果您熟悉 Android 生命周期,我相信您知道以下方法!

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

从后置摄像头为我们的直播设置预览。

    	preview = findViewById(R.id.preview_view);
    	if (preview == null) {
        	Log.e(OBJECT_DETECTION_CUSTOM, "Preview is null");
    	}

接下来,我们在屏幕上检测到闪电的部分绘制一个图形叠加层(在本例中是一个边界框),同时处于相机模式。

        graphicOverlay = findViewById(R.id.graphic_overlay);
    	if (graphicOverlay == null) {
        	Log.e(OBJECT_DETECTION_CUSTOM, "graphicOverlay is null");
    	}

接下来,我们检查我们的应用程序是否已经拥有所需的权限,如果没有,我们在运行时请求它们

        if (allPermissionsGranted()) {
        	createCameraSource(selectedModel);
    	} else {
        	getRuntimePermissions();
    	}
	}

调用 CameraSource 类以使用我们的模型将相机视图显示到屏幕上

        if (allPermissionsGranted()) {
        	createCameraSource(selectedModel);
    	} else {
        	getRuntimePermissions();
    	}
	}

当存储在 assets 文件夹中的模型运行时,我们调用 LocalModel 类来构建模型并检测对象。 CustomObjectDetectorOptions 通常用于实时检测相机视野中最突出的对象。

    	try {
        	if (OBJECT_DETECTION_CUSTOM.equals(model)) {
            	Log.e(OBJECT_DETECTION_CUSTOM, "Using Custom Object Detector Processor");
            	LocalModel localModel =
                    	new LocalModel.Builder()
                                .setAssetFilePath("model.tflite")
                            	.build();
                CustomObjectDetectorOptions customObjectDetectorOptions =
        	            PreferenceUtils.getCustomObjectDetectorOptionsForLivePreview(this, localModel);
            	cameraSource.setMachineLearningFrameProcessor(
                    	new ObjectDetectorProcessor(this, customObjectDetectorOptions));
        	} else {
            	Log.e(OBJECT_DETECTION_CUSTOM, "Unknown model: " + model);
        	}
    	} catch (Exception e) {
        	Log.e(OBJECT_DETECTION_CUSTOM, "Can not create image processor: " + model, e);
        	Toast.makeText(
   	             getApplicationContext(),
                	"Can not create image processor: " + e.getMessage(),
                	Toast.LENGTH_LONG)
                	.show();
    	}
	}

一旦授予权限,并且应用程序显示预览,就启动相机。

	private void startCameraSource() {
    	if (cameraSource != null) {
        	try {
            	if (preview == null) {
                	Log.e(TAG, "resume: Preview is null");
            	}
            	if (graphicOverlay == null) {
                	Log.e(TAG, "resume: graphOverlay is null");
            	}
            	preview.start(cameraSource, graphicOverlay);
        	} catch (IOException e) {
                Log.e(TAG, "Unable to start camera source.", e);
            	cameraSource.release();
            	cameraSource = null;
        	}
    	}
	}

以下代码在发生中断时维护 Android UI 生命周期

	@Override
	public void onResume() {
    	super.onResume();
    	Log.e(TAG, "onResume");
    	createCameraSource(selectedModel);
    	startCameraSource();
	}

应用程序暂停的处理方式如下

	@Override
	protected void onPause() {
    	super.onPause();
    	preview.stop();
	}

关闭应用程序会销毁相机预览

	@Override
	public void onDestroy() {
    	super.onDestroy();
    	if (cameraSource != null) {
        	cameraSource.release();
    	}
	}

onCreate 调用授予对所需权限的访问权限之后

    private String[] getRequiredPermissions() {
    	try {
        	PackageInfo info =
                	this.getPackageManager()
                        	.getPackageInfo(this.getPackageName(), PackageManager.GET_PERMISSIONS);
        	String[] ps = info.requestedPermissions;
        	if (ps != null && ps.length > 0) {
            	return ps;
        	} else {
            	return new String[0];
        	}
    	} catch (Exception e) {
        	return new String[0];
    	}
	}

	private boolean allPermissionsGranted() {
    	for (String permission : getRequiredPermissions()) {
        	if (!isPermissionGranted(this, permission)) {
            	return false;
        	}
    	}
    	return true;
	}

	private void getRuntimePermissions() {
    	List<String> allNeededPermissions = new ArrayList<>();
    	for (String permission : getRequiredPermissions()) {
        	if (!isPermissionGranted(this, permission)) {
                allNeededPermissions.add(permission);
        	}
    	}

    	if (!allNeededPermissions.isEmpty()) {
        	ActivityCompat.requestPermissions(
                	this, allNeededPermissions.toArray(new String[0]), PERMISSION_REQUESTS);
    	}
	}

	@Override
	public void onRequestPermissionsResult(
        	int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    	Log.i(TAG, "Permission granted!");
    	if (allPermissionsGranted()) {
        	createCameraSource(selectedModel);
    	}
    	super.onRequestPermissionsResult(requestCode, permissions, grantResults);
	}

	private static boolean isPermissionGranted(Context context, String permission) {
    	if (ContextCompat.checkSelfPermission(context, permission)
            	== PackageManager.PERMISSION_GRANTED) {
        	Log.i(TAG, "Permission granted: " + permission);
        	return true;
    	}
    	Log.i(TAG, "Permission NOT granted: " + permission);
    	return false;
	}

}

您会在代码中看到很多 Log.e… 的实例。这只是为了使 Logcat 检查在视觉上突出。当我执行 e- Error 日志时,跟踪以红色显示 - 易于查看。

其他类文件

类文件名 描述
BitmapUtils 用于位图转换的 utils 函数。
CameraImageGraphic 在背景中绘制相机图像。
CameraSource 管理相机并允许在相机顶部进行 UI 更新(例如,覆盖额外的图形或显示额外的信息)。它以指定的速率从相机接收预览帧,并将这些帧发送到子类的检测器/分类器,并尽可能快地处理它们。
CameraSourcePreview 在屏幕上预览相机图像。
FrameMetaData 包含有关帧的附加信息。
GraphicOverlay 渲染一系列自定义图形,以叠加在预览之上(即,相机预览)。创建者可以添加图形对象、更新这些对象并删除它们,从而触发视图中的适当绘制和失效。
InferenceInfoGraphic 一个图形实例,用于在叠加视图中渲染推理信息(延迟、FPS、分辨率)。
ObjectDetectorProcessor 一个运行对象检测器的处理器。
ObjectGraphic 在预览中绘制检测到的对象信息。
PreferenceUtils 一个用于检索共享首选项的实用程序类。
ScopedExecutor 包装现有执行程序,以提供一种方法来后续取消提交的 Runnable。
VisionImageProcessor 一个用于使用各种视觉检测器和自定义图像模型处理图像的接口。
VisionProcessorBase 提取视觉帧处理器的基类。 子类需要实现此接口以定义他们想要使用检测结果做什么,并指定检测器对象。

后续步骤

下一篇文章 中,我们将在 Android 设备上对我们的应用程序进行实时测试。

© . All rights reserved.