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.
我正在努力使用 Python 处理原始图像以将其转换为 png 格式。 处理这些类型的数据对我来说是新手,我还不太了解其中的逻辑。
图像数据(根据相机文档)是 12 位、小端顺序和拜耳模式。 图像为 2048x1944 像素。 图片可用 here.
我在
知道如何处理这个问题吗?
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.