高通Camx功能feature分析之十五:insensor zoom介绍及实现

【关注我,后续持续新增专题博文,谢谢!!!】

上一篇我们讲了:

这一篇我们开始讲: 高通Camx功能feature分析之十五:insensor zoom介绍及实现

目录

[一、Insensor Zoom背景](#一、Insensor Zoom背景)

[二、Insensor Zoom 技术解析](#二、Insensor Zoom 技术解析)

[InSensorZoom 技术介绍](#InSensorZoom 技术介绍)

[InSensorZoom 核心原理](#InSensorZoom 核心原理)

三、InSensorZoom功能介绍

四、InSensorZoom方案介绍

[4.1 :平台决策,触发InSensorZoom拍照](#4.1 :平台决策,触发InSensorZoom拍照)

[4.2 :CHI 获取VendorTag](#4.2 :CHI 获取VendorTag)

[4.3 :CHI 转换VendorTag](#4.3 :CHI 转换VendorTag)

[4.4 :Camx 切换 Settings](#4.4 :Camx 切换 Settings)

[4.5 :更新 Crop Region](#4.5 :更新 Crop Region)


一、Insensor Zoom背景

InSensorZoom 技术背景与需求

传统主摄在变焦过程中依赖数字裁剪或插值算法放大画面,导致画质清晰度随变焦倍数增加而显著下降。用户反馈集中在以下问题:

  • 变焦后细节模糊、边缘锯齿化
  • 低光环境下噪点加剧
  • 色彩还原失真

二、Insensor Zoom 技术解析

InSensorZoom 技术介绍

Insensor Zoom 是一种通过传感器端直接处理图像裁剪的技术。传统数码变焦依赖平台端对全分辨率图像进行裁剪放大,而 Insensor Zoom 将裁剪过程前置到传感器端,利用传感器的高分辨率原始数据直接输出目标视野的图像。

InSensorZoom 核心原理

通过传感器硬件层优化实现无损变焦:

  1. 高分辨率传感器设计

    采用超高像素传感器(如48MP/64MP),物理像素冗余为裁剪留出空间。例如:
    实际输出12MP时,64MP传感器可提供5.3倍无损裁剪空间

  2. 像素级精准裁剪

    直接调用传感器原生区域成像,避免传统数字放大导致的画质损失:

    • 全分辨率模式:拍摄完整传感器范围
    • 裁剪模式:仅读取传感器中心区域像素
  3. 多帧合成算法

    结合多帧超分辨率技术进一步提升裁剪后的画质:

    • 对齐多帧消除抖动
    • 智能融合增强细节

以三星 S5KGW1 传感器为例:

  • 传统模式:采用 Binning 输出 16MP(4608x3456)图像,变焦时平台端对 16MP 图像进行裁剪放大。
  • Insensor Zoom 模式:启用 64MP 全分辨率,传感器端直接从 64MP 原始数据裁剪出目标视野的 16MP 图像,再输出给平台端。
核心优势
  • 清晰度提升:64MP 传感器裁剪的 16MP 图像比原生 16MP 裁剪的 4MP 图像保留更多细节,物理分辨率更高。
  • 带宽优化:平台端无需处理大尺寸图像裁剪,仅接收已优化的输出数据,降低计算负载。
  • 变焦效率:2 倍变焦时平台端无需裁剪;5 倍变焦时平台裁剪倍数从 5 倍降至 2.5 倍。
效果对比
变焦场景 传统方式 Insensor Zoom
2 倍变焦 平台裁剪 2 倍(16MP→4MP) 传感器直接输出目标 16MP
5 倍变焦 平台裁剪 5 倍 平台仅需裁剪 2.5 倍

实施效果对比

指标 传统数字变焦 InSensorZoom
变焦2倍清晰度 下降约30% 下降<5%
边缘锐度 明显模糊 接近光学镜头
处理延迟 中(需多帧)
技术实现关键
  • 传感器支持:需具备高分辨率模式(如 64MP)和片上裁剪能力。
  • 算法协同:传感器端需精确计算裁剪区域,确保与目标变焦倍数匹配。
  • 功耗平衡:全分辨率模式可能增加传感器功耗,需优化工作流程。

该技术适用于多摄系统中长焦镜头的辅助增强,或在单摄系统中实现更高质量的数字变焦。

三、InSensorZoom功能介绍

普通Zoom流程

传统Zoom拍摄过程中,传感器(sensor)通过选择binning size输出图像,平台随后对图像进行S倍裁剪(S代表Zoom的倍率)。例如,当Zoom倍率为2倍时,传感器输出40003000分辨率图像,平台裁剪为20001500。

InSensorZoom流程

InSensorZoom采用不同的处理方式。传感器选择full size设置,先进行2倍裁剪输出图像,平台再对图像进行S/2倍裁剪。例如,当Zoom倍率为4倍时,传感器输出80006000分辨率图像,先裁剪为40003000,平台再裁剪为2000*1500。

启用条件

InSensorZoom的启用分为两种情况:

  • 当Zoom倍率1 ≤ S < 2时,采用普通Zoom流程。
  • 当Zoom倍率S ≥ 2时,采用InSensorZoom流程。
优势与原理

InSensorZoom的主要优势在于提升高倍率Zoom(≥2倍)拍摄时的图像清晰度,Zoom倍率越大效果越显著。其原理是通过选择传感器的full size设置,使得有效像素点数量是普通Zoom的2倍。以OV48B传感器2倍Zoom为例:

  • 普通Zoom:传感器输出4000**3000,平台裁剪为2000**1500,有效像素点为2000*1500。
  • InSensorZoom:传感器输出8000**6000,裁剪为4000**3000(2倍Zoom时平台不裁剪),有效像素点为4000*3000。

通过这种方式,InSensorZoom在高倍率Zoom时能够保留更多细节,从而提升图像质量。

四、InSensorZoom方案介绍

4.1 :平台决策,触发InSensorZoom拍照

平台决策逻辑 平台通过评估当前环境参数(feature type、ISO、luxIndex等)判断是否满足InSensorZoom触发条件。若参数符合要求,平台将向APP返回状态标识mSupportCaptureZoomFeature=4,作为启用InSensorZoom的决策依据。

APP端执行流程 当APP检测到mSupportCaptureZoomFeature=4时,会通过VendorTag机制向HAL层传递控制指令。具体使用的VendorTag为com.qti.izoom_control.state_izoom_snapshot

关键参数说明

  • mSupportCaptureZoomFeature:平台与APP间的状态通信变量,值为4时表示满足InSensorZoom条件
  • state_izoom_snapshot:HAL层控制标签,通过1/2/3的数值序列实现分段控制

4.2 :CHI 获取VendorTag

  • 在CreateUsecaseRequestObject将APP Meta 填充到HAL Meta。
cpp 复制代码
chi-cdk/core/chifeature2/chifeature2wrapper.cpp
1974  ChiFeature2UsecaseRequestObject* Feature2Wrapper::CreateUsecaseRequestObject(
1975      camera3_capture_request_t* pRequest)
1976  {
1977      CDKResult                                       result                = CDKResultSuccess;
1978      ChiFeature2UsecaseRequestObjectCreateInputInfo  pCreateInputInfo      = { };
1979      ChiFeature2UsecaseRequestObject*                pUsecaseRequestObject = NULL;

............
2030          {
2031              camera_metadata_t* pAppMetadata = const_cast<camera_metadata_t*>(pRequest->settings);
2032              ChiMetadata*       pHalMetadata = pCreateInputInfo.pAppSettings;
2033              INT32 isInSensorZoom = 0;
2034  
2035              CHITAGSOPS   tagOps = { 0 };
2036              ExtensionModule::GetInstance()->GetVendorTagOps(&tagOps);
2037              UINT32       tagLocation  = 0;
2038  
2039              if (CDKResultSuccess == tagOps.pQueryVendorTagLocation("com.qti.izoom_control", "state_izoom_snapshot", &tagLocation))
2040              {
2041                    if(pHalMetadata != NULL)
2042                    {
2043                        tagOps.pGetMetaData(pAppMetadata, tagLocation, &isInSensorZoom, sizeof(INT32));
2044                        pHalMetadata->SetTag("com.qti.izoom_control", "state_izoom_snapshot", &isInSensorZoom, 1);
2045                    }
2046              }
2047          }
............
  • 读取InSensorZoom的VendorTag
  1. 检测拍照标志位 isSnapshot,若为 TRUE,则读取 VendorTag(com.qti.izoom_control.state_izoom_snapshot)
  2. 若该 Tag 存在,表明当前为 InSensorZoom 拍照模式,需设置 FeatureHint(captureMode.u.InSensorZOOM)1
cpp 复制代码
2347  VOID ChiFeature2GraphSelector::AddCustomFeatureGraphNodeHints(
2348      ChiFeature2UsecaseRequestObject*             pRequestObject,
2349      std::vector<ChiFeature2InstanceRequestInfo>& rFeatureInstanceReqInfoList)
2350  {
2353      BOOL isInSensorZoomSnapshot                = IsInSensorZOOMSnapshot(pRequestObject);
............
2373          if (isInSensorZoomSnapshot)
2374          {
2375            SetFeatureHint(&(rFeatureInstanceReqInfoList[featureIndex].featureHint));
2376          }
............
}


3039  BOOL ChiFeature2GraphSelector::IsInSensorZOOMSnapshot(
3040      ChiFeature2UsecaseRequestObject*             pRequestObject)
3041  {
3042      CHICAPTUREREQUEST* pChiRequest             = pRequestObject->GetChiCaptureRequest();
3043      const Feature2ControllerResult* pMccResult = pRequestObject->GetMCCResult();
3044      BOOL isSnapshot                            = FALSE;
3045      BOOL isInSensorZoomSnapshot                = FALSE;
3046  
3047      if (pMccResult == NULL || pMccResult->isValid == FALSE)
3048      {
3049          for (UINT i = 0; i < pChiRequest->numOutputs; i++)
3050          {
3051              if (TRUE == UsecaseSelector::IsJPEGSnapshotStream(
3052                  reinterpret_cast<camera3_stream_t*>(pChiRequest->pOutputBuffers[i].pStream)) ||
3053                  TRUE == UsecaseSelector::IsYUVSnapshotStream(reinterpret_cast<camera3_stream_t*>(pChiRequest->pOutputBuffers[i].pStream)))
3054              {
3055                  isSnapshot = TRUE;
3056                  break;
3057              }
3058          }
3059  
3060          if (isSnapshot && ChxUtils::IsInSensorZoom(pRequestObject->GetAppSettings()))
3061          {
3062              isInSensorZoomSnapshot = TRUE;
3064              CHX_LOG_INFO("InSensorZOOM[1] triggerred in sensor snapshot InSensorZOOM:%d", static_cast<INT>(ChxUtils::GetInSensorZoomState(pRequestObject->GetAppSettings())));
3065          }
3066      }
3067      CHX_LOG_INFO("isInSensorZoomSnapshot = %d", isInSensorZoomSnapshot);
3068      return isInSensorZoomSnapshot;
3069  }

4.3 :CHI 转换VendorTag

判断 是否InSensorZoom 拍照模式

通过 FeatureHint 检测是否为 InSensorZoom 模式。若确认,需设置上下文环境:

  • isInSensorZoomCaptureEnable = TRUE
  • isManualCaptureNeeded = TRUE

添加 Dummy Request

  • 由于SensorPipelineDelay,切换Settings需要延后。在 InSensorZoom 的第一个 Request 前和最后一个 Request 后,添加 SensorPipelineDelay 对应的 Dummy Request。
  • 未添加 Dummy Request 会导致最后两帧输出为 Binning Size 而非 Full Size。
cpp 复制代码
437  CDKResult ChiFeature2RealTime::OnExecuteProcessRequest(
438      ChiFeature2RequestObject * pRequestObject
439      ) const
440  {
............
462      BOOL    isInSensorZoomSnapshotEnabled =
463                  IsInSensorZoomSnapshot(pHint,
464                                         IsPortEnabledInFinalOutput(pRequestObject,
465                                                                    RealtimeOutputPortRaw,
466                                                                    requestId),
467                                         pRequestObject);
............
488      else if (isInSensorZoomSnapshotEnabled)
489      {
490          //  For the single frame snapshot with In-sensor zoom case, we need to add SensorPipelineDelay two times.
491          //  One is for the sensor mode seamless switch to In-sensor zoom mode and the other one is to switch back.
492          if (0 == requestId)
493          {
494              maxSequence += SensorPipelineDelay;
495          }
496          CHX_LOG_INFO("InSensorZOOM[2] maxSequence:%d frame:%u, requestId:%u", maxSequence, pRequestObject->GetUsecaseRequestObject()->GetAppFrameNumber(), requestId);
497      }

InSensorZoom 状态转换

  • isInSensorZoomCaptureEnableTRUE,执行InSensorZoom状态转换逻辑。
cpp 复制代码
437  CDKResult ChiFeature2RealTime::OnExecuteProcessRequest(
438      ChiFeature2RequestObject * pRequestObject
439      ) const
440  {
............
661                          if ((NULL != pPrivContext) && TRUE == pPrivContext->isInSensorZoomCaptureEnable)
662                          {
663                              pPrivContext->inSensorZoomState = GetInSensorZoomState(pRequestObject, stageSequenceId);
664                              CHX_LOG_INFO("InSensorZOOM[2] pPrivContext->inSensorZoomState:%d", static_cast<INT>(pPrivContext->inSensorZoomState));
665                          }

}

    CHX_INLINE InSensorZOOMState GetInSensorZoomState(
818          ChiFeature2RequestObject*    pRequestObject,
819          UINT8                        stageSequenceId) const
820      {
821          InSensorZOOMState            returnState = InSensorZoom_NONE;
822          UINT8                        requestId = pRequestObject->GetCurRequestId();
823          UINT8                        numRequests = pRequestObject->GetNumRequests();
824          ChiFeatureRealtimeContext* pPrivContext = static_cast<ChiFeatureRealtimeContext *>(
825                                                          GetFeaturePrivContext(pRequestObject));
826  
827          //Decide the InSensorZoom state depends on requestId, stageSequenceId, numRequests and maxSequence.
828          InSensorZOOMState        appState    = ChxUtils::GetInSensorZoomState(pRequestObject->GetUsecaseRequestObject()->GetAppSettings());
829          if (0 == requestId)
830          {
831              switch (appState)
832              {
833                  case InSensorZoom_START:
834                      if (stageSequenceId < SensorPipelineDelay)
835                      {
836                          returnState = InSensorZoom_NONE;
837                      }
838                      else if (stageSequenceId == SensorPipelineDelay)
839                      {
840                          returnState = InSensorZoom_START;
841                      }
842                      else
843                      {
844                          returnState = InSensorZoom_ENABLED;
845                      }
846                      CHX_LOG_INFO("InSensorZOOM[2] InSensorZoom_START returnState:%d", returnState);
847                      break;
848                  case InSensorZoom_STOP:
849                      if (stageSequenceId < SensorPipelineDelay)
850                      {
851                          returnState = InSensorZoom_ENABLED;
852                      }
853                      else
854                      {
855                          returnState = InSensorZoom_STOP;
856                      }
857                      CHX_LOG_INFO("InSensorZOOM[2] InSensorZoom_STOP returnState:%d", returnState);
858                      break;
859                  case InSensorZoom_ENABLED:
860                      returnState = InSensorZoom_ENABLED;
861                      CHX_LOG_INFO("InSensorZOOM[2] InSensorZoom_ENABLED returnState:%d", returnState);
862                      break;
863                  default:
864                      returnState = InSensorZoom_NONE;
865                      CHX_LOG_INFO("InSensorZOOM[2] InSensorZoom_NONE returnState:%d", returnState);
866                      break;
867              }
868          }
869          else if (((requestId + 1) == numRequests) &&
870                   (SensorPipelineDelay == stageSequenceId))
871          {
872              returnState = InSensorZoom_STOP;
873          }
874          else
875          {
876              returnState = InSensorZoom_ENABLED;
877          }
878  
879          CHX_LOG_INFO("InSensorZOOM[2] requestId:%d, stageSequenceId:%d numRequests:%d", requestId, stageSequenceId, numRequests);
880          return returnState;
881      }

回写 VendorTag

转换后的InSensorZoom状态需回写到 VendorTag

  • 第一帧状态为 1
  • 中间 8 帧状态为 2(APP 下发 6 帧)
  • 最后一帧状态为 3(返回 APP 的帧为状态 1 和前 7 帧状态 2

4.4 :Camx 切换 Settings

读取 InSensorZoom VendorTag

SensorNode::ExecuteProcessRequest 中获取 VendorTag(com.qti.izoom_control.state_izoom_snapshot),并配置以下InSensorZoom setting参数:

  • 最大模拟 Gain
  • LineLengthPixelClock
  • FrameLengthLines
cpp 复制代码
1895  CamxResult SensorNode::ExecuteProcessRequest(
1896      ExecuteProcessRequestData* pExecuteProcessRequestData)
1897  {
............
2010              if (IsInSensorZoomSupported())
2011              {
2012                  SetInSensorZoomState(requestId);
2013              }


3284  VOID ImageSensorData::SetMaxAnalogGain(
3285      UINT32              resolutionIndex,
3286      SensorSeamlessType  inputSeamlessType)
3287  {
3300              case SensorSeamlessType::InSensorZoom:
3301                  inputMaxAnalogGain =
3302                              GetResolutionInfo()->resolutionData[resolutionIndex].InSensorZoomSettings.MaxAnalogGain;
3303                  break;


487  UINT16 ImageSensorData::GetLineLengthPixelClk(
488      UINT                resolutionIndex,
489      SensorSeamlessType  inputSeamlessType
490      ) const
491  {
505      else if (SensorSeamlessType::InSensorZoom == inputSeamlessType)
506      {
507          returnValue = static_cast<UINT16>(pResData->InSensorZoomSettings.LineLengthPixelClock);
508      }

切换 InSensorZoom Settings

ZoomStateInSensorZoom_STARTInSensorZoom_STOP 时,调用 SensorNode::ApplySensorUpdate 切换 SensorZoom Settings,在新的sensormode出full size图。

涉及函数:

  • ImageSensorData::GetI2CCmdMaxSize
  • ImageSensorData::GetI2CCmdSize
cpp 复制代码
4822  CamxResult SensorNode::ApplySensorUpdate(
4823      UINT64  requestId)
4824  {
4967      if ((InSensorZoom_START == m_InSensorZoomState) ||
4968          (InSensorZoom_STOP  == m_InSensorZoomState))
4969      {
4970          ApplyUpdateInSensorZoomI2CCmd(requestId);
4971      }


7226  VOID SensorNode::ApplyUpdateInSensorZoomI2CCmd(UINT64  requestId)
7227  {
7228      CamxResult          result                 = CamxResultSuccess;
7229      UINT                inSensorZoomCmdSize    = 0;
7230      UINT                regSettingIdx          = 0;
7231      I2CRegSettingType   i2cSettingType         = I2CRegSettingType::InSensorZoomOFF;
7232  
7233      if (InSensorZoom_START == m_InSensorZoomState)
7234      {
7235          i2cSettingType = I2CRegSettingType::InSensorZoomON;
7236      }
7237      else
7238      {
7239          i2cSettingType = I2CRegSettingType::InSensorZoomOFF;
7240      }
7241  
7242      inSensorZoomCmdSize = GetSensorDataObject()->GetI2CCmdSize(i2cSettingType,
7243                                                                    NULL,
7244                                                                    m_currentResolutionIndex,
7245                                                                    &regSettingIdx);
7246  
7247      if (0 != inSensorZoomCmdSize)
7248      {
7249          CAMX_LOG_INFO(CamxLogGroupSensor, "InSensorZOOM[3] requestId: %llu, cameraId %d,"
7250                        "inSensorZoomCmdSize:%d, m_InSensorZoomState=%u",
7251                        requestId, m_cameraId, inSensorZoomCmdSize, m_InSensorZoomState);
7252          VOID* pInSensorZoomUpdate = m_pUpdateCmds->BeginCommands(inSensorZoomCmdSize / sizeof(UINT32));
7253          if (pInSensorZoomUpdate != NULL)
7254          {
7255              result = GetSensorDataObject()->CreateI2CCmd(i2cSettingType,
7256                                                           pInSensorZoomUpdate,
7257                                                           NULL,
7258                                                           m_currentResolutionIndex,
7259                                                           regSettingIdx);
7260              if (CamxResultSuccess == result)
7261              {
7262                  result = m_pUpdateCmds->CommitCommands();
7263              }
7264          }
7265      }
7266  }

调节曝光 Gain 和 LineCount

  • 切换 Settings 后需调整 Gain 以补偿 LineCount 变化,确保亮度一致。
  • OV Sensor 需客制化 LineCount:切换后首帧的 LineCount 不得与 Settings 中配置的 FrameLengthLines 相同,否则会导致 Raw 黑图或 YUV 花图。
cpp 复制代码
4512  VOID SensorNode::PrepareSensorUpdate(
4513      SensorParam* pSensorParam,
4514      NodeProcessRequestData* pNodeProcessRequestData)
4515  {
............
4630      AdjustExposureGainForInSensorZoom(pSensorParam);

4.5 :更新 Crop Region

InSensorZoom模式下传感器已进行2倍裁剪(crop),需调整平台裁剪参数为S/2。HAL层的裁剪会导致不同帧间视场角(FOV)差异显著(Zoom倍数越大差异越明显),因此Hal需要disable crop信息。

解决方案步骤

禁用HAL层裁剪信息 修改HAL层代码逻辑,确保裁剪参数不传递至下游处理模块。需检查以下接口:

  • 确认set_crop_region()或类似接口是否被调用
  • 屏蔽或注释掉HAL层向平台传递裁剪参数的代码段
  • 验证裁剪参数是否在HAL层被默认设置为全分辨率范围

方案选择

  • hal收到Request 时保存 Crop Region 并重置,不做crop,Result 时回写保存的crop region。

实现步骤

  • Request 阶段 :在 Feature2Wrapper::ExecuteProcessRequest 中保存并重置 Crop Region。
  • Result 阶段 :通过 Feature2Wrapper::ProcessResult 回写保存的 Crop Region。
  • 通知平台更新 :通过 VendorTag "com..IZOOMsnapshot" 触发平台将 Crop Region 更新为 S/2 倍。

【关注我,后续持续新增专题博文,谢谢!!!】

下一篇讲解:

相关推荐
aqi003 小时前
一文读懂 HarmonyOS 6.1 带来的十大重要升级
android·华为·harmonyos·鸿蒙·harmony
秋95 小时前
MySQL 9.7.0 使用详解:新特性、实战与避坑指南
android·数据库·mysql
狼与自由5 小时前
clickhouse ReplacingMergeTree
android·clickhouse
吉吉615 小时前
php反序列化基础知识前奏
android·php·反序列化
努力努力再努力wz5 小时前
【MySQL进阶系列】拒绝冗余SQL:带你透彻理解视图的底层逻辑
android·c语言·数据结构·数据库·c++·sql·mysql
常利兵6 小时前
安卓黑科技:实现多平台商品详情页一键跳转APP
android·科技
_李小白6 小时前
【android opencv学习笔记】Day 5: 高效的图像扫描
android·opencv·学习
liang_jy14 小时前
Android 窗口容器树(一)—— 窗口和窗口容器树
android·源码
HUGu RGIN14 小时前
MySQL--》如何在MySQL中打造高效优化索引
android·mysql·adb