使用 OpenCV / Python 读取和保存 12 位原始拜耳图像

Reading and saving 12bit Raw bayer image using OpenCV / Python

我正在尝试使用 Python 和 openCV 读取并保存 12 位 Raw 文件。我正在使用的代码保存了一张图片,但保存的图片出现乱码/失真。

图像来自 FLIR Oryx Camera 23MP (5320x4600) 12Bit,像素格式为 BayerRG12P,应该是 RG GB 拜耳模式。

import cv2
import numpy as np

width = 5320
height = 4600

with open("aaa12packed.Raw", "rb") as rawimg:
   img = np.fromfile(rawimg, np.dtype('u1'), width * height).reshape(height, width)
   colimg = cv2.cvtColor(img, cv2.COLOR_BAYER_GR2RGB)
   cv2.imwrite("test.jpeg", colimg)

我上传了两个用于测试 debayer/demoisaic 的原始文件。您可以使用下面的 link 下载它们:

"RG12P.Raw"(这是 12 位常规)和"RG12packed.Raw"(这是 12 位压缩)

Raw files download

** 我的最终目标是使用 openCV 处理包含 RAW 图像序列的文件夹,并将它们 process/convert 转换为另一种高分辨率格式,如 DPX 10 位或同等格式。

我对此很陌生 - 感谢您的帮助。

编辑#1:添加屏幕截图,其中包含 FLIR 手册中有关所用 12 位格式的信息。

Link to 12 bit channel image formats (packed and regular)

我不确定您共享的两个文件之间的区别,但这里有一个相当快速的技术来读取和解压缩 12 位样本。我不太确定你到底想要什么,所以我放了很多调试代码和注释,这样你就可以看到我在做什么,然后你就可以微调了。

不要被代码的长度拖延,我在评论中真正编号的只有 4 行:

#!/usr/bin/env python3
# Demosaicing Bayer Raw image

import cv2
import numpy as np

filename = 'RG12P.Raw'

# Set width and height
w, h = 5320, 4600

# Read entire file and reshape as rows of 3 bytes
bayer = np.fromfile(filename, dtype=np.uint8).reshape((-1,3))    # LINE 1
print(f'DEBUG: bayer.shape={bayer.shape}')
for i in 0,1,2:
   print(f'DEBUG: bayer[{i}]={bayer[i]}')

# Make each 3-byte row into a single np.uint32 containing 2 samples of 12-bits each
bayer32 = np.dot(bayer.astype(np.uint32), [1,256,65536])         # LINE 2
print(f'DEBUG: bayer32.shape={bayer32.shape}')
for i in 0,1,2:
   print(f'DEBUG: bayer32[{i}]={bayer32[i]}')

# Extract high and low samples from pairs
his = bayer32 >> 12                                              # LINE 3
los = bayer32 &  0xfff                                           # LINE 4

print(f'DEBUG: his.shape={his.shape}')
for i in 0,1,2:
   print(f'DEBUG: his[{i}]={his[i]}')

print(f'DEBUG: los.shape={los.shape}')
for i in 0,1,2:
   print(f'DEBUG: los[{i}]={los[i]}')


# Stack into 3 channel
#BGR16 = np.dstack((B,G,R)).astype(np.uint16)

# Save result as 16-bit PNG
#cv2.imwrite('result.png', BGR16)

示例输出

DEBUG: bayer.shape=(12236000, 3)
DEBUG: bayer[0]=[119 209  36]
DEBUG: bayer[1]=[249  17  29]
DEBUG: bayer[2]=[ 49 114  35]
DEBUG: bayer32.shape=(12236000,)
DEBUG: bayer32[0]=2412919
DEBUG: bayer32[1]=1905145
DEBUG: bayer32[2]=2322993
DEBUG: his.shape=(12236000,)
DEBUG: his[0]=589
DEBUG: his[1]=465
DEBUG: his[2]=567
DEBUG: los.shape=(12236000,)
DEBUG: los[0]=375
DEBUG: los[1]=505
DEBUG: los[2]=561

我们可能会重复使用我在以下 中的回答。

OpenCV 不支持 DPX 10 位图像格式。
您可以使用 Tiff 格式或 16 位 PNG,但您可能需要将像素缩放 16(将 12 位放在 16 位的上部)。


代码示例:

import cv2
import numpy as np

width = 5320
height = 4600

with open("RG12P.Raw", "rb") as rawimg:
    # Read the packed 12bits as bytes - each 3 bytes applies 2 pixels
    data = np.fromfile(rawimg, np.uint8, width * height * 3//2)

    data = data.astype(np.uint16)  # Cast the data to uint16 type.
    result = np.zeros(data.size*2//3, np.uint16)  # Initialize matrix for storing the pixels.

    # 12 bits packing: ######## ######## ########
    #                  | 8bits| | 4 | 4  |  8   |
    #                  |  lsb | |msb|lsb |  msb |
    #                  <-----------><----------->
    #                     12 bits       12 bits
    result[0::2] = ((data[1::3] & 15) << 8) | data[0::3]
    result[1::2] = (data[1::3] >> 4) | (data[2::3] << 4)
    bayer_im = np.reshape(result, (height, width))

    # Apply Demosacing (COLOR_BAYER_BG2BGR gives the best result out of the 4 combinations).
    bgr = cv2.cvtColor(bayer_im, cv2.COLOR_BAYER_BG2BGR)  # The result is BGR format with 16 bits per pixel and 12 bits range [0, 2^12-1].

    # Show image for testing (multiply by 16 because imshow requires full uint16 range [0, 2^16-1]).
    cv2.imshow('bgr', cv2.resize(bgr*16, [width//10, height//10]))
    cv2.waitKey()
    cv2.destroyAllWindows()

    # Convert to uint8 before saving as JPEG (not part of the conversion).
    colimg = np.round(bgr.astype(float) * (255/4095))
    cv2.imwrite("test.jpeg", colimg)

结果: