Python:将 RAW 图像转换为 PNG

发布于 2025-01-16 20:44:22 字数 2346 浏览 5 评论 0原文

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

图像数据(根据相机文档)是 12 位、具有拜耳模式的小端序。 图像尺寸为 2048x1944 像素。 图片位于此处

我在这里遵循了@Rotem的答案,但是我的图像get 基本上只是噪音。代码如下。

关于如何解决这个问题有什么想法吗?

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)

I am struggling with processing a raw image with Python to convert it to png format.
Processing these type of data is new to me and I don't quite understand the logic yet.

The image data (as per the camera doc) is 12 bit, little-Endian order with a Bayer pattern.
The image is 2048x1944 px.
Image available here.

I have followed @Rotem answer in here but the image I get is basically just noise. Code below.

Any idea on how to approach this?

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

花开雨落又逢春i 2025-01-23 20:44:22

您发布的原始图像为每像素 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)

我们可以看到,这是一张月亮的图片:
输入图片此处描述

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

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

The raw image you have posted is 12 bit per pixel but without packing.
The 12 bits data are stored in the higher 12 bits of every 16 bits.

We can see by the size of the file, that there are 2 bytes per pixel:
7962624 = 2048*1944*2

We may represent the 12 bits data in uint16 element as follows:

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

This format is much more simple to work with compared to the 12 bits packed format...
We don't need to unpack the data, we may look at it as 16 bits per pixel.


Code sample:

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)

We can see, it's a picture of the moon:
enter image description here

The moon is not the best choice, because we can't verify the correctness of the colors...

Note:
I "manually" scaled up the red and the blue color channels to make the moon gray (instead of green).
We may refer the scaling as manual White Balance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文