该文件位于com.ruturaj.detectlightning
包中。com.ruturaj.detectlightning.mlkit
包含所有对象检测所需的类文件。
首先,从包开始:
Java
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 {
在类全局范围内定义了一些重要的变量和字符串:
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;
}
}
}
以下代码维护AndroidUI生命周期,以防中断:
@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];
}
}
私有方法allPermissionsGranted
:
private boolean allPermissionsGranted() {
for (String permission : getRequiredPermissions()) {
if (!isPermissionGranted(this, permission)) {
return false;
}
}
return true;
}
私有方法getRuntimePermissions
:
private void getRuntimePermissions() {
List 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);
}
私有静态方法isPermissionGranted
:
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
日志时,轨迹以红色出现 - 很容易看到。