编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • Android提升进阶

    • 库的解读

    • 专栏博客

    • 智能硬件

      • README
      • 实体卡开发和实践
      • 继电器和韦根协议
      • 设备串口通信实践
      • USB开发设计实践
      • UVC相机设计实践
      • 原生相机采集图片库
        • 01.基础概念说明
          • 1.1 相机打开和采集
          • 1.2 CameraManager说明
          • 1.3 CameraDevice说明
          • 1.4 ImagerReader说明
        • 02.打开相机的步骤
          • 2.1 如何打开相机
          • 2.2 获取设备相机
          • 2.3 打开相机后采集
          • 2.4 获取采集图像
        • 03.图像采集编解码
          • 3.1 图像采集数据
          • 3.2 YUV格式理解
          • 3.2.1 YUV444采样
          • 3.2.2 YUV422采样
          • 3.2 图像色彩编码
          • 3.3 图像编码转化
          • 3.4 YUV转RGB编码
          • 3.5 RGB转YUV编码
        • 04.遇到的坑分析
          • 4.1 辨别硬件支持等级
        • 05.广角采集的步骤
          • 5.3 参考博客连接
      • 蓝牙开发业务实践
  • iOS开发和进阶

  • Web开发和进阶

  • Linux应用开发

  • Apps
  • Android提升进阶
  • 智能硬件
杨充
2025-06-30
目录

原生相机采集图片库

# 相机打开和采集库

# 目录介绍

  • 01.基础概念的说明
    • 1.1 相机打开和采集
    • 1.2 CameraManager说明
    • 1.3 CameraDevice说明
    • 1.4 ImagerReader说明
  • 02.打开相机的步骤
    • 2.1 如何打开相机
    • 2.2 获取设备相机
    • 2.3 打开相机后采集
    • 2.4 获取采集图像
  • 03.图像采集编解码
    • 3.1 图像采集数据
    • 3.2 YUV格式理解
    • 3.3 图像色彩编码
    • 3.4 YUV编码转化
    • 3.5 YUV转RGB编码
    • 3.6 RGB转YUV编码
  • 05.广角采集的步骤

# 01.基础概念说明

# 1.1 相机打开和采集

  • 打开相机和采集涉及的类
    • CameraManager 用于打开相机和检测相关的功能
    • CameraDevice 打开相机后,相机的实体对象,用于操作相机捕获,相机回调等操作
    • ImagerReader 专门做图像读取采集的,最终捕获图像是Image格式
  • 相机图像渲染涉及的类
    • SurfaceView或TextureView。相机预览图像发送到SurfaceView或TextureView渲染出图像

# 1.2 CameraManager说明

  • CameraManager类概述
    • CameraManager是用于检测、表征和连接到 CameraDevices 的系统服务管理器。专门用于 检测 和 打开相机,以及 获取相机设备特性。
  • CameraManager 是一个负责查询和建立相机连接的系统服务,它的功能不多,这里列出几个 CameraManager 的关键功能:
    • 1)、将相机信息封装到 Camera Characteristics 中,并提获取 CameraCharacteristics 实例的方式。
    • 2)、根据指定的相机 ID 打开相机设备(openCamera)。
    • 3)、提供将闪光灯设置成手电筒模式的快捷方式。
  • AvailabilityCallback抽象类
    • 注册相机设备变为可用或不可打开的回调。
    • 当不再使用相机或连接新的可拆卸相机时,相机将变得可用。 当某些应用程序或服务开始使用相机时,或者当可移动相机断开连接时,它们将变得不可用。
  • TorchCallback抽象类
    • 相机闪光灯模式变得不可用、禁用或启用的回调。
    • 当手电筒模式处于禁用或启用状态时,才可通过 setTorchMode 设置。扩展此回调并将子类的实例传递给 registerTorchCallback 以收到此类状态更改的通知。
  • String[] getCameraIdList()
    • 获取当前连接的相机设备列表,这个 id 通常都是从 0 开始并依次递增的。对于一般的手机而言:
    • 后置摄像头一般为 “0”,常量值为 CameraCharacteristics.LENS_FACING_FRONT;
    • 前置摄像头一般为 “1”,常量值为 CameraCharacteristics.LENS_FACING_BACK。
  • CameraCharacteristics getCameraCharacteristics(String cameraId)
    • 根据 cameraId 获取对应相机设备的特征。返回一个 CameraCharacteristics,类比于旧 API 中的 Camera.Parameter 类,里面封装了相机设备固有的所有属性功能。
  • void openCamera(String cameraId, final CameraDevice.StateCallback callback, Handler handler)
    • 打开指定的相机设备,该方法使用当前进程 uid 继续调用 openCameraForUid(cameraId, callback, handler, USE_CALLING_UID) 方法。
    • handler : 指定回调执行的线程。传 null 时默认使用当前线程的 Looper,我们通常创建一个后台线程来处理。

# 1.3 CameraDevice说明

  • CameraDevice类概述
    • CameraDevice 类表示连接到 Android 设备的单个相机,允许以高帧速率对图像捕获和后处理进行细粒度控制。
  • 如何获取CameraDevice实例
    • 通过 CameraManager 的 openCamera() 方法打开相机,在 CameraDevice.StateCallback 的 onOpened(CameraDevice camera) 方法中可获得 CameraDevice 的实例。
  • 内部类CameraDevice.StateCallback说明
    • 当相机状态发生变化时,会调用该类相应的回调方法。
    • onOpened,当相机成功打开时回调该方法,接下来可以执行创建预览的操作
    • onDisconnected,当相机断开连接时回调该方法,应该在此执行释放相机的操作
    • onError,当相机打开失败时,应该在此执行释放相机的操作
    • onClosed,当相机关闭时回调该方法,这个方法可以不用实现
  • CaptureRequest.Builder createCaptureRequest(int templateType)
    • 使用指定模板创建一个 CaptureRequest.Builder 用于新的捕获请求构建。
  • void createCaptureSession(List outputs, CameraCaptureSession.StateCallback callback, Handler handler)
    • 使用一个指定的 Surface 输出列表创建一个相机捕捉会话

# 1.4 ImagerReader说明

  • ImagerReader类介绍
    • 简单来说就是图像读取器。ImageReader可以直接获取屏幕渲染数据,得到屏幕数据是image格式。
    • 图像数据封装在Image对象中,可以同时访问多个此类对象,最多可达 maxImages构造函数参数指定的数量。
    • 通过 ImageReader 发送到 ImageReader 的新图像Surface将排队,直到通过acquireLatestImage() 或acquireNextImage()调用访问。
    • 由于内存限制,如果 ImageReader 没有以等于生产速率的速率获取和释放图像,则图像源最终将在尝试渲染到 Surface 时停止或丢弃图像。
  • 一些核心的API说明
    • setOnImageAvailableListener,注册一个侦听器,以便在 ImageReader 中提供新图像时调用该侦听器。
    • newInstance,通过工厂方法 newInstance函数或构建器模式ImageReader.Builder并使用。
    • getSurface,获取一个Surface可用于Images为此 生产的ImageReader。Surface用于各种 API 的绘图目标。

# 02.打开相机的步骤

# 2.1 如何打开相机

  • 如何打开相机操作
    • 第一种方式:使用最原始方式,通过intent打开原生相机。
    • 第二种方式:通过CameraManager打开(openCamera)指定的相机设备。
  • 打开相机后如何如何判断相机可用与不可用
    • 通过CameraManager注册相机设备监听,具体的api是:registerAvailabilityCallback
    • onCameraAvailable。相机已经可以使用,并且回调可以使用相机的ID
    • onCameraUnavailable。之前可用的相机已无法使用,如果应用程序具有当前已断开连接的相机的活动 CameraDevice 实例,则该应用程序将收到断开连接错误。
  • 如何判断打开相机成功或异常
    • 具体可以看:CameraDevice.StateCallback 执行的回调。打开相机成功会回调到onOpened,打开相机异常会回调onError。

# 2.2 获取设备相机

  • 使用CameraManager对象调用getCameraIdList()
    • 获取当前连接的相机设备列表,这个 id 通常都是从 0 开始并依次递增的。对于一般的手机而言:
    • 后置摄像头一般为 “0”,常量值为 CameraCharacteristics.LENS_FACING_FRONT;
    • 前置摄像头一般为 “1”,常量值为 CameraCharacteristics.LENS_FACING_BACK。
  • 有些相机有多个,比如说四五个摄像头
    • 若要打开指定的摄像头,则必须先知道该摄像头的id才可以。

# 2.3 打开相机后采集

  • 在打开相机成功之后操作
    • 在openCamera打开相机后,会执行onOpened回调,这表明打开相机成功了。然后拿到当前相机对象:CameraDevice
  • 理解采集的内容是什么
    • 相机打开后,捕获的是一个个画面。那么这个时候,采集数据,是针对这种一个个画面,进行相机捕捉会话!
    • 具体则是使用:cameraDevice.createCaptureSession(surfaces, stateCallback, null);

# 2.4 获取采集图像

  • 第一步:创建图像读取器
    • 通过ImageReader.newInstance创建图像采集器,可以指定宽高和格式。
  • 第二步:添加图像读取器监听
    • 调用setOnImageAvailableListener,注册一个侦听器,以便在 ImageReader 中提供新图像时调用该侦听器。如果有图像,则获取图像image对象。
  • 第三步:绑定图像读取器surface到相机上
    • 获取ImageReader的Surface,然后添加到CameraDevice配置的Surface输出列表,最后使用相机创建一个捕捉会话。
  • 第四步:异常情况处理
    • 如果打开相机异常,或者相机断开连接,则关闭图像读取器。

# 03.图像采集编解码

# 3.1 图像采集数据

相机采集的数据一般是什么格式的?

  1. 在绝大多数摄像头所采用的是免驱摄像头,一般有这几种传输格式,YUV和MJPG和RGB。
  2. 一般视频采集芯片采集到数据都是按照YUV格式输出,包括很多现在很多的相机。

# 3.2 YUV格式理解

YUV也是一种颜色空间,一种编码格式,当初是为了兼容黑白电视和彩色电视机设计的。Y、U、V分别占用8位

  • Y 表示明亮度(Luminance、Luma),也就是灰阶值。
  • U、V 表示色度(Chrominance 或 Chroma),描述的是色调和饱和度
  • YUV图片查看器:http://datahammer.de/

YUV采样格式有3种:

  1. YUV444 采样: 每1个Y分量对应一组UV分量,一个像素共占用(8+8+8)bit = 3byte
  2. YUV422 采样: 每2个Y分量对应一组UV分量,一个像素共占用(8+81/2 + 81/2)bit = 2byte
  3. YUV420 采样: 每4个Y分量对应一组UV分量,一个像素共占用(8+81/4+81/4) = 1.5byte

# 3.2.1 YUV444采样

四个像素为:

[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]
1

采样的码流为:

Y0 U0 V0 Y1 U1 V1 Y2 U2 V2 Y3 U3 V3
1

映射出的像素点为:

[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]
1

一张 1920 * 1280 大小的图片,如果按照YUV444采样,其存储占用共:(192012808 + 192012808 + 192012808)/8/1024/1024 = 7.03M

# 3.2.2 YUV422采样

四个像素为:

[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]

1
2

采样的码流为:

Y0 U0 Y1 V1 Y2 U2 Y3 U3
1

映射出的像素点为:

[Y0 U0 V1]、[Y1 U0 V1]、[Y2 U2 V3]、[Y3 U2 V3]
1

一张 1920 * 1280 大小的图片,如果按照YUV444采样,其存储占用共:(192012808 + 1920128081/2 + 1920128081/2)/8/1024/1024 = 4.68M

# 3.2 图像色彩编码

  • 常用图像颜色编码格式
    • NV21、NV12、YV12、RGB、YUV、RGBA、RGBX8888都是常见的图像颜色编码格式,它们之间的主要区别在于色彩空间和数据排列方式。
  • NV21
    • NV21是Android系统使用的一种图像颜色编码格式,它采用的是YUV 4:2:0的采样方式,意味着垂直方向上每两个像素采样一次,水平方向上每个像素采样两次。
    • NV21的Y分量是亮度信息,V和U分量是色度信息(分别代表饱和度和色调)。这种格式主要应用于前置摄像头和Android的Camera API。
  • NV12:
    • NV12是一种用于视频编解码的颜色编码格式,它同样采用了YUV 4:2:0的采样方式。NV12的Y分量是亮度信息,V和U分量也是色度信息。
    • 不同的是,与NV21不同的是,NV12的Y、V、U三个分量分别采用了不同的采样率,即垂直方向上每两个像素采样一次,水平方向上每隔一个像素采样一次。
  • YV12:
    • YV12是一种用于视频编解码的颜色编码格式。它同样采用了YUV 4:2:0的采样方式。YV12的Y分量是亮度信息,V和U分量也是色度信息。
    • 与NV12不同的是,YV12的V和U分量交换了位置。这种格式主要应用于软件编解码器,如FFmpeg。
  • RGB:
    • RGB是一种常见的颜色编码格式,它采用红、绿、蓝三种颜色组成图像。RGB的R、G、B三个分量分别表示红色、绿色和蓝色的强度。
    • RGB图像中的每个像素都需要三个值来表示颜色,因此它的数据排列方式是按照红、绿、蓝的顺序排列。

# 3.3 图像编码转化

  • 了解YUV概念是什么意思
    • 要做的yuv数据处理,无非就是针对各种图像格式下yuv数据(byte[])的转换、调整。
    • NV21:安卓的模式。存储顺序是先存Y,再存U,再VU交替存储,格式为:YYYYVUVUVU。
    • https://blog.csdn.net/haiping1224746757/article/details/109815884
    // NV21: YYYYVUVU NV12: YYYYUVUV
    public static byte[] ImageToNV21Byte(Image image) {
        Image.Plane[] planes = image.getPlanes();
        int width = image.getWidth();
        int height = image.getHeight();
        byte[] data = new byte[width * height * 3 / 2];
        //planes[0] 总是Y ,planes[1] 总是U(Cb), planes[2]总是V(Cr)。
        ByteBuffer yBuffer = planes[0].getBuffer();
        ByteBuffer vuBuffer = planes[2].getBuffer();
        int ySize = yBuffer.remaining();
        int vuSize = vuBuffer.remaining();
        yBuffer.get(data, 0, ySize);
        vuBuffer.get(data, ySize, vuSize);
        return data;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
  • 如何区分NV12和NV21?
    • plane[0] + plane[1] 可得NV12。
    • plane[0] + plane[2] 可得NV21

# 3.4 YUV转RGB编码

  • 利用摄像流实时做画面图像的分析,并做出许多有用的应用。
    • 比如人脸识别,条码识别,特定图像替换等等,不过大多数图像处理软件在处理时是需要RGB格式的图像,而默认的视频流是压缩的YUV格式。
    • Android下是YUV420SP,虽然可以在程序中修改,但是修改后好像不起作用,也就是说只能得到编码为YUV420SP的视频流,这就需要把YUV420SP的视频流转换成RGB格式的图像,用于图像识别。

# 3.5 RGB转YUV编码

# 04.遇到的坑分析

# 4.1 辨别硬件支持等级

  • 在 Camera2 中,相机设备支持的硬件等级有
    • LEVEL_3 > FULL > LIMIT > LEGACY
    • 对于大多数的Android设备而言,都会支持到 FULL 或 LIMIT。当支持到 FULL 等级的相机设备,将拥有比旧 API 强大的新特性,如 30fps 全高清连拍,帧之间的手动设置,RAW 格式的图片拍摄,快门零延迟以及视频速拍等,否则和旧 API 功能差别不大。
  • 如何获取相机的特性
    • 通过 CameraCharacteristics 类获取相机设备的特性,包括硬件等级的支持等级。

# 05.广角采集的步骤

  • https://blog.csdn.net/Gaga246/article/details/128654820

# 5.3 参考博客连接

  • Android Camera之createCaptureSession()
    • https://blog.csdn.net/weixin_42463482/article/details/119858829
  • 相机Camera官方文档
    • https://developer.android.google.cn/reference/android/hardware/camera2/package-summary
  • Android音视频——Libyuv使用实战
    • https://zhuanlan.zhihu.com/p/666127328
    • https://blog.csdn.net/weekend_y45/article/details/125079916
上次更新: 2026/06/10, 11:13:41
UVC相机设计实践
蓝牙开发业务实践

← UVC相机设计实践 蓝牙开发业务实践→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式