关于 raw 图像的理解

1、问题背景

在图像调试过程,当发现一个问题时,很多时候都要通过 dump raw图像来分析,如果raw图像上有,那就排除了是 ISP的处理导致。

下一步就是排查 sensor 或者镜头,这样可以有效的帮我们定位问题所在。

但遇到过有些 raw, 用工具打不开或者出图不对的情况,那可能是因为 raw 的存储格式不同导致,本文主要对 raw 的格式做下介绍说明。

2、问题分析

a. 什么是 raw

raw 数据是 sensor 输出的原始数据,常用的一般有raw8, raw10, raw12等,分别表示一个像素点有 8bit、10bit、12bit 数据。

是 sensor 将光信号转化为电信号时的电平高低的原始记录,单纯地没有进行任何处理的图像数据,即表现的是 sensor 和镜头本征特性的数据。

raw 数据在输出的时候是有一定顺序的,主要有四种: GRBG、RGGB、BGGR、GBRG,如下图为BGGR格式:

b. raw 分哪几种格式,有什么区别 ?

raw 一般分为 plain raw 和 mipi raw,主要是存储方式上的区别,如下图所示是 Plain raw10 的示意图。

10bit的raw,单个像素也就是10bit,需要两个字节(16bit)来存储。

那就会空出 6位用不到,因为有空余,这里就涉及到一个高位/低位对齐的问题,也就是存储数据时,右移6位低位对齐(如下图1所示),

左移6位高位对齐(如下图2所示)。这个主要看平台厂商对数据处理有什么要求,我司用的是高位对齐的数据,所以读取时,要有相应的移位操作才行。

如下图所示是 mipi raw10 的示意图,以大端存储方式为例,它是把4个像素放到5个字节(40bit)中,组成一个包去存储。

前4字节依次存放 raw10图像的前4个像素的后8位,4个像素的前2位依次存放在包的第5个字节中。

所以从存储方式来看,mipi raw 的存储方式是要比 plain raw 更节省内存。

c. 怎么正确查看 raw ?

一般raw图工具打开都会要求配置一下 raw 图尺寸、位宽、bayer格式、MSB/LSB,

但一般工具支持 plain raw 打开的居多,还有些并不支持MSB和LSB的选择,所以需要我们对raw 做一下处理。

如下是mipi raw 转 plain raw 、plain raw10 MSB 转LSB 的相关 python 代码,

分析代码的处理过程,也会加深我们关于raw图像的理解,

如下代码中使用的raw图像,可以在此链接获取:

https://pan.baidu.com/s/1H-s0YDcJCmeMxVKTTa3N6g?pwd=bxm9

提取码:bxm9

# plain raw10 的读取和 MSB转LSB的处理

import numpy as np

def read_plained_file(file_path_name,height,width,shift_bits):
    frame = np.fromfile(file_path_name, dtype="uint16")
    frame=frame[0:height*width]
    frame.shape = [height, width]

    # MSB ----> LSB,  LSB存低位数据,此时是高位对齐的,则右移代表向低位移了6位,数值是减小的状态。
    frame=np.right_shift(frame, shift_bits)  
    return frame

if __name__ == "__main__":
    file_name = "ov13b10_shading_4208X3120_MSB.raw"
    image = read_plained_file(file_name, 3120, 4208, 6)
    image = image / 1023

    # 将读取的 image 数据另存为 raw 数据
    output_file_name = "output_image.raw"

    # 将图像数据映射到 16 位无符号整数范围
    image_mapped = (image * 1023).astype('uint16')
    image_mapped.tofile(output_file_name)
    print(f"Image data has been saved to {output_file_name}")
# mipi raw10 转 plain raw10

import numpy as np
import math

def read_mipi10_file(file_path_name,height,width):
    # 单行长度的补齐
    new_width = int(math.floor((width + 3) / 4) * 4) #对四字节补齐
    packet_num_L = int(new_width / 4)
    width_byte_num = packet_num_L * 5 #单行byte长度
    width_byte_num = int(math.floor((width_byte_num + 7) / 8) * 8)#单行做8个字节补齐
    image_bytes=width_byte_num*height
    frame = np.fromfile(file_path_name, count=image_bytes,dtype ="uint8")
    print("b shape",frame.shape)
    print('%#x'%frame[0])

    frame.shape = [height, width_byte_num] #按字节整理的图像矩阵
    one_byte = frame[:,0:image_bytes:5]
    two_byte = frame[:,1:image_bytes:5]
    three_byte = frame[:,2:image_bytes:5]
    four_byte = frame[:,3:image_bytes:5]
    five_byte = frame[:,4:image_bytes:5]

    #数据转换防止溢出
    one_byte = one_byte.astype('uint16')
    two_byte = two_byte.astype('uint16')
    three_byte = three_byte.astype('uint16')
    four_byte = four_byte.astype('uint16')
    five_byte = five_byte.astype('uint16')

    #用矩阵的方法进行像素的拼接
    one_byte = np.left_shift(one_byte, 2) + np.bitwise_and((five_byte), 3)
    two_byte = np.left_shift(two_byte, 2) + np.right_shift(np.bitwise_and((five_byte), 12), 2)
    three_byte = np.left_shift(three_byte, 2) + np.right_shift(np.bitwise_and((five_byte), 48), 4)
    four_byte = np.left_shift(four_byte, 2) + np.right_shift(np.bitwise_and((five_byte), 192), 6)

    #重组帧
    frame_pixels=np.zeros(shape=(height,new_width))
    frame_pixels[:, 0: new_width:4]=one_byte[:, 0: packet_num_L]
    frame_pixels[:, 1: new_width:4]=two_byte[:, 0: packet_num_L]
    frame_pixels[:, 2: new_width:4]=three_byte[:, 0: packet_num_L]
    frame_pixels[:, 3: new_width:4]=four_byte[:, 0: packet_num_L]

    #裁剪无用的数据,这里表示的是0-2559列,包含完整的数据了。
    frame_out=frame_pixels[:,0:width]
    return frame_out

if __name__ == "__main__":
    file_name="imx335_2560x1440_GRBG_mipi.raw"
    image=read_mipi10_file(file_name,1440, 2560)
    image=image/1023

    # 将读取的 image 数据另存为 raw 数据
    output2_file_name = "output2_image.raw"
    # 将图像数据映射到 16 位无符号整数范围
    image_mapped = (image * 1023).astype('uint16')
    image_mapped.tofile(output2_file_name)
    print(f"Image data has been saved to {output2_file_name}")

参考资料:

大话成像-数字成像算法基础课程

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ChatGPT化身“AI间谍”:你在网上说的每句话都将被监控

大多数人使用 ChatGPT 就是用来聊天或者辅助学习、办公。 然而现在一些“间谍软件”公司正在探索如何使用ChatGPT和其他新兴的AI来监视社交媒体上的用户。 其中一家由俄罗斯企业家创立的Social Links的公司正使用 ChatGPT 作为助手,监控着用户在Facebook、Instagr…

CANdelaStudio 使用教程5 编辑DID

文章目录 在哪编辑DID的分类编辑快照数据添加 DID 在哪编辑 DID的分类 编辑快照数据 添加 DID

【数据中台】开源项目(2)-Moonbox计算服务平台

Moonbox是一个DVtaaS(Data Virtualization as a Service)平台解决方案。 Moonbox基于数据虚拟化设计思想,致力于提供批量计算服务解决方案。Moonbox负责屏蔽底层数据源的物理和使用细节,为用户带来虚拟数据库般使用体验&#xff0…

Windows安装mysql8.0

官网地址:MySQL :: MySQL Community Downloads 选择相应版本信息下载 默认选择点击下一步 默认配置点击next 设置密码 默认配置

一、Lua基础

文章目录 一、Lua是什么二、Lua特性(一)轻量级(二)可扩展(三)其它特性 三、Lua安装四、Lua应用 看到评论说,C让我见识了语言的严谨与缜密,lua让我见识到了语言的精巧与创新&#xff…

【Java】循环语句练习

文章目录 1. 计算5的阶乘2. 计算 1! 2! 3! 4! 5!3. 数字9 出现的次数4. 判定素数5. 求1-100之间的素数6. 求2个整数的最大公约数7. 计算分数的值8. 模拟登陆9. 输出乘法口诀表10. 求出0~999之间的所有“水仙花数”并输出11. 猜数字游戏🙈 1. 计算5的…

设计一个算法,将链表中所有结点的链接方向“原地”逆转,即要求仅利用原表的存储空间,换句话说,要求算法的空间复杂度为O(1)

设计一个算法,将链表中所有结点的链接方向“原地”逆转,即要求仅利用原表的存储空间,换句话说,要求算法的空间复杂度为O(1) 代码思路: 这里要求不用额外空间,那么就要考虑链表自身的…

web前端之vue和echarts的堆叠柱状图顶部显示总数、鼠标悬浮工具提示、设置图例的显示与隐藏、label、legend、tooltip

MENU 效果图htmlJavaScripstyle解析 效果图 html <template><div><div><div id"idStackedColumnChart" style"width: 100%; height: 680px"></div></div></div> </template>JavaScrip export default {…

【深度学习笔记】04 概率论基础

04 概率论基础 概率论公理联合概率条件概率贝叶斯定理边际化独立性期望和方差模拟投掷骰子的概率随投掷次数增加的变化 概率论公理 概率&#xff08;probability&#xff09;可以被认为是将集合映射到真实值的函数。 在给定的样本空间 S \mathcal{S} S中&#xff0c;事件 A \m…

Servlet知识汇总

小王学习录 Ⅰ. servlet程序导入依赖创建目录编写代码打包程序部署程序验证简化打包和部署Ⅱ. Servlet Api1. HttpServlet2. HttpServletRequest3. HttpServletResponseⅢ. Cookie 和session1. Cookie2. Session(会话)3. session 和 cookie的区别4. session 和 cookie的联系5. …

5、Hydra与Crunch基本使用

文章目录 一、关于Hydra与Crunch二、在操作机上使用Crunch生成用户名和密码字典三、在操作机上使用Hydra对靶机FTP登录密码进行字典攻击 一、关于Hydra与Crunch Hydra&#xff08;九头蛇&#xff09;是一个相当强大的暴力密码破解工具。该工具支持几乎所有协议的在线密码破解&…

免费 2 个月!ChatGPT-4 和 Claude 2 都能用

你好&#xff0c;我是 EarlGrey&#xff0c;一名双语学习者&#xff0c;会一点编程&#xff0c;目前已翻译出版《Python 无师自通》、《Python 并行编程手册》等书籍。 点击上方蓝字关注我&#xff0c;获取最新编程及AI干货、高赞工具和项目分享。 在后台回复“books”&#xf…

一网打尽异步神器CompletableFuture

Future接口以及它的局限性 我们都知道&#xff0c;Java中创建线程的方式主要有两种方式&#xff0c;继承Thread或者实现Runnable接口。但是这两种都是有一个共同的缺点&#xff0c;那就是都无法获取到线程执行的结果&#xff0c;也就是没有返回值。于是在JDK1.5 以后为了解决这…

深入解析Selenium动作链:精通点击、拖拽、切换等操作

背景&#xff1a; 一些交互动作都是针对某个节点执行的。比如&#xff0c;对于输入框&#xff0c;我们就调用它的输入文字和清空文字方法&#xff1b;对于按钮&#xff0c;就调用它的点击方法。其实&#xff0c;还有另外一些操作&#xff0c;它们没有特定的执行对象&#xff0…

关于vs code Debug调试时候出现“找不到任务C/C++: g++.exe build active file” 解决方法

vs code Debug调试时候出现“找不到任务C/C: g.exe build active file” &#xff0c;出现报错&#xff0c;Debug失败 后来经过摸索和上网查找资料解决问题 方法如下 在Vs code的操作页面左侧有几个配置文件 红框里的是需要将要修改的文件 查看tasks.json和launch.json框选&…

跟着chatgpt一起学|1.spark入门之MLLib

chatgpt在这一章表现的不好&#xff0c;所以我主要用它来帮我翻译文章提炼信息 1.前言 首先找到spark官网里关于MLLib的链接 spark内一共有2种支持机器学习的包&#xff0c; 一种是spark.ml,基于DataFrame的&#xff0c;也是目前主流的 另一种则是spark.mllib,是基于RDD的…

Python---函数的数据---拆包的应用案例(两个变量值互换,*args, **kwargs调用时传递参数用法)

案例&#xff1a; 使用至少3种方式交换两个变量的值 第一种方式&#xff1a;引入一个临时变量 c1 10 c2 2# 引入临时变量temp temp c2 c2 c1 c1 tempprint(c1, c2) 第二种方式&#xff1a;使用加法与减法运算交换两个变量的值&#xff08;不需要引入临时变量&#xff09…

【单调栈】子数组的最小值之和

import java.util.Deque; import java.util.LinkedList;/** 参考链接&#xff1a;https://leetcode.cn/problems/sum-of-subarray-minimums/solutions/1930857/gong-xian-fa-dan-diao-zhan-san-chong-shi-gxa5/* https://leetcode.cn/problems/sum-of-subarray-minim…

[NOIP2006]明明的随机数

一、题目 登录—专业IT笔试面试备考平台_牛客网 二、代码 set去重&#xff0c;再利用vector进行排序 std::set是一个自带排序功能的容器&#xff0c;它已经按照一定的规则&#xff08;默认是元素的小于比较&#xff09;对元素进行了排序。因此&#xff0c;你不能直接对std::s…

栈和队列OJ题

目录 【1】括号匹配问题 思路分析 易错总结 Stack.h&Stack.c手撕栈 isValid括号匹配 【2】设计循环队列 今天接着栈&队列OJ题目。 【1】括号匹配问题 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff…