Android摄像头调用实战:从Camera API到CameraX

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:在Android应用中,实现摄像头调用和保存图片到SD卡是常见的功能需求。本文首先介绍了如何声明和请求相机及存储权限,然后详细说明了使用Camera API的基本流程,包括启动预览、拍照及图片保存。之后,探讨了CameraX库的使用,展示了如何通过简洁的代码实现相同的拍照和预览功能。最后,对比了Camera API和CameraX在实现摄像头调用时的复杂性与易用性,帮助开发者根据实际需求选择合适的实现方式。 android摄像头

1. Android摄像头调用概述

在当今移动应用开发领域,摄像头已成为不可或缺的硬件组件之一。Android平台为开发者提供了强大的Camera API来访问和控制设备的摄像头。从简单的拍照到复杂的图像处理,这些功能都能通过Android的Camera API来实现。

随着Android版本的迭代,摄像头调用的API也在不断地演进。最初的Camera API提供了一系列直接控制硬件的方法,但随着Android 5.0(API 级别 21)的发布,引入了Camera2 API,它支持更多的控制功能和更高的图像质量,同时引入了更复杂的使用模型。在最新的Android 11中,Google推出了CameraX库,为开发者提供了一个更为简单、更加一致的API,用于处理不同设备上摄像头的兼容性问题。

为了充分利用Android摄像头功能,开发者需要了解权限系统、Camera API和CameraX库等核心组件。本文将分章节对这些组件进行详细介绍,帮助开发者在应用中实现高效、稳定的摄像头调用功能。让我们从第一章开始,了解摄像头调用的必要性和基本概念。

2. Android相机权限声明与请求

在Android开发中,访问摄像头是应用中常见的功能之一。但出于安全考虑,Android系统对敏感权限如摄像头访问进行了严格控制。本章节将详细介绍如何在Android应用中声明和请求相机权限,包括权限系统的组成、动态权限请求的流程以及用户授权和拒绝权限时的应对措施。

2.1 Android权限系统简介

2.1.1 权限系统的作用和组成

Android权限系统的作用是确保用户数据和设备安全,防止恶意应用访问用户的私人信息和硬件设备。该系统要求开发者在应用中明确声明所需的权限,并在运行时向用户请求这些权限。

Android权限系统由以下几个部分组成:

  • 普通权限 :这些权限被认为是低风险的,通常与用户隐私相关性不大,系统可以自动授予,不需要用户干预。
  • 危险权限 :涉及到用户的隐私信息或设备的敏感功能,如摄像头、联系人、位置等,需要用户明确授权。
  • 权限组 :相关联的权限被组织到一个权限组中,用户一次性授权一组权限,而非单独授权每个权限。
  • 运行时权限请求 :当应用尝试使用一个危险权限时,如果用户尚未授权该权限,应用必须显示一个对话框来请求权限。

2.1.2 静态权限声明方法

在应用的 AndroidManifest.xml 文件中声明所需的权限是访问特定资源和服务的第一步。对于相机权限,需要添加如下声明:

<uses-permission android:name="android.permission.CAMERA" />

此外,由于摄像头属于危险权限,还需要在应用的运行时请求用户授权,即使在 AndroidManifest.xml 中声明了权限。

2.2 动态权限请求流程

2.2.1 权限请求的时机和条件

动态权限请求的时机一般是在应用尝试使用相机功能时。例如,在用户点击拍照按钮后,应用需要先检查相机权限是否已经被授予。如果未授予,应用应立即向用户请求权限。

权限请求需要满足以下条件:

  • 应用目标SDK版本是Android 6.0(API级别23)或更高。
  • 用户未在系统设置中关闭权限。
  • 权限未被系统自动拒绝。

2.2.2 用户授权后的处理

用户授权后,应用应检查返回的权限状态,并进行相应操作。例如,如果用户授权了相机权限,应用应该立即启动相机功能并显示预览。以下是处理授权结果的伪代码:

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
    // 权限已授权,执行需要权限的操作
    openCamera();
} else {
    // 权限未授权,请求权限
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
}

2.2.3 拒绝权限的应对措施

当用户拒绝权限请求时,应用应当给予用户适当的反馈,并且根据业务需求提供替代方案或解释为什么应用需要这些权限。

用户拒绝权限后,应检查 shouldShowRequestPermissionRationale 方法的返回值来判断用户是选择了"不再询问"还是单次拒绝。如果用户选择了"不再询问",应用可以引导用户到设置页面手动开启权限。伪代码示例:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_CAMERA_PERMISSION) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 用户授权了权限
            openCamera();
        } else {
            // 用户拒绝了权限请求
            if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
                // 用户选择了不再询问,引导到设置页面
                openAppSettings();
            }
            // 可以在这里添加对用户拒绝权限的处理逻辑,例如禁用某些功能或解释为什么需要这些权限
        }
    }
}

AndroidManifest.xml 中加入设置页面的跳转:

<activity android:name="com.example.app.SettingsActivity" />

通过以上步骤,应用可以有效地处理相机权限的声明与请求,确保应用能够合法且安全地访问Android设备上的摄像头资源。

3. Camera API的基本使用方法

3.1 Camera API概述

3.1.1 Camera API的历史和现状

在Android开发的历史长河中,Camera API一直扮演着重要的角色,它从Android平台早期就已经存在,并随着时间的推移不断发展和优化。Camera API作为Android原生的相机接口,允许开发者通过编程来控制和访问Android设备上的摄像头硬件,实现拍照、录像、预览等功能。

随着技术的进步和应用需求的增加,Camera API经历了多次更新和迭代。最开始的Camera API(Camera API 1)在Android 2.3(Gingerbread)版本中引入,它为开发者提供了一套较低级别的接口,允许直接与设备的相机硬件进行交互,但同时也带来了复杂的编程模型,使得开发者需要编写大量的代码来处理相机的各种状态和配置。

为了简化开发者的工作,Android 5.0(Lollipop)引入了Camera2 API,这是一套更为现代、功能更为强大的API集合,提供了更为丰富的控制选项和更高的性能。然而,Camera2 API的复杂性也大大增加,需要开发者具备更深入的相机知识和更高级的编程技巧。

尽管如此,由于许多现有设备可能尚未获得更新或出于兼容性的考虑,原始的Camera API依然有着广泛的使用基础。开发者需要根据自己的需求和目标设备支持情况,选择合适的API来实现功能。

3.1.2 Camera API的架构和关键类

Camera API的整体架构是围绕Camera对象建立的,该对象代表了与特定相机硬件的连接。通过Camera API,开发者可以设置不同的参数来控制相机的行为,例如对焦、曝光、白平衡等。

主要的类包括: - Camera :提供了操作摄像头的方法和状态信息。 - Camera.Parameters :包含了一系列参数,用于控制摄像头的硬件特性,如图片大小、缩放比例、预览尺寸等。 - Camera.PictureCallback :用于处理拍照完成后的回调事件。 - Camera.AutoFocusCallback :用于处理自动对焦完成后的回调事件。

要使用Camera API,开发者首先需要检查设备上摄像头的数量,并通过 Camera.open() 方法打开摄像头设备。通常,摄像头设备分为前置和后置,具体的设备编号需要根据实际设备情况查询。打开摄像头后,开发者还需要设置摄像头参数,并通过 Camera.Parameters 类来配置它们。

3.2 Camera API的初始化与配置

3.2.1 创建Camera实例

在Android应用中,初始化Camera通常从尝试打开设备的第一个后置摄像头开始。以下是创建Camera实例的基础代码:

Camera camera = null;
try {
    camera = Camera.open(); // 尝试获取相机实例
    if (camera == null) {
        throw new RuntimeException("相机不可用");
    }
} catch (RuntimeException e) {
    // 相机不可用时的处理逻辑
}

在这段代码中, Camera.open() 方法尝试连接到设备上的第一个后置摄像头。如果摄像头被其他应用占用或不可用,该方法将返回null,并抛出一个RuntimeException异常。因此,我们需要用try-catch语句来捕获这个异常,并提供相应的错误处理逻辑。

3.2.2 相机参数的设置和优化

一旦我们有了Camera实例,就可以对摄像头进行进一步的配置。这包括设置预览的尺寸、图片大小、焦距、对焦模式等参数。以下是一些基本的参数设置示例:

Camera.Parameters parameters = camera.getParameters(); // 获取当前相机参数
Camera.Size size = parameters.getSupportedPreviewSizes().get(0); // 获取支持的预览尺寸列表,并取第一个作为示例
parameters.setPreviewSize(size.width, size.height); // 设置预览尺寸

Camera.Size picSize = parameters.getSupportedPictureSizes().get(0); // 获取支持的图片尺寸列表,并取第一个作为示例
parameters.setPictureSize(picSize.width, picSize.height); // 设置图片大小

parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // 设置自动对焦模式

camera.setParameters(parameters); // 应用设置的参数

上面的代码展示了如何获取并设置摄像头参数。 getSupportedPreviewSizes() getSupportedPictureSizes() 方法分别返回支持的预览和图片尺寸列表。通常情况下,开发者会根据需求选择列表中的第一个尺寸作为默认值,或者设计一个用户界面让用户自行选择。

这里还需要注意的是, setParameters() 方法可能需要在Camera打开后和预览开始前调用,以确保参数的变更能够被正确应用。

为了确保用户得到最佳的拍照体验,开发者还需要根据应用需求和设备性能进行细致的参数优化。例如,为了提高预览性能,可以选择较低分辨率的预览尺寸;为了获得高质量的图片,则可以选择较高的图片尺寸。同时,开发者还需要注意合理使用摄像头的资源,避免因为过度消耗而导致应用性能下降。

在调整完参数后,开发者还需要检查这些设置是否真的被应用,以及设备是否支持这些设置。这是因为并非所有的参数设置在所有设备上都可用。通过检查返回的 Camera.Parameters 对象,开发者可以验证参数设置是否成功。

上述步骤为Camera API的基础使用方法。要实现更高级的图像处理和控制,开发者还需要深入了解Camera API提供的更多功能和参数选项。

4. 摄像头预览启动与停止

随着移动设备的发展,摄像头已成为用户与数字世界互动的重要接口之一。在Android平台上,实现摄像头的预览功能是构建交互式应用的基础。本章节将深入探讨如何使用Android Camera API来启动和停止摄像头预览,并对预览过程中的资源管理和控制进行说明。

4.1 预览功能的实现

摄像头预览的实现过程涉及到多个组件和步骤,包括SurfaceView和TextureView的选择与使用,以及预览回调的处理和图像显示。

4.1.1 SurfaceView和TextureView的选择与使用

在Android开发中, SurfaceView TextureView 都可以用来显示视频流,但它们在功能和性能上有着明显的区别。

SurfaceView

SurfaceView 是一种可以在独立线程中绘制的视图。它具有以下特点:

  • 硬件加速渲染:在许多设备上, SurfaceView 提供了硬件加速的渲染能力,可以有效地减少CPU的负担。
  • 只能显示: SurfaceView 是不可交互的,它显示的内容位于另一个窗口层,不会对用户输入事件产生影响。
  • 适合视频流:在视频流场景中, SurfaceView 因为其高效性而被推荐使用。
// 示例代码:创建一个SurfaceView用于摄像头预览
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;
        // 获取SurfaceHolder对象并添加回调
        mHolder = getHolder();
        mHolder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // 在这里尝试连接摄像头预览
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            // 处理错误
        }
    }

    // SurfaceHolder.Callback接口其他方法的实现...
}
TextureView

SurfaceView 不同, TextureView 允许在应用的视图层级中显示内容,可以实现透明度和动画效果。

  • 软件渲染: TextureView 主要通过软件渲染,可能对CPU造成较大负担。
  • 可交互: TextureView 是可交互的,可以接收用户的输入事件。
  • 动态变化:支持大小和位置的动态变化。
// 示例代码:创建一个TextureView用于摄像头预览
public class CameraTextureView extends TextureView {
    private Camera mCamera;

    public CameraTextureView(Context context) {
        super(context);
        // TextureView的初始化
    }

    public void setCamera(Camera camera) {
        mCamera = camera;
        // 设置为可渲染
        setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
                // 在这里尝试连接摄像头预览
                mCamera.setPreviewTexture(surface);
                mCamera.startPreview();
            }
            // 其他回调方法的实现...
        });
    }
    // 其他TextureView相关方法的实现...
}

4.1.2 预览回调的处理和图像显示

摄像头预览流必须通过某种方式输出到用户界面上,这通常通过回调函数来完成。

在Camera API中,可以通过 Camera.PreviewCallback 接口来处理每一帧的预览数据。以下是一个示例代码,展示了如何在回调中处理图像数据:

// 设置预览回调
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        // 在这里处理图像数据
        // 'data'数组包含了当前预览帧的图像数据
    }
});

onPreviewFrame 方法会在预览帧数据可用时被调用,开发者可以在此方法中处理每一帧的图像数据。可以进行图像处理,例如调整大小、旋转、滤镜等,然后将处理后的图像数据显示在 SurfaceView TextureView 上。

4.2 预览控制与资源管理

在摄像头预览的整个生命周期中,合理的资源管理和控制对于提升用户体验和性能至关重要。

4.2.1 预览的启动与停止流程

为了确保摄像头资源得到恰当的管理,需要在启动预览之前检查摄像头是否可用,以及在不需要时及时停止预览并释放资源。

// 启动预览
mCamera.startPreview();

// 停止预览
mCamera.stopPreview();

启动预览时,应该确保摄像头已经被正确地打开,并且预览的回调已经设置好。停止预览时,则要确保任何相关的回调被清除,以避免内存泄漏或错误使用无效的摄像头资源。

4.2.2 相机资源的释放和状态保存

当应用程序不再需要摄像头资源时,必须确保摄像头资源被完全释放,并且其状态得到妥善保存。

// 释放摄像头资源
mCamera.release();

在活动(Activity)或片段(Fragment)的 onPause() onStop() 方法中调用 mCamera.release() 是一种常见的做法。这样可以确保摄像头资源在不需要时不会被无谓地占用。另外,应该在适当的地方保存摄像头的状态,以便在活动或片段恢复时能够重新配置摄像头并继续预览。

通过本章节的介绍,我们深入理解了如何使用Camera API实现摄像头预览功能,并通过代码示例和逻辑分析,详细说明了使用SurfaceView和TextureView实现摄像头图像显示的方法,以及预览的控制和资源管理策略。这些知识点对于开发人员在进行Android应用开发时,能够构建出更加高效、稳定的摄像头预览功能至关重要。

5. 使用Camera API进行拍照及图片保存流程

5.1 拍照功能的触发和处理

5.1.1 拍照按钮的监听与触发

在Android应用中,用户通常通过界面上的一个按钮来触发拍照功能。监听这个按钮的动作是启动拍照流程的第一步。在Camera API中,拍照按钮的监听与触发可以通过设置一个 OnClickListener 来实现。以下是具体的实现步骤:

  1. 在布局文件中定义一个按钮(例如 button_capture )。
  2. 在Activity中找到这个按钮,并为其设置一个 OnClickListener
  3. 在点击事件的回调方法中,调用拍照方法。
Button captureButton = findViewById(R.id.button_capture);
captureButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (mCamera != null) {
            // Call takePicture method to capture photo.
            mCamera.takePicture(shutterCallback, rawCallback, jpegCallback);
        }
    }
});

在这个例子中, takePicture 方法需要传入三个回调函数: shutterCallback rawCallback jpegCallback ,分别用于处理快门声、原始图像数据和压缩后的JPEG图像数据。

5.1.2 拍照参数的配置和优化

在实际应用中,仅仅触发拍照功能是不够的。为了获得更好的拍照效果,需要对拍照参数进行适当的配置和优化。例如,可以通过设置不同的图像大小、JPEG质量、白平衡、对焦模式等来满足特定的拍摄需求。以下是一个设置拍照参数的示例:

Camera.Parameters params = mCamera.getParameters();
// 设置图像尺寸
params.setPictureSize(1920, 1080);
// 设置JPEG质量
params.setJpegQuality(90);
// 设置闪光灯模式
params.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
// 设置白平衡
params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
// 应用参数设置
mCamera.setParameters(params);

上述代码中的 pictureSize 参数应根据实际需求选择合适的分辨率。同时, jpegQuality 的值范围是0到100,数值越高,图片质量越好,但文件体积也越大。

5.2 图片的保存与管理

5.2.1 图片数据的捕获和存储

拍照功能触发后,通过回调函数可以获得拍照后的图像数据。通常情况下,我们需要将这些数据保存为文件,以便后续使用。JPEG图像数据一般保存为 .jpg 文件,而原始图像数据可能需要转换为其他格式,例如 .raw 。以下是将JPEG数据保存为文件的示例:

Camera.PictureCallback jpegCallback = new Camera.PictureCallback() {
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        // 将图像数据写入到文件
        FileOutputStream outStream = null;
        try {
            File photoFile = createImageFile();
            outStream = new FileOutputStream(photoFile);
            outStream.write(data);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outStream != null) {
                try {
                    outStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            // 重新启动预览
            mCamera.startPreview();
        }
    }
};

private File createImageFile() throws IOException {
    // 创建一个文件名以保存图片
    String imageFileName = "JPEG_" + System.currentTimeMillis() + ".jpg";
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    File image = File.createTempFile(
            imageFileName,  /* 前缀 */
            ".jpg",         /* 扩展名 */
            storageDir      /* 目录 */
    );
    // 保存文件路径,用于返回结果
    currentPhotoPath = image.getAbsolutePath();
    return image;
}

在这个例子中,首先调用 createImageFile 方法创建一个用于保存JPEG图片的文件,然后在 onPictureTaken 回调中,将图像数据写入到这个文件中。

5.2.2 多格式支持与图片质量控制

在不同场景下,可能需要支持图片的多种格式,以便提供更灵活的图像处理选项。Camera API允许开发者获取原始图像数据,并将其保存为RAW格式或其他格式,从而提供更高质量的图像源。同时,需要对图片质量进行控制,以保证文件体积不会过大。

为了支持多格式保存,可以在拍照回调中同时处理JPEG和RAW数据,并根据用户的需要将它们保存到不同的文件中。对于图片质量控制,可以通过调整JPEG质量参数来平衡图片的大小和质量。需要注意的是,高JPEG质量可能导致较大的文件体积,因此需要在保存文件之前进行适当的文件大小检查或压缩处理。

6. CameraX库的优势与使用示例

6.1 CameraX库概述

6.1.1 CameraX的设计目标和优势

CameraX 是一个由 Google 推出的相机库,旨在简化 Android 应用程序中相机的使用。它针对不同的 Android 版本和设备进行了广泛的兼容性测试,让开发者能够专注于相机功能的实现,而不是处理复杂的相机 API 调用和设备兼容性问题。CameraX 的设计目标是让开发者能够通过简单的 API 实现常见的相机用例,同时保持足够的灵活性来实现更高级的定制。

CameraX 的优势包括:

  • 简化性 :抽象了许多复杂性,提供了一个高层次的 API 来处理图像的捕获。
  • 兼容性 :支持广泛的设备,并且会自动处理不同 Android 版本之间的 API 差异。
  • 模块化 :将相机用例分解成可配置的预览、图像分析和图像捕获等模块,易于理解和实现。
  • 生命周期感知 :与 Android 生命周期紧密集成,自动管理相机资源,减少内存泄漏和错误使用相机的风险。

6.1.2 CameraX与Camera API的对比

CameraX 与传统的 Camera API 相比,提供了一种更加现代化和简洁的方式来处理相机任务。Camera API 通常需要开发者手动管理大量的状态和回调,而 CameraX 通过其生命周期感知的架构将这些复杂性隐藏起来。Camera API 的使用通常涉及到以下几个步骤:

  • 实例化 Camera 对象 :获取相机实例,选择合适的相机 ID。
  • 配置 Camera.Parameters :设置预览大小、对焦模式等参数。
  • 创建预览显示 Surface :设置 SurfaceTexture 或 SurfaceView 供相机显示。
  • 处理 Camera.Callbacks :管理如预览帧回调和错误通知。

与之相比,CameraX 的主要优势是它利用了 Jetpack 的组件,如 ViewModel 和 LiveData,来简化相机操作,并使得代码更加模块化和可重用。通过使用 CameraX,开发者可以少写甚至不写状态管理和错误处理的代码,从而更快地实现功能。

6.2 CameraX的快速上手与高级功能

6.2.1 CameraX的基本使用方法

要使用 CameraX,首先需要在项目的 build.gradle 文件中添加 CameraX 的依赖项:

dependencies {
    def camerax_version = "1.0.0-rc01"
    implementation "androidx.camera:camera-camera2:$camerax_version"
    implementation "androidx.camera:camera-lifecycle:$camerax_version"
    implementation "androidx.camera:camera-view:$camerax_version"
}

然后,可以创建一个 CameraXConfig 对象,并在应用程序中初始化 CameraX:

val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
cameraProviderFuture.addListener(Runnable {
    val cameraProvider = cameraProviderFuture.get()
    bindPreview(cameraProvider)
}, ContextCompat.getMainExecutor(context))

其中 bindPreview 是一个自定义的函数,用于绑定预览和相机实例。这是一个非常基本的使用方法,CameraX 还提供了许多其他的预定义用例,例如图像分析和图像捕获,它们允许开发者在不同的用例中重用大部分代码。

6.2.2 CameraX的进阶功能和定制选项

CameraX 不仅提供了快速上手的简单用例,还允许开发者通过自定义配置来满足特定需求。例如,可以指定图像的保存格式,调整缩放和裁剪控制,以及实现更复杂的图像处理逻辑。

例如,使用 ImageAnalysis 用例进行实时图像分析的代码如下:

val imageAnalysis = ImageAnalysis.Builder()
    .build()
    .also {
        it.setAnalyzer(executor, ImageAnalysis.Analyzer { imageProxy ->
            val rotationDegrees = imageProxy.imageInfo.rotationDegrees
            // 这里进行图像分析的逻辑
        })
    }

通过定制 ImageAnalysis.Builder ,可以设置分析的分辨率,帧率等属性。此外,还可以结合使用 CameraSelector 来选择不同的相机硬件(前置或后置)。

通过这些进阶功能,CameraX 不仅能够帮助开发者快速实现基本的相机功能,还能够支持更高级的图像处理和定制需求,让应用的相机功能更加强大和灵活。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:在Android应用中,实现摄像头调用和保存图片到SD卡是常见的功能需求。本文首先介绍了如何声明和请求相机及存储权限,然后详细说明了使用Camera API的基本流程,包括启动预览、拍照及图片保存。之后,探讨了CameraX库的使用,展示了如何通过简洁的代码实现相同的拍照和预览功能。最后,对比了Camera API和CameraX在实现摄像头调用时的复杂性与易用性,帮助开发者根据实际需求选择合适的实现方式。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值