camera-qsc-crosstalk校准数据XTALK回写

news2024/9/20 20:40:37

问题背景

手机越做越紧凑,需要模组和芯片尺寸越做越小,在尺寸一定的基础上,高像素和大像素,对于手机摄像头来说,一直是一对矛盾的存在。

  • 高像素:带来高分辨率画质
  • 大像素:带来暗态下高感光度和低噪声的画质。

以上两者都非常重要,为了两者兼得4cell1感光芯片应运而生,也称之为“Tetra cell”,“Quad bayer”,“four cell”等,该芯片基于经典的Bayer阵列,将每一种颜色以4个pixel排列组合,成功可以让一款摄像头在高像素和大像素之间自由切换。现如今4cell1感光芯片兼具了常态的高像素和暗态的高感光低噪声的表现,已经成为目前手机摄像头的主力军。
在这里插入图片描述同时也带来问题,如下图,左边实拍图比右图多了许多齿狀格子等伪色。主要原因是芯片本身硬件感光和Remosaic造成的,为了优化这种现象,‘CrossTalk校准’登场,去除由于信号差别造成的格子,锯齿状等色块干扰。
在这里插入图片描述什么是crosstalk?
在感光芯片中,crosstalk(串扰)现象是指相邻像素之间的信号互相影响导致的一种干扰。当一个像素受到光照并转换成电信号时,其附近的像素可能会因为光电效应或其他物理机制而感应到部分光强,这不属于它们自身的光学响应,而是由于彼此之间产生的非线性相互作用。这种串扰可能导致图像质量下降,尤其是在高密度像素阵列如CMOS传感器中更为明显,因为它增加了错误信息的传播机会。为了减少crosstalk,设计者通常会采用各种技术,比如优化像素布局、增加隔离层等措施。
在这里插入图片描述解决办法:crosstalk(串扰)校准。
Crosstalk校准工具,通常将全图分成多个ROI方块,计算各像素通道的能量并确定其补偿数据,芯片再使用这些校准数据让原本不均匀状态的能量分布变得更为平衡。
在这里插入图片描述在这里插入图片描述

问题分析

一般是模组厂家在模组出厂的时候,会使用上述的crosstalk工具将校准补偿数据烧录在eeprom里面。在调试模组成像效果的时候,需要从eeprom中读取crosstalk数据(QSC),然后写入感光芯片中的特定寄存器中进行校准。
注意:
4cell1芯片还会涉及到PD补偿,坏点补偿等其他的内容,而整个流程,通常需要先补偿PD点,再做Crosstalk校准,然后再Remosaic成为正常的Bayer去应用。针对软件的Remosaic,这其中所有的步骤,通常都封装在芯片厂商提供的一个算法库里面,手机端调用该算法库,去实现4cell1芯片,兼具常态时候的高分辨率和暗态时候的高感光度,然后你就可以美美地拍照了。
————————————————

                        版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/qq_41897352/article/details/117336884

当向sensor寄存器(0x53c0 ~ 0x54df)写入Crosstalk补偿数据时候,sensor要么在sleep mode(0x0100 = 0)要么crosstalk disable(寄存器0x5000[6] = 0)

关键代码

  1. 在文件camxeepromdriver.xsd添加Crosstalk对应的QSC数据属性可以模仿SPC的填写方法,如在eeprom的xml文件模仿SPC的数据格式填写如下。
    <QSC>
       <!--Specifies the availability of the specified data and type of endianness
            element for operation  -->
       <QSCData description="Memory Type">
         <!--Specifies whether a particular OTP data available or not -->
         <isAvailable>true</isAvailable>
         <!--Type of the Endianness
             Valid values are: BIG, LITTLE -->
         <endianness>BIG</endianness>
       </QSCData>
       <QSCSettings>
           <!--Specifies memory offset value and mask information -->
           <dataOffset>
             <!--Offset value in the OTP memory -->
             <offset>0x1798</offset>
             <!--mask value which will be applied to obtain required data bits -->
             <mask>0xFF</mask>
           </dataOffset>
           <!--register address value to write QSC data -->
           <QSCAddress>0x53c0</QSCAddress>
           <!--size of the QSC data settings -->
           <settingsSize>288</settingsSize>
       </QSCSettings>
       <!--Register address / data size in bytes -->
       <addressType range="[1,4]">2</addressType>
       <!--Register address / data size in bytes -->
       <dataType range="[1,4]">1</dataType>
       <!--Delay in milli seconds. Delay is 0 if not explicitly provided -->
       <delay>0</delay>
     </QSC>
  1. 在仓库camx中,先将EEPROM中的crosstalk校准数据读取出来,主要实现在src/core/camxeepromdata.cpp中的FormatQSCData();FormatQSCData函数在构造函数EEPROMData::EEPROMData()中调用。FormatQSCData函数是模仿者FormatSPCData函数写的。如下:
 
  /// EEPROMData::FormatQSCData
  
  VOID EEPROMData::FormatQSCData()
  {
      QSCInfo*             pQSCFormatInfo = &(m_pEEPROMDriverData->formatInfo.QSC);
      QSCCalibrationData*  pQSCData       = &(m_pSensorInfoTable->moduleCaps.OTPData.QSCCalibration);
      MemoryInfo           dataOffset     = { 0 };
  
      pQSCData->isAvailable = pQSCFormatInfo->QSCData.isAvailable;
  
      if (TRUE == pQSCFormatInfo->QSCData.isAvailable)
      {
          UINT32  totalRegCount = 0;
          for (UINT16 i = 0; i < pQSCFormatInfo->QSCSettingsCount; ++i)
          {
              totalRegCount += pQSCFormatInfo->QSCSettings[i].settingsSize;
          }
  
          pQSCData->settings.regSettingCount = totalRegCount;
          pQSCData->settings.regSetting      = static_cast<RegisterSetting*>(
                                                           CAMX_CALLOC(sizeof(RegisterSetting) * totalRegCount));
  
          if (NULL != pQSCData->settings.regSetting)
          {
              RegisterData* pRegData = static_cast<RegisterData*>(CAMX_CALLOC(sizeof(RegisterData) * totalRegCount));
  
              if (NULL != pRegData)
              {
                  RegisterSetting* pCurRegOffset = pQSCData->settings.regSetting;
  
                  for (UINT16 i = 0; i < pQSCFormatInfo->QSCSettingsCount; ++i)
                  {
                      /// copy to local structures so that original offset values wont be modified because of increments
					  
                      Utils::Memcpy(&dataOffset, &pQSCFormatInfo->QSCSettings[i].dataOffset, sizeof(MemoryInfo));
  
                      UINT32 dataSize = MaskLengthInBytes(dataOffset.mask);
                      if (NULL != pQSCData->settings.regSetting)
                      {
                          for (UINT16 index = 0; index < pQSCFormatInfo->QSCSettings[i].settingsSize; index++, pCurRegOffset++)
                          {
                              (pCurRegOffset)->registerAddr    = pQSCFormatInfo->QSCSettings[i].QSCAddress + index;
                              (pCurRegOffset)->registerData    = pRegData++;
                              (pCurRegOffset)->registerData[0] =
                                  FormatDataTypeInteger((&dataOffset), pQSCFormatInfo->QSCData.endianness);
                              dataOffset.offset                += static_cast<UINT16>(dataSize);
                              (pCurRegOffset)->regAddrType     = pQSCFormatInfo->addressType;
                              (pCurRegOffset)->regDataType     = pQSCFormatInfo->dataType;
                              (pCurRegOffset)->operation       = OperationType::WRITE;
  
                              if (0 != pQSCFormatInfo->delay)
                              {
                                  (pCurRegOffset)->delayUsExists = TRUE;
                                  (pCurRegOffset)->delayUsID     = 0;
                                  (pCurRegOffset)->delayUs       = pQSCFormatInfo->delay;
                              }
                          }
                      }
                  }
  
              }
              else
              {
                  CAMX_LOG_ERROR(CamxLogGroupSensor, "Calloc failed");
              }
          }
          else
          {
              CAMX_LOG_ERROR(CamxLogGroupSensor, "Calloc failed");
          }
      }
  }

同理,也需要模仿DumpWBData函数来实现DumpQSCData
其他地方,可以参考模仿AWB,SPC的写法在SensorNode::LoadSensorConfigCmds()函数中添加,即可打通流程。

具体的说,crosstalk补偿写入是发生在配流阶段,详细可以参考
CamX-Chi 高通Android Camera HAL框架学习2-configure_streams

验证测试

验证高像素模式下修改前后的预览成像和拍照成像在手机上肉眼无法观察到明显差异。
那么如何保证已经正确地将EEPROM中的crosstalk校准数据写入了感光芯片对应的寄存器中呢?

  1. 首先验证确保从EEPROM中crosstalk校准数据读取正确,这可以通过checksum和dump数据来分别验证。
  
  /// EEPROMDataDump::DumpQSCData
  
  VOID EEPROMDataDump::DumpQSCData()
  {
      FILE*              pQSCDumpFile            = NULL;
      CHAR               fileName[FILENAME_MAX] = { 0 };
      QSCCalibrationData* pQSCData                = &(m_pSensorInfoTable->moduleCaps.OTPData.QSCCalibration);
  
      if (TRUE == pQSCData->isAvailable)
      {
          OsUtils::SNPrintF(fileName, sizeof(fileName), "%s/%s_%s_%s", ConfigFileDirectory,
                            m_pEEPROMDriverData->slaveInfo.EEPROMName, "qsc", "OTP.txt");
          pQSCDumpFile = OsUtils::FOpen(fileName, "w");
      }
  
      if (pQSCDumpFile != NULL)
      {

        for (UINT16 index = 0; index < pQSCData->settings.regSettingCount; index++)
        {
            OsUtils::FPrintF(pQSCDumpFile,
                             "addr = 0x%x : value  = 0x%x\n",
                             pQSCData->settings.regSetting[i].registerAddr,
                             pQSCData->settings.regSetting[i].registerData[0]);
        }

  
        OsUtils::FClose(pQSCDumpFile);
      }
  }
  1. 如何确保将crosstalk校准数据准确地写入了sensor对应的寄存器0x53c0 ~ 0x54df中,最简单的思路就是去读取写入后寄存器的值。遗憾的是,这些寄存器都是只写寄存器。
    于是,想到找效果同事去验证下Xtalk补偿回写前后高像素模式拍照图片对比。使用效果专用软件发现,补偿后的图片在放大后的效果字体更加清晰,说明补偿有不错的收益。

代码评审问题

  1. Xtalk补偿回写是在什么时候写入的?是在使用高像素模式的时候进行回写补偿吗?
  2. sensor寄存器0x5380(值0x0f)默认打开 Xtalk补偿回写,有没有副作用?

参考文章

https://blog.csdn.net/qq_41897352/article/details/117336884

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1925841.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【java】力扣 反转链表

力扣 206 链表反转 题目介绍 解法讲解 先定义两个游标indexnull&#xff0c;prenull&#xff0c;反转之后链表应该是5&#xff0c;4&#xff0c;3&#xff0c;2&#xff0c;1&#xff0c;我们先进行2->1的反转&#xff0c;然后再循坏即可 让定义的游标index去存储head.n…

RocketMQ~消息的种类与生命周期(普通消息、延时定时消息、事务消息)

普通消息 普通消息一般应用于微服务解耦、事件驱动、数据集成等场景&#xff0c;这些场景大多数要求数据传输通道具有可靠传输的能力&#xff0c;且对消息的处理时机、处理顺序没有特别要求。 以在线的电商交易场景为例&#xff0c;上游订单系统将用户下单支付这一业务事件封…

im即时通讯系统有哪些?

IM即时通讯系统是一种通过互联网和移动通信网络实现实时通信的系统。在众多IM即时通讯系统中&#xff0c;WorkPlus作为企业级IM即时通讯系统&#xff0c;提供了全面的通讯和协作解决方案。本文将介绍几种常见的IM即时通讯系统&#xff0c;以及WorkPlus作为企业级IM即时通讯系统…

第三方配件也能适配苹果了,iOS 18与iPadOS 18将支持快速配对

苹果公司以其对用户体验的不懈追求和对创新技术的不断探索而闻名。随着iOS 18和iPadOS 18的发布&#xff0c;苹果再次证明了其在移动操作系统领域的领先地位。 最新系统版本中的一项引人注目的功能&#xff0c;便是对蓝牙和Wi-Fi配件的配对方式进行了重大改进&#xff0c;不仅…

【自动驾驶汽车通讯协议】UART通信详解:理解串行数据传输的基石

文章目录 0. 前言1. 同步通讯与异步通讯1.1 同步通信1.2 异步通信 2. UART的数据格式3. 工作原理3.1 波特率和比特率3.2 UART的关键特性 4. UART在自动驾驶汽车中的典型应用4.1 UART特性4.2应用示例 5. 结语 0. 前言 按照国际惯例&#xff0c;首先声明&#xff1a;本文只是我自…

html5——列表、表格

目录 列表 无序列表 有序列表 自定义列表 表格 基本结构 示例 表格的跨列 表格的跨行 列表 无序列表 <ul>【声明无序列表】 <li>河间驴肉火烧</li>【声明列表项】 <li>唐山棋子烧饼</li> <li>邯郸豆沫</li> <l…

pyinstaller教程(二)-快速使用(打包python程序为exe)

1.介绍 PyInstaller 是一个强大的 Python 打包工具&#xff0c;可以将 Python 程序打包成独立的可执行文件。以下会基于如何在win系统上将python程序打包为exe可执行程序为例&#xff0c;介绍安装方式、快速使用、注意事项以及特别用法。 2.安装方式 通过 pip 安装 PyInstal…

随笔-不是来养老的吗

来了有一个多月了&#xff0c;日子过得飞快。都以为我来养老的&#xff0c;一开始我也这么认为&#xff0c;结果6月份的日均工时&#xff0c;排在了部门第一。一个月做的需求比之前的三个月都多。 来之前&#xff0c;老徐让我多承担点&#xff0c;想着能有多少活嘛&#xff0c…

QT TCP多线程网络通信

学习目标&#xff1a; TCP网络通信编程 学习前置环境 运行环境:qt creator 4.12 QT TCP网络通信编程-CSDN博客 Qt 线程 QThread类详解-CSDN博客 学习内容 使用多线程技术实现服务端计数器 核心代码 客户端 客户端&#xff1a;负责连接服务端&#xff0c;每次连接次数1。…

sklearn之神经网络学习算法

文章目录 什么是神经网络人工神经网络的结构输入层输出层隐含层神经元的链接 近几年深度学习还是比较火的&#xff0c;尤其是在大语言模型之后&#xff0c;在本质上深度学习网络就是层数比较多的神经网络。sklearn并不支持深度学习&#xff0c;但是支持多层感知机&#xff08;浅…

安全测试理论

安全测试理论 什么是安全测试&#xff1f; 安全测试&#xff1a;发现系统安全隐患的过程安全测试与传统测试区别 传统测试&#xff1a;发现bug为目的 安全测试&#xff1a;发现系统安全隐患什么是渗透测试 渗透测试&#xff1a;已成功入侵系统为目标的的攻击过程渗透测试与安全…

自动驾驶事故频发,安全痛点在哪里?

大数据产业创新服务媒体 ——聚焦数据 改变商业 近日&#xff0c;武汉城市留言板上出现了多条关于萝卜快跑的投诉&#xff0c;多名市民反映萝卜快跑出现无故停在马路中间、高架上占最左道低速行驶、转弯卡着不动等情况&#xff0c;导致早晚高峰时段出现拥堵。萝卜快跑是百度 A…

配置与管理Samba服务器(详细教程)

目录 一、基础理论 二、samba工作流程 三、项目实训 3.1目的 3.2准备工作 3.2.1服务器安装samba服务软件包 3.2.2客户端安装软件包 3.3配置Samba服务 3.3.1开启Samba服务&#xff0c;并设置开启自启动 3.3.2创建共享文件夹 3.3.3创建群组 3.3.4修改文件用户权限 3.3.5修改…

LabVIEW人工模拟肺控制系统开发

开发了一种创新的主被动一体式人工模拟肺模型&#xff0c;通过LabVIEW开发的上位机软件&#xff0c;实现了步进电机驱动系统的精确控制和多种呼吸模式的模拟。该系统不仅能够在主动呼吸模式下精确模拟快速呼吸、平静呼吸和深度呼吸&#xff0c;还能在被动模式下通过PID控制实现…

训练CDN基础代码

文章目录 时间整体流程训练细节小结 时间 从开始在平台上搭建到现在可以在平台上训练已经4天了 有GPU平台一般是autoDL平台&#xff0c;白嫖200元平台是&#xff1a;https://cloud.lanyun.net/ 整体流程 1.注册平台&#xff0c;以蓝耘为例子 卡从好变坏依次是&#xff1a;…

C语言:指针详解(5)

目录 一、sizeof()函数和strlen()函数的对比 1.sizeof()函数 2.strlen()函数 3.sizeof()函数和strlen()函数的对比 二、数组和指针笔试试题解析 1.一维数组 2.字符数组 &#xff08;1&#xff09;代码1 &#xff08;2&#xff09;代码2 &#xff08;3&#xff09;代码…

【数组、特殊矩阵的压缩存储】

目录 一、数组1.1、一维数组1.1.1 、一维数组的定义方式1.1.2、一维数组的数组名 1.2、二维数组1.2.1、二维数组的定义方式1.2.2、二维数组的数组名 二、对称矩阵的压缩存储三、三角矩阵的压缩存储四、三对角矩阵的压缩存储五、稀疏矩阵的压缩存储 一、数组 概述&#xff1a;数…

香橙派AIpro:体验强劲算力,运行ROS系统

文章目录 前言一、香橙派AIpro开箱及功能介绍1.1香橙派AIpro开箱1.2香橙派AIpro功能介绍 二、香橙派AIpro资料下载及环境搭建2.1资料下载2.2环境搭建2.3使用串口启动进入开发板2.4使用HDMI线接入屏幕启动 三、部署ROS系统四、香橙派AIpro的使用和体验感受 前言 本篇文章将带体…

sip协议栈简介

SIP协议栈简介 SIP协议栈流程 数据链路层&#xff1a;当SIP消息从网络中传输到达TCP/IP协议栈时&#xff0c;首先被接收到的是数据链路层的数据帧。数据链路层会对数据帧进行解封装&#xff0c;得到网络层的IP数据报。 网络层&#xff1a;网络层会对IP数据报进行解析&#xf…

js实现 JSON数据格式化的两种方法

本次方法不使用JS库直接采用原生JS 完整HTML代码如下&#xff0c;您可以复制代码然后&#xff0c;新建一个.html的网页进行保存即可体验 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><b…