S32V234 软件系列 - ISP | S32V 应用层 Debayer 操作技巧

在处理 RAW 数据转换成 RGB 信号的过程,一般情况下都是通过 ISP 核做 Debayer 运算。在 DS 中直接通过调用 debayer 算子,便可以实现在 ISP 核中将 RAW12 的数据转换成 RGB888 的数据,然后再将其存储到 DDR 中,应用层上可以直接调用 RGB888 的数据,无需再做转换。


但是,为了更好地剖析 Debayer 是如何转换数据的,下面会直接在应用层上实现插值处理,将 RAW12 的数据转换成 RGB888 的数据。

一、 制作 graph

      需要制作一个 graph 将从 mipicsi 口接收到的 RAW 数据直接存放到 DDR 中,且输出是8 bits 和单通道。

1.1 搭建 Graph

          

1.2 配置Graph

        1.2.1 配置 MIPICSI 以及 Port [0]

         

 
          

           


           由于这里用的是 OV9716,输出数据格式为 RAW12 ,而且分辨率为 1288*728。

        1.2.2 配置 SRAM

               
                  


        1.2.3 配置 IPUS 及端口

          (1) A[0] 端口

               

 

          (2) OUT[0] 端口

 
          


          (3) IPUS

          

               (

                     Parameters:

                            { D_IPUS_SYN_HOST_INACFG_OFF, 0x00000100 },

                            { D_IPUS_SYN_HOST_XCFG_OFF, (1280 << 16) | 0x1 },

                            { D_IPUS_SYN_HOST_OUTCFG_OFF, 0x00000100 },

                            { D_IPUS_SYN_S_CH0_CFG_INA_OFF, 0x00058000 },

                            { D_IPUS_SYN_S_CH0_CFG_OUT_OFF, 0x10000000 },

                 )

 

        1.2.4 配置 SRAM

    

           

        1.2.5 配置 DDR

          

二、抓取图像 Buffer 分析

      把抓取到的 Buffer 文件通过 7yuv 软件查看(由于 7yuv 中没有 Bayer RGGB 8-bit 的选择,所以这里选择的是 16 bits 的来进行观察)通过图片显示,可以确定从 DDR 中抓取到的图像数据流是 RAW格式的,而且分辨率为 1280*720

          

三、转换数据格式

      由于 SDI_Frame 中定义的用于存放图像数据的类是 SMat 的类型,可以通过 output_umat.getMat(vsdk::ACCESS_RW | OAL_USAGE_CACHED).data 获取到数据的头指针,但是由于我们还需要进行插值处理,这里并不能直接操作 SMat 中的数据,特别是需要进行嵌套循环的时候,直接操作会导致程序挂掉或者跑飞。

 

        具体实现如下:

              ① uint8_t  r_val[WIDTH*HEIGHT];

              ② memcpy(r_val,Frame_Umat.getMat(vsdk::ACCESS_RW | OAL_USAGE_CACHED).data,

                             WIDTH*HEIGHT);

 

        做这个转换主要是将 pixel 的数据提取出来,不直接操作 SMat 中的数据,避免系统在提取时出现错误



四、分析数据

      查看手册可知 OV9716 中的感光元件排布如下图。

               

 

      在进行插值处理的时候,需要分奇数行和偶数行的处理。

      (1) 奇数行插值处理

            ① 处理第一个 pixel R 的时候,需要先取出红框内的右下角的 pixel B,然后再取出 pixel G ,再与左上角 pixel R 组成一个 RGB888 的 pixel


                 

 

             ② 处理第二个 pixel G 的时候,需要先取出红框内的 pixel B ,然后再取出 pixel G ,再与右上角 pixel R 组成一个 RGB888 的 pixel

    

                 

 

 

        (2) 偶数行插值处理

              ① 处理第一个 pixel G 的时候,需要先取出红框内的右上角的 pixel B,然后再取出 pixel G ,再与左下角的 pixel R 组成一个 RGB888 的 pixel

 

                 

               ② 处理第一个 pixel B的时候,需要先取出 pixel B,然后再取出右上角的 pixel G ,再与右下角的 pixel R 组成一个 RGB888 的 pixel

 

                  

 

         (3) 按照这种取值方式,到最后可能会出现最后第 720 行和第 3840 行的数据出现问题,所以需要在程序中优化这部分的 pixel,避免画面边缘出现毛刺

 

 

 五、代码分析

     创建一个 WIDTH*HEIGHT*3 的数组作为插值处理后的数据载体,然后通过 WIDTH*HEIGHT*3 次的循环,对 RAW 格式的数据进行插值处理,并组合形成 RGB888 格式的数据形式。中间需要分情况做赋值操作,奇偶行的操作以及第奇数个 pixel 和第偶数个pixel 的操作都是不一样的,同时,对于第 720 行和第 3480 列程序中全部写零,避免由于没有操作到而画面出现毛刺现象。

代码如附录所示。

 

六、转换效果

      可以成功显示画面以及物体的颜色。

               

【参考资料】

博文操作都是参考 NXP 的 DS 软件操作手册:
[1] 《 HOWTO_Create_An_ISP_Project_From_Example_in_S32DS_for_Vision 》 操作手册
[2] 《 HOWTO_Create_An_ISP_Project_From_Existing_VSDK_Graph_in_S32DS_for_Vision 》操作手册
[3] 《 ISP_graph_tool_in_depth_tutorial 》 操作手册
[4] 《 S32DS_Vision_User_Guide 》 操作手册


附录

插值处理代码:

附录
插值处理代码:
for(int j = 0;j< 720 ;j++){
for(int i = 0; i < 3840; i = i+3){
int thread_index = 3840*j+i;
int data_index = i/3;
scan_index = false;
if(i == 3837){
g_val[thread_index+2] = 0;
scan_index = true;
}

if( j%2 == 0){
if(data_index%2 == 0){
if(r_val[data_index+1+(j+1)*1280] >= 235)
g_val[thread_index] = 255 ;
else
g_val[thread_index] = r_val[data_index+1+(j+1)*1280] + 20;
if(r_val[data_index+1+j*1280] < 40 )
g_val[thread_index+1] = 0;
else
g_val[thread_index+1] = r_val[data_index+1+j*1280] - 40;
if(scan_index == false){
if(r_val[data_index+1+j*1280] >= 245 )
g_val[thread_index] = 255 ;
else
g_val[thread_index+2] = r_val[data_index+j*1280] + 10;
}
}
else{
if(r_val[data_index+(j+1)*1280] >= 235)
g_val[thread_index] = 255 ;
else
g_val[thread_index] = r_val[data_index+(j+1)*1280] + 20;
if(r_val[data_index+j*1280] < 40)
g_val[thread_index+1] = 0 ;
else
g_val[thread_index+1] = r_val[data_index+j*1280] - 40;
if(scan_index == false){
if(r_val[data_index+1+j*1280] >= 245)
g_val[thread_index+2] = 255 ;
else
g_val[thread_index+2] = r_val[data_index+1+j*1280] + 10;
}
}
}
else{
if( j == 719 ){
g_val[thread_index] = 0;
g_val[thread_index+1] = 0;
g_val[thread_index+2] = 0;
}
else{
if(data_index%2 == 0){
if(r_val[data_index+1+j*1280] >= 235)
g_val[thread_index] = 255 ;
else
g_val[thread_index] = r_val[data_index+1+j*1280] + 20;
if(r_val[data_index+1+(j+1)*1280] < 40)
g_val[thread_index+1] = 0 ;
else
g_val[thread_index+1] = r_val[data_index+1+(j+1)*1280] - 40;
if(scan_index == false){
if(r_val[data_index+(j+1)*1280] >= 245)
g_val[thread_index+2] = 255 ;
else
g_val[thread_index+2] = r_val[data_index+(j+1)*1280] + 10;
}
}
else{
if(r_val[data_index+j*1280] >= 235)
g_val[thread_index] = 255 ;
else
g_val[thread_index] = r_val[data_index+j*1280] + 20;
if(r_val[data_index+(j+1)*1280] < 40)
g_val[thread_index+1] = 0 ;
else
g_val[thread_index+1] = r_val[data_index+(j+1)*1280] - 40;
if(scan_index == false){
if(r_val[data_index+1+(j+1)*1280] >= 245)
g_val[thread_index+2] = 255 ;
else
g_val[thread_index+2] = r_val[data_index+1+(j+1)*1280] + 10;
}
}
}
}
}
}

 

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★文明上网,请理性发言。内容一周内被举报5次,发文人进小黑屋喔~

评论