1. 基础开发环境
JDK:JDK17
Android Studio:Android Studio Giraffe | 2022.3.1
Android SDK:Android API 34
Gradle: gradle-8.0-bin.zip
CameraX Version: 1.1.0-alpha05
2. 添加相关依赖
在 build.gradle 中添加 CameraX 的相关依赖
// *** Camera 相关依赖 ***def cameraxVersion = "1.1.0-alpha05";implementation "androidx.camera:camera-core:${cameraxVersion}"implementation "androidx.camera:camera-camera2:${cameraxVersion}"implementation "androidx.camera:camera-lifecycle:${cameraxVersion}"implementation 'androidx.camera:camera-view:1.0.0-alpha25'// ***********************
在 AndroidManifest.xml 文件中注册相机权限
<!-- 这个权限声明意味着此 Android 应用程序需要设备具有摄像头功能才能正常运行,并且如果设备没有摄像头,则应用程序将无法在该设备上安装或运行。"android:required = "true"" 表示摄像头功能是必需的,而不是可选的。 --><uses-featureandroid:name="android.hardware.camera"android:required="true" /><!-- 注册相机权限 --><!-- 这个权限允许应用程序读取摄像头的输入并拍照或录制视频。如果没有这个权限,应用程序将无法访问设备的相机功能。 --><uses-permission android:name="android.permission.CAMERA" /><!-- 这个权限允许应用程序录制音频。 --><uses-permission android:name="android.permission.RECORD_AUDIO" /><!-- 这个权限允许应用程序向外部存储(例如SD卡)写入数据。而这个权限只适用于 Android 版本号不大于 28 的设备。 --><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"android:maxSdkVersion="28" />
3. APP 布局
使用 LinearLayout 布局,其中添加一个 PreviewView 用来显示相机画面的预览,添加一个 Button 用来控制图像分析。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:divider="@color/black"android:gravity="center"android:orientation="vertical"tools:context=".MainActivity"><androidx.camera.view.PreviewViewandroid:id="@+id/previewView"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_weight="3" /><Buttonandroid:id="@+id/analysisButton"android:layout_width="wrap_content"android:layout_height="100dp"android:layout_weight="1"android:text="@string/analysis_button" /></LinearLayout>
<resources><string name="app_name">camera-video-analysis</string><string name="analysis_button">分析</string>
</resources>
4. 主流程逻辑
package com.example.analysis;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat;import android.os.Bundle;
import android.util.Log;
import android.util.Size;
import android.view.View;
import android.widget.Button;import com.google.common.util.concurrent.ListenableFuture;import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;public class MainActivity extends AppCompatActivity implements View.OnClickListener {private ListenableFuture<ProcessCameraProvider> processCameraProviderListenableFuture;PreviewView previewView;Button analysisButton;ImageAnalysis imageAnalysis;@Overrideprotected void onCreate(Bundle savedInstanceState) {// onCreate 在活动被创建时被调用的。// 它的作用是对活动进行初始化,例如加载布局文件,设置事件监听器和初始化变量等。// `Bundle savedInstanceState` 参数用于保存活动状态,以便在活动被销毁后能够恢复它的状态。super.onCreate(savedInstanceState);// 将指定的布局文件加载到当前 Activity 中并显示在屏幕上。setContentView(R.layout.activity_main);// 从当前布局中查找具有指定 ID 的视图,并将其返回为 Java 对象。previewView = findViewById(R.id.previewView);analysisButton = findViewById(R.id.analysisButton);// 将当前类实现的 OnClickListener 接口设置为 analysisButton 的点击事件监听器,// 以便在单击 analysisButton 时调用类中的 onClick() 方法来处理点击事件。analysisButton.setOnClickListener(this);// 这行代码的作用是获取相机提供者的实例,它是使用 Android CameraX API 实现相机功能的关键对象之一,// 通过它可以获取相机设备、预览用例、图像分析用例等等,从而实现相机应用的各种功能。// 此代码返回一个ListenableFuture对象,用于异步获取相机提供者的实例。processCameraProviderListenableFuture = ProcessCameraProvider.getInstance(this);// 监听摄像头的准备情况。准备好时,该代码块中的 start() 方法将被调用,以便启动相机。processCameraProviderListenableFuture.addListener(() -> {try {ProcessCameraProvider processCameraProvider = processCameraProviderListenableFuture.get();start(processCameraProvider);} catch (ExecutionException | InterruptedException e) {throw new RuntimeException(e);}// 将监听器绑定到主线程,以确保在 UI 上下文中运行该代码块。}, ContextCompat.getMainExecutor(this));}private void start(ProcessCameraProvider processCameraProvider) {// 取消当前已经绑定的摄像头设备,释放它们的资源,以便其他应用或者进程可以使用这些摄像头设备。// 这个方法通常在摄像头应用程序退出或者暂停时调用,以确保摄像头设备不会一直占用系统资源。processCameraProvider.unbindAll();// 创建一个相机选择器对象,并指定选择前置摄像头。CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_FRONT).build();// 创建一个相机预览对象// 并将其与一个 SurfaceView 组件(previewView)的 SurfaceProvider 绑定,从而在该组件上显示相机预览画面。Preview preview = new Preview.Builder().build();preview.setSurfaceProvider(previewView.getSurfaceProvider());// Create an ImageAnalysis objectimageAnalysis = new ImageAnalysis.Builder().setTargetResolution(new Size(1280, 720)).setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).build();// 在 Android 设备上启动相机,并将其与当前生命周期绑定,以便在应用程序暂停或停止时释放相机资源。// 该方法接受一个 `CameraSelector` 对象用于选择相机设备,一个 `Preview` 对象用于显示预览,以及一个 `imageAnalysis` 对象用于分析图像。processCameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis);}@Overridepublic void onClick(View view) {// onClick(View view) 的作用是为按钮或其他视图设置点击事件处理程序。// 当用户点击该视图时,该方法会被调用并执行其中的代码。if (view.getId() == R.id.analysisButton) {if (analysisButton.getText() == "分析") {analysisButton.setText("停止");executeAnalysis();} else {analysisButton.setText("分析");imageAnalysis.clearAnalyzer();}}}private void executeAnalysis() {// Create an ImageAnalysis.Analyzer objectImageAnalysis.Analyzer analyzer = new ImageAnalysis.Analyzer() {@Overridepublic void analyze(@NonNull ImageProxy image) {// Get the width and height of the imageint width = image.getWidth();int height = image.getHeight();int format = image.getFormat();// Log the width and heightLog.d("TAG", "Image analyzed with width: " + width + ", height: " + height + ", format: " + format);// Close the image when doneimage.close();}};// Set the analyzer for the ImageAnalysis objectimageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor(), analyzer);}
}
5. 调试或安装 APK
使用 USB 调试或者 Build 出 APK(Build -> Make Project)然后找到 app-debug.apk 文件进行安装。
注意:由于代码逻辑中没有权限申请部分,需要在安装好后手动开启拍照权限。
由于项目实现的功能只有显示 ImageAnalysis 的日志,因此需要进行真机调试来查看 Logcat 中的日志。
6. 项目完整代码
https://gitee.com/hl0929/camera-video-analysis
7. 后续计划
TODO:增加人脸识别、手势识别、姿态识别等常用只能视觉功能