RAW Camera Pipeline

[在此处输入文章标题]

 

 

Raw Camera的工作过程

文章说明

这只是一篇备忘文章,防止在时间的冲刷下忘掉这些基础知识。

二格式说明

2.1 Bayer pattern

         我们当前所有的数字化的Camera,都要感谢Bryce E.Bayer。是他开创了当前色彩缤纷包罗万象的数字图像传感器的先河。是他最先想到的用Color Filter的方式来获取现实世界的彩色投影(来自维基百科)。这些红、绿、蓝色是盖在感光三极管上面的,作用就是将环境光分离出三个颜色来。如图这个filter Pattern叫做GBRG,这个顺序很关键,Demosaic的时候需要重点用到。

 

Bayer_matrix.svg.png

2.2 RAW格式

         RAW是一种原始数据的格式,就是说,基本上保留了图像形成时的样子。当然,为了最大化利用存储空间以及MIPI传输方便,这里做了一些数据穿插的小动作。比如说,这是RAW10格式的图片,RAW10意味着AD用的是10bits精度,所以一个Pixel得到的数据是10bits。存储/传输的时候,一般会采用16Bytes存储12Pixels的方式。RAW图是没有颜色的,因为它只是感光三极管将环境光转化成模拟电压然后经过AD数字化的东西。

题外话:RAW图的大小怎么计算的?

我们来看下一个13M3120*4208)的图像的大小,17,,612,800字节。但是按照3120*4208*10/8来计算也仅仅是16,411,200字节,缺失的大小存储的是什么呢?^-^ 这里面涉及到三个方面,一是图像宽度的16字节对齐,二是图像高度的64行对齐,三是图像尺寸的4K对齐。这样计算出来的值如下:

 

实际的图片大小:

一个字节都不少,我喜欢这个有逻辑有确定结果的世界。

底电流

         也叫暗电流。意思是说环境全黑的时候的电流。因为当前三极管的制造工艺,决定了这个东西肯定会存在。从这幅标有三极管内部无源寄生器件的图上能看到内部有多个寄生电容存在,这会导致在输入为0的情况下,输出会有一个小电压存在,这些电容充电的过程中还会有一些电流产生。这些先按下不表,因为这些三极管的基础知识要写完最少两张A4纸。

 

tras.png

         暗电流表现在图像上是什么样子的呢?我们拍摄了一张全黑环境下的RAW图,如下可以看到上面有很多亮度不一的点,这就是暗电流的图像。这里面会夹杂着一些坏点,过会会看到。

         当然,这样看起来可能不是太直观,我们将其转化到三维上面看下,可以看出来,绝大部分的像素值在8左右,理想三极管应该是0的。

         我们将整帧图像减去一个暗电流的数值(均值是14.8,就会看到图像干净了很多。这上面的那些凸起来的点我认为就是坏点了。从这两幅对比图上来看,去除暗电流可以减掉底噪声,但是也不能去除太多,过大的设置底电流值会导致图像信息丢失;过小的话图片会整体偏白并且噪声过高。

坏点和降噪

         通过底电流后,我们发现有一些像素会比较个性,这时候我们首先要找出来这些像素,标记为坏点,在我的程序中是使用拉普拉斯算子找到这些坏点的。在RAW空间内,降噪不可以太多。首先,因为这是在时域空间,可以采用的降噪手法很有限;其次,RAW图上时域空间降噪会对后续的pipeline影响深远。从信息量上来说,前端损失的信息量越大,后续的处理就越难,所以一般会前端以保持信息为主。降噪现在还是主要依靠频域处理,感谢傅里叶。坏点一般分为冷点和热点。真正的坏点永远是坏点,我们标记出来就好了。怕的是有一些点平时表现不错,Sensor温度高一些后就变坏了,那我们只能降温和降噪了。不确定性,真可怕。

filter =

[

    0    -1     0

   -1     4    -1

    0    -1     0

];

经过滤波器后,我们可以看到这些坏点已经被标记出来,以前是将坏点位置直接存储下来,以后该点的数据不采用,直接周边均值补上。

然后使用原图上周边同Color Filter的像素补充这个位置。我们可以看到经过去除坏点后,RAW图像上面异常像素的数目降到了2个(4208*3120),并且这两个异常像素的数值最大是3.

Rolloff

         lensshading是由于透镜成像的原理决定的,所以在很长一段时间里这个东西也会一直存在,只是会逐渐的弱化。我们来看下什么是lens shading

 

         肉眼能明显看到中间亮四周暗。反映到三维图像上是这样子的:

         ColorShading指的是这四个channel的鸡蛋壳不重合,所以周边会有偏色,但是经过rolloff补偿后,就一致了。

         我们按照这个形状给他一个反向的增益,将其补平,但是补充的太平也不好,因为周边信息量本来就小,这里的补平仅仅是数字上的放大,相当于数字增益,若是调整过大,会导致四周噪声严重,(原始两个Pixel之间差异是1,肉眼不可区分;放大十倍,变成了10,我看见了)。使用的增益如下图所示:

 

然后补充完成的图像如下:

仔细看四角,能看到好多小颗粒噪声,这就是补偿过高(100%)的后果;所以一般会采用70% ~ 80%的补偿目标,这样可以在肉眼可接受的shading区间内寻找到噪声的最佳平衡点。以前有一个很牛很牛的人说,Tuning其实就是Balance,不懂Balance的产品经理不是好人。

Demosaic

         我们补完的图像其实还是RAW空间,需要进行Demosaic将其转化为RGB空间内。这一步我现在用的是非向量转换方式,太挫了,正在找相应的转换矩阵......你看数学多么重要...... 之前的经验告诉我,向量化的运算相较于这种指针方式的运算速度会提升十倍以上。   我们有四个channel,分别是BGbGrRDemosaic我采用的是4邻域方式,就是参考周边四个相同Color Filter的像素信息来补全当前的数据。这一块实在是写的太挫了,我实在是不好意思在这块BB了。计算方式如下:

白平衡参考点运算

         我们选取图像的一部分,当然也可以是全部的像素值,认为他是灰度的。然后根据反向补平原理,算出他的增益来。

         我们选取位置如下:

Rg =

 

   1.3895

 

 

Bg =

 

   1.6336

然后将增益作用到RGB空间的图像上,得到如下图,可以看到白色正了。整体图像的颜色也不是那么绿了。

Gamma调整

我认为Gamma是一个一一对应的变换表,输入像素值经过查表(可以有三张表,RGB)得到输出值。维基百科的定义见链接。这个表很重要,因为它直接关系到图像的动态范围。下面的三幅图,分别是两条Gamma曲线,和对应的效果图。可以明显看到,当Gamma在暗区较高(高于1:1直线很多)的时候,图像整体会偏白。

Ps:题外话,Gamma是作用在RAW空间的。而RAW空间是很暗的,极其特别的情况最亮部分的亮度(拍太阳)会高于200。所以绝大部分的时候我们用到的是Gamma曲线的中下部分,这一块很关键,在调试的时候,要重点进行这一块的修改。至于200以上的部分就要看实际的需求了。

CC校准

Color Correction这一步,最主要的目的是将颜色还原到最接近真实的情况。所以在我的工具中首先会选定色卡区域,然后将24的颜色块切出来进行均值计算,得到一个6*4的矩阵。色卡是有标准值的:

我们校准的时候,得到的其实是一个3*3矩阵,他的作用就是将RGB进行变换。

[1 3] * [3 3 ] = [3 1];[3 1]' = [1 3];

剩下的工作就是将矩阵进行迭代,计算色卡,迭代寻找最小的色差。就固定下来。

Color Correction

         这一步我们会用到CC校准中得到的3*3的转换矩阵,类似这个样子:

 

color_correction =

[

   1.3000   -0.1500   -0.1500

  -0.1500    1.3000   -0.1500

  -0.1500   -0.1500    1.3000

];

         按照矩阵乘法规则,这样乘完后,对应的RGB都会增加30%,饱和度会提升,但是色彩没有转换。这个矩阵仅仅是示例。

 

十一 Up Luma

         为了观看方便并且更加接近实际的相机显示效果,我们在这里将亮度进行一个提升。我们的目标是将最亮色块(白块19)提升到200

这样图像的亮度就上来了,更加接近数字增益生效后的效果。

十二 Color Conversion

         在保证了颜色的准确性后,我们需要按照产品定义将颜色的饱和度和色彩倾向做个调整。这两个目的在YUV空间是最容易做的,当然,要是仅仅调整饱和度的话,我个人认为在HSV空间最合适。这里面就涉及到一个RGB2YUV的转换:

平台端在这一块做了一小块修改,他不是按照标准的方式转换的,而是在转换的时候,将CbCr两个转换算子做了微调,这样在YUV2RGB转换回来的时候,你会发现颜色变了。如果按照标准的方式进行RGB2YUV ,然后YUV2RGB,你得到的图像是近乎一致的。但是修改后的转换方式你转回来后就成了右图的熊样,原谅我这块还在摸索,半瓶子水,半瓶醋……

十三 小波降噪

         这块写的很粗糙,因为我没完全懂,我很惭愧。

         小波降噪是在频率域进行的噪声处理,这要感谢傅里叶。当年学习数学时,老师讲得很好,但是没有告诉我傅里叶变换有啥鸟用。等工作了,发现处处都有傅里叶的影子时,我又拿起了课本……感谢中国教育,感谢我的老师。

         小波降噪的原理我还不太明白,虽然网上很多讲解的,但饭菜好不好吃,吃了才知道。下面这个图片,来源于如下程序:

         我只是简单的将小波转换后的小波分解矢量中,最后一维全部置为0,然后将它再恢复成图像,能看到噪声明显减小了(下方两图):

 

         我看下MATLAB中自带的小波程序,可以将小波分解图形化,可以看到LL的图像基本不含噪声,但是细节也丢失的很多。然后逐层的噪声比例会越来越高。

 

下面这幅图是小波分解矢量中,右下角的图像,可以看到基本全是噪声了,我就是简单的将这块全部置为0,就能看到噪声明显减小。


### Android Camera Raw Data Injection Implementation In the context of Android development, raw data injection (RDI) into the camera pipeline is not directly supported by standard APIs provided by the Android SDK. However, developers can achieve similar functionality through custom implementations or using specialized hardware interfaces. #### Custom Camera Application Development To implement raw data injection within an Android application: For injecting raw image data into a camera stream, one approach involves creating a custom camera application that bypasses the default camera interface and interacts with lower-level components. This requires access to native libraries and possibly modifications at the device driver level[^1]. ```java // Example pseudo-code for handling custom camera operations public class CustomCameraActivity extends AppCompatActivity { private Camera mCamera; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Initialize camera object here try { injectRawData(byte[] rawData); // Hypothetical method for raw data injection } catch (Exception e) { Log.e("CustomCamera", "Failed to inject raw data"); } } private void injectRawData(byte[] data) throws Exception { // Code to interact with low-level API or drivers would go here } } ``` This code snippet demonstrates how one might structure a function call intended to perform raw data injection; however, actual implementation details depend heavily on specific requirements and available resources. #### Using Frameworks like Dagger for Dependency Management When building complex applications involving multiple modules such as those required for advanced camera features including RDI, frameworks like Dagger provide efficient dependency injection mechanisms which help manage dependencies between different parts of the system efficiently[^2]. While Dagger itself does not facilitate direct interaction with camera hardware, it plays a crucial role in organizing project architecture so that integrating third-party solutions becomes easier when necessary. --related questions-- 1. What are some common challenges faced while developing custom camera apps? 2. How do manufacturers typically enable support for raw data processing in their devices? 3. Can you recommend any open-source projects focusing on enhancing Android's camera capabilities? 4. Are there alternative methods besides modifying the kernel to gain deeper control over the camera module?
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

eric_wang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值