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圖像,可以在公眾號后臺回復 "raw圖" 獲取。
# 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[:,05] two_byte = frame[:,15] three_byte = frame[:,25] four_byte = frame[:,35] five_byte = frame[:,45] #數據轉換防止溢出 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}")
審核編輯:黃飛
-
ISP
+關注
關注
6文章
476瀏覽量
51805 -
光信號
+關注
關注
0文章
438瀏覽量
27787 -
電信號
+關注
關注
1文章
817瀏覽量
20564 -
RAW
+關注
關注
0文章
21瀏覽量
3800
原文標題:關于 raw 圖像的理解
文章出處:【微信號:vision263com,微信公眾號:新機器視覺】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論