背景
ISP是Image Signal Processor的缩写,用于对image sensor采样来的原始图像数据(又叫RAW数据)做进一步处理,比如降噪、色域转换等操作,最终生成RGB格式的图像数据。
ISP是按照pipeline理念来组织上面提到的那些处理模块的,每个模块之间通过若干根信号线相连。这些信号线大部分用于传像素的每个bit,一小部分用于传控制信号,其中控制信号主要是帧开始
、行开始
、行数据开始
之类的同步信号。
为了方便定位pipeline的问题,ISP厂商通常会在某些模块之间接入一个DMA模块,用于将pipeline上的数据流写入到DDR内存。
这里有个问题,pipeline上的像素数据流,每个像素不一定是8bit,有可能是10bit或12bit甚至14bit,而且像素之间是紧挨着的,即没有为8bit对齐而填充0,因此DMA写到DDR里的像素数据无法用常规的16进制编辑器查看,必须转换成8bit对齐的格式才行。
转换方法
要想正确转换,先要弄清楚ISP DMA的工作原理
ISP DMA工作原理
ISP DMA跟系统DMA的区别:
- 不具备系统DMA的寻址能力,因为pipeline是数据流模型,没有地址总线。
- 不依赖软件触发,一般由硬件自动触发,因为pipeline有各种同步信号,DMA可以在收到特定信号后开始搬移。
- 当pipeline没有数据(此时DMA收到
行数据结束
信号),但系统总线的当前burst传输
还未填满时,DMA要自动填充数据,以保证系统总线的数据对齐。
ISP DMA的内存访问
假设pipeline的图像宽度是8像素,每个像素的位宽是12bit,系统总线位宽是64bit,则ISP DMA按下图进行内存访问
- 在收到
行数据开始
信号后,将pipeline上的像素数据依次写入内部shift register之类的寄存器,凑够一个beat
(即一次burst传输)后写入DDR - 如果一个像素放不进前一个beat的剩余bit,则拆分成2段后分别放入前一个beat和后一个beat,不会填充气泡(即padding数据),上图中第6个像素就被拆分成4bit和8bit了。
- 如果一行结束,但beat还未结束,则ISP DMA填充气泡,以保证beat时序。
- 收到下一个
行数据开始
信号后,重复上述过程。 - 收到
帧结束
信号后,发送中断,通知软件填写下一帧的DDR地址。
转换思路
弄清楚了ISP DMA的压缩写入过程,那转换就是个解压缩读取过程
- 首先根据
图像宽度
、像素位宽
、总线位宽
算出line_stride_width
,并换算成对应的字节数
n - 读取一行数据(即n字节)。
- 每次读取32bit或64bit数据,然后用移位指令提取出每个像素的数据,再存储到
unsigned short
型中,这样就自动加上了气泡,实现8bit对齐。 - 如果某个像素跨
beat
,则要小心处理。 - 当一行的所有像素都存储完毕,就读取下一行。
- 当所有行都读完,RAW数据文件解析就结束了。
unpack转换代码
我的这个repo实现了一种unpack方法,已经用10bit和12bit的像素宽度测试过,大家可以参考。
预览unpack后的RAW图
可以使用7yuv预览,加载RAW图后要修改以下界面设置:
- Bayer pattern的像素存储宽度
- 图像的宽度
- 图像的高度
- Bayer pattern的像素有效宽度
总结
跨beat
的处理很麻烦,关键是组织好unpack的上下文信息。
如果对像素的bit-order不确定,可以获取一份很暗的图像(像素值很小),再用16进制编辑器查看RAW文件,以32位或64位整型分组,如果每个像素值都很小,说明是小端,如果很大,说明是大段。