Python: 将 RAW 图像转换为 PNG

Python: Convert RAW image to PNG

我正在努力使用 Python 处理原始图像以将其转换为 png 格式。 处理这些类型的数据对我来说是新手,我还不太了解其中的逻辑。

图像数据(根据相机文档)是 12 位、小端顺序和拜耳模式。 图像为 2048x1944 像素。 图片可用 here.

我在 中遵循了@Rotem 的回答,但我得到的图像基本上只是噪音。下面的代码。

知道如何处理这个问题吗?

import cv2
import numpy as np

width = 2048
height = 1944

with open('.raw_image.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].
    # bgr = cv2.cvtColor(bayer_im, cv2.COLOR_BayerGB2BGR)  # The result is BGR format with 16 bits per pixel and 12 bits range [0, 2^12-1].
    # bgr = cv2.cvtColor(bayer_im, cv2.COLOR_BayerRG2BGR)  # The result is BGR format with 16 bits per pixel and 12 bits range [0, 2^12-1].
    # bgr = cv2.cvtColor(bayer_im, cv2.COLOR_BayerGR2BGR )  # 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.png", colimg)

您发布的原始图像是每像素 12 位,但没有打包。
12位数据存储在每16位的高12位。

我们从文件的大小可以看出,每个像素有2个字节:
7962624 = 2048*1944*2

我们可以将uint16元素中的12位数据表示如下:

 ------------------------------------------------------------------------------- 
|    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |
| b11| b10| b9 | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |  0 |  0 |  0 |  0 |
 -------------------------------------------------------------------------------

与 12 位压缩格式相比,这种格式更易于使用...
我们不需要解包数据,我们可以将其视为每个像素 16 位。


代码示例:

import cv2
import numpy as np

width = 2048
height = 1944

with open("raw_image.ims_rgb", "rb") as rawimg:
    # Read the raw image as uint16 (two bytes per pixel).
    bayer_im = np.fromfile(rawimg, np.uint16, width * height).reshape(height, width)

    # The 12 bits of each pixel are stored in the upper 12 bits of every uint16 element.
    # The lower 4 bits of the uint16 element are zeros.
    # <--- 16 bits -->
    # ************0000
    # <-12 bits -><4->    
    #    data     zeros

    # Apply Demosacing.
    # It look like COLOR_BAYER_BG2BGR gives the best result, but it hard to tell from the given input.
    bgr = cv2.cvtColor(bayer_im, cv2.COLOR_BAYER_BG2BGR)  # The result is BGR format with 16 bits per pixel range [0, 2^16-1].

    # Apply manual "white balance".
    # The result image is greenish - this is normal for most cameras.
    # We may fix it by scaling up the red and the blue color channels.
    # It look like approximate scaling is about 1.5 for the red and about 1.25 for the blue.
    bgr[:, :, 0] = (bgr[:, :, 0].astype(np.float32)*1.25).clip(0, 65535).astype(np.uint16)
    bgr[:, :, 2] = (bgr[:, :, 2].astype(np.float32)*1.5).clip(0, 65535).astype(np.uint16)


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

    # Save the output as tiff with 16 bits per color component.
    cv2.imwrite("rgb16.tif", bgr)

我们可以看到,这是一张月亮的照片:

月亮不是最好的选择,因为我们无法验证颜色的正确性...

注:
我“手动”放大了红色和蓝色通道,使月亮变成灰色(而不是绿色)。
我们可以将缩放称为手动 White Balance.