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





5.00/5 (5投票s)
在本文中,我们将在 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 设备上对我们的应用程序进行实时测试。


