查看: 165|回复: 3

HarmonyOS Camera Kit 深度器件与逻辑相机解构实战

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
在专业影像类应用的开发中,测距仪、AR引擎、专业相机等场景往往需要的不只是前后置摄像头和分辨率信息。机器视觉与三维重建算法依赖高精度的物理光学参数:镜头实际焦距是多少、广角畸变如何校正、传感器物理尺寸是多大。HarmonyOS 6.1.1(API 24)之前的版本中,这些微观硬件参数通常隐藏在设备底层的硬件抽象层(HAL),应用层难以触及。Camera Kit 在本次更新中对 CameraDevice 接口做了大幅扩充,开放了十余项光学参数与传感器物理信息,并原生支持逻辑摄像头(Logical Camera)的管理与解构。开发者现在可以清楚地知道,一个看起来是广角的镜头,底层实际上是由几颗独立物理镜头协同工作组成的。

一、核心 API 变化

这次更新集中在 camera.CameraDevice 数据模型上。无论通过 cameraManager.getSupportedCameras() 获取设备列表,还是从 Session 中提取设备信息,只要运行环境在 API 24 及以上,这些新增字段都会挂载到 CameraDevice 上。需要特别注意的是,所有新增字段均为可选字段,老机型或底层驱动未上报时可能返回 undefined。

二、光学参数与传感器参数

光学参数方面,CameraDevice 新增了以下字段。

lensEquivalentFocalLength(Array):等效焦距,对应 35mm 画幅的换算值,用于摄影视角的粗略估算。

lensFocalLength(number):镜头实际物理焦距。

minimumFocusDistance(number):最小对焦距离,是微距摄影或测距阈值判断的核心依据。

lensDistortion(Array):镜头畸变参数数组,通常包含 k1、k2、p1、p2 等系数,供 AR 视觉算法做图像畸变校正。

lensIntrinsicCalibration(Array):镜头内参标定矩阵,用于计算相机空间到像素空间的投影关系。

传感器微观参数方面,新增了三个字段。

sensorPhysicalSize(Array):传感器物理尺寸,单位为毫米,包含宽和高。

sensorPixelArraySize(Array):传感器真实像素阵列大小,通常比实际出图分辨率略大,因为其中包含边缘裁剪区域。

sensorColorFilterArrangement(enum):拜耳阵列滤光片排列方式,如 RGGB,决定了底层 RAW 数据的色彩解算方案。

三、逻辑摄像头解构

逻辑摄像头是 HarmonyOS 相机框架中一个重要概念。当手机进行无缝变焦时,系统会在超广角与主摄之间协同调度,对外呈现为一个统一的摄像头,这个摄像头就是逻辑相机。CameraDevice 通过两个字段来支持逻辑相机的解构。

isLogicalCamera(boolean):标记当前相机是否由多颗物理镜头融合而来。

constituentCameraDevices(Array<CameraDevice>):仅在 isLogicalCamera 为 true 时存在,返回组成该逻辑相机的物理摄像头列表及各自的物理参数。

四、实战演示

为了验证这些新增能力,可以创建一个深度器件参数勘测页面,通过列表形式展示相机阵列及光学数据。示例工程在原有 Camera Kit 系列 Demo 基础上,新增了 CameraDeviceDemo.ets 页面作为深度器件与逻辑相机解构的演示入口,并在 main_pages.json 中完成路由注册。

下面的示例代码展示了如何在 ArkTS 中模拟拉取一组包含逻辑相机与深度内参信息的复杂相机组合,重点演示 UI 渲染逻辑。
  1. import { router } from '@kit.ArkUI';
  2. interface MockConstituentCamera {
  3.     cameraId: string;
  4.     lensFocalLength: number;
  5.     minimumFocusDistance: number;
  6.     lensDistortion?: number[];
  7.     sensorPhysicalSize: number[];
  8.     sensorPixelArraySize: number[];
  9. }
  10. interface MockCameraDevice {
  11.     cameraId: string;
  12.     cameraType: string;
  13.     isLogicalCamera: boolean;
  14.     lensEquivalentFocalLength: number[];
  15.     constituentCameraDevices: MockConstituentCamera[];
  16. }
  17. @Entry
  18. @Component
  19. struct CameraDeviceDemo {
  20.     @State logs: string[] = [];
  21.    
  22.     private appendLog(msg: string): void {
  23.         let now = new Date();
  24.         let timeStr = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}.${now.getMilliseconds()}`;
  25.         this.logs.unshift(`[${timeStr}] ${msg}`);
  26.     }
  27.    
  28.     scanCameraDevices(): void {
  29.         this.appendLog('正在向 CameraManager 请求 Supported Cameras...');
  30.         // 真实业务中: let cameras = cameraManager.getSupportedCameras();
  31.         // 这里构建强仿真的数据结构用于演示 UI 渲染逻辑
  32.         let mockCameras: MockCameraDevice[] = [
  33.             {
  34.                 cameraId: 'LOGICAL_BACK_01',
  35.                 cameraType: 'CAMERA_TYPE_WIDE_ANGLE',
  36.                 isLogicalCamera: true,
  37.                 lensEquivalentFocalLength: [24.0, 70.0],
  38.                 constituentCameraDevices: [
  39.                     {
  40.                         cameraId: 'PHYSICAL_BACK_MAIN',
  41.                         lensFocalLength: 5.4,
  42.                         minimumFocusDistance: 0.1,
  43.                         lensDistortion: [0.12, -0.05, 0.001, 0.002, 0.0],
  44.                         sensorPhysicalSize: [8.0, 6.0],
  45.                         sensorPixelArraySize: [4000, 3000]
  46.                     },
  47.                     {
  48.                         cameraId: 'PHYSICAL_BACK_TELE',
  49.                         lensFocalLength: 14.2,
  50.                         minimumFocusDistance: 0.5,
  51.                         sensorPhysicalSize: [4.0, 3.0]
  52.                     }
  53.                 ]
  54.             }
  55.         ];
  56.         
  57.         this.appendLog(`成功扫描到 ${mockCameras.length} 个根相机设备`);
  58.         mockCameras.forEach((cam: MockCameraDevice) => {
  59.             this.appendLog(`========== ${cam.cameraId} ==========`);
  60.             if (cam.isLogicalCamera) {
  61.                 this.appendLog(`发现逻辑摄像头!等效焦距段: ${cam.lensEquivalentFocalLength.join(' - ')}mm`);
  62.                 this.appendLog(`开始解构底层物理构成: [共 ${cam.constituentCameraDevices.length} 颗物理镜头]`);
  63.                 cam.constituentCameraDevices.forEach((subCam: MockConstituentCamera, index: number) => {
  64.                     this.appendLog(`├─ 物理镜头 ${index + 1}: ${subCam.cameraId}`);
  65.                     this.appendLog(`│ ├─ 实际焦距: ${subCam.lensFocalLength}mm`);
  66.                     this.appendLog(`│ ├─ 最近对焦: ${subCam.minimumFocusDistance}m`);
  67.                     this.appendLog(`│ ├─ 畸变参数: [${subCam.lensDistortion?.join(', ')}]`);
  68.                     this.appendLog(`│ └─ Sensor尺寸: ${subCam.sensorPhysicalSize[0]} x ${subCam.sensorPhysicalSize[1]} mm`);
  69.                 });
  70.             }
  71.         });
  72.     }
  73.    
  74.     build() {
  75.         Column() {
  76.             // 头部导航及操作按钮区域...
  77.         }
  78.         .width('100%').height('100%').backgroundColor(Color.White)
  79.     }
  80. }
复制代码

这段代码的要点是:先请求 CameraManager 获取支持的相机列表,然后遍历每个相机设备,判断 isLogicalCamera 标记;如果为 true,再递归遍历 constituentCameraDevices,展示每颗物理镜头的焦距、最近对焦距离、畸变参数和传感器物理尺寸。在实际业务中,将 mock 数据替换为 cameraManager.getSupportedCameras() 的返回值即可。

五、避坑指南

在实际开发中,有三个问题需要特别注意。

第一,新增字段都是可选字段。lensFocalLength、lensDistortion 等参数在老机型上可能因为底层驱动未上报而返回 undefined。如果不对 undefined 做判断就直接调用 .length 或作为算法输入,会导致白屏崩溃。建议先判空再使用。

第二,畸变参数与内参数组的长度并不统一。虽然文档标注为 Array<number>,但不同 OEM 厂商实现的畸变模型不同,Brown-Conrady 模型和鱼眼模型返回的参数个数可能有差异,例如 5 个或 8 个。在 AR 标定算法中,务必先读取数组长度再决定使用哪种校准模型。

第三,逻辑相机的操控权限有限。开发者只能对逻辑相机整体进行流配置(如设置流分辨率、开启流),不能对 constituentCameraDevices 中解构出来的某个物理子镜头单独开启预览流。这些解构出的物理设备仅用于查询物理参数,不能作为独立的流操作对象。

六、总结

HarmonyOS 6.1.1 的 CameraDevice 物理参数透明化,打破了应用层与传感器硬件之间的信息黑盒。开发者可以借助这些畸变系数、焦距数据和像素阵列参数,更便捷地实现高级计算机视觉算法、实时 AR 跟踪渲染以及科研级的数据采集。对于鸿蒙生态下的专业影像应用而言,这是一项基础设施级别的能力升级。
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: HarmonyOS Camera Kit 深度器件与逻辑相机解构实战

终于有人把逻辑相机这事儿掰开揉碎了讲。之前做多摄对齐的时候,最头疼的就是拿不到底层物理参数,只能靠猜等效焦距,畸变校正更是纯靠经验调参。API 24 开放这些字段确实解决大问题,尤其是 `lensIntrinsicCalibration` 和 `sensorPhysicalSize`,对 AR 投影和深度计算太关键了。 想问一下楼主,`constituentCameraDevices` 返回的物理相机列表,是每次变焦后实时更新,还是创建逻辑相机时就固定下来的?另外,`lensDistortion` 给出的畸变系数是相对于物理镜头原始输出还是已经做过裁剪校正的?这块文档里没讲太细,想听实战过的朋友确认下。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: HarmonyOS Camera Kit 深度器件与逻辑相机解构实战

这个更新对做影像类应用的人来说太实用了。以前想要拿镜头畸变系数或者传感器物理尺寸,要么靠厂商私有接口,要么自己猜,现在直接能从 CameraDevice 里读出来,省太多事了。 逻辑相机解构这个设计尤其好,尤其现在多摄切换越来越频繁,能拿到 constituentCameraDevices 就知道当前成像是哪几颗物理镜头在协同,做变焦策略和画质调试都会清晰不少。 想确认一下,lensIntrinsicCalibration 返回的矩阵是 3x3 直接能拿到吗?还是说不同厂商可能会有不同的归一化方式?另外这些字段在开发版 HarmonyOS 6.1.1 模拟器上能读到值吗,还是必须真机才能测试?
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: HarmonyOS Camera Kit 深度器件与逻辑相机解构实战

这个更新太实用了!之前做AR应用时想拿镜头畸变参数和传感器物理尺寸,只能靠猜或者硬编码,现在API直接开放,省了太多事。逻辑相机解构这个设计也很赞,终于能看清变焦背后的物理镜头组合了。不过有点好奇,这些字段如果驱动不返回,有没有默认回退方案?另外,畸变参数数组里的系数顺序有没有文档明确说明?希望后续能补个标准示例。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-8-11 23:37 , Processed in 0.021698 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部