RAW 每像素 12 位数据格式
RAW 12 bits per pixel data format
我正在分析每像素 12 位、GRBG、Little Endian、1920x1280 分辨率的原始图像,但我对数据或 RGB 像素的存储方式感到困惑。图像大小为4915200字节,计算时为4915200/(1920x1280) = 2。这意味着每个像素占用2字节,2字节中的4位用于填充。我尝试使用十六进制编辑器编辑图像,但我不知道像素是如何存储在图像中的。如果您有任何想法,请分享。
您可以将图像加载到 Numpy 数组中并像这样正确地重新整形:
import numpy as np
# Load image and reshape
img = np.fromfile('Image_12bpp_grbg_LittleEndian_1920x1280.raw',dtype=np.uint16).reshape((1280,1920))
print(img.shape)
(1280, 1920)
然后您可以去马赛克和缩放以获得 16 位 PNG。请注意,我不知道你的校准系数所以我猜:
#!/usr/bin/env python3
# Demosaicing Bayer Raw image
#
import cv2
import numpy as np
filename = 'Image_12bpp_grbg_LittleEndian_1920x1280.raw'
# Set width and height
w, h = 1920, 1280
# Read mosaiced image as GRGRGR...
# BGBGBG...
bayer = np.fromfile(filename, dtype=np.uint16).reshape((h,w))
# Extract g0, g1, b, r from mosaic
g0 = bayer[0::2, 0::2] # every second pixel down and across starting at 0,0
g1 = bayer[1::2, 1::2] # every second pixel down and across starting at 1,1
r = bayer[0::2, 1::2] # every second pixel down and across starting at 0,1
b = bayer[1::2, 0::2] # every second pixel down and across starting at 1,0
# Apply (guessed) color matrix for 16-bit PNG
R = np.sqrt(r) * 1200
B = np.sqrt(b) * 2300
G = np.sqrt((g0+g1)/2) * 1300 # very crude
# Stack into 3 channel
BGR16 = np.dstack((B,G,R)).astype(np.uint16)
# Save result as 16-bit PNG
cv2.imwrite('result.png', BGR16)
关键词: Python, raw, image processing, Bayer, de-Bayer, mosaic, demosaic, de-mosaic, GBRG, 12-bit.
That means each pixel takes 2 bytes and 4 bits in 2bytes are used for padding
嗯,有点。这意味着每个 sample 都存储在两个连续的字节中,并带有 4 位填充。但在原始图像中,样本通常不是像素,不完全是像素。原始图像还没有被去马赛克,它们毕竟是原始的。对于 GRGB,拜耳模式如下所示:
文件中的内容是 12+4 位样本的 1920x1280 网格,排列顺序与像素相同,但每个样本只有一个通道,即与其在拜耳模式。
此外,颜色 space 可能是线性的,而不是 Gamma 压缩的。除非您对其进行逆向工程,否则色彩平衡是未知的。一个合适的解码器应该有一个校准过的颜色矩阵,但我没有。
我结合了这两件事并猜测了一个色彩平衡来做一个真正基本的解码(去马赛克不好,只是为了证明上面的信息可能是准确的):
使用此 C# 代码:
Bitmap bm = new Bitmap(1920, 1280);
for (int y = 0; y < 1280; y += 2)
{
int i = y * 1920 * 2;
for (int x = 0; x < 1920; x += 2)
{
const int stride = 1920 * 2;
int d0 = data[i] + (data[i + 1] << 8);
int d1 = data[i + 2] + (data[i + 3] << 8);
int d2 = data[i + stride] + (data[i + stride + 1] << 8);
int d3 = data[i + stride + 2] + (data[i + stride + 3] << 8);
i += 4;
int r = Math.Min((int)(Math.Sqrt(d1) * 4.5), 255);
int b = Math.Min((int)(Math.Sqrt(d2) * 9), 255);
int g0 = Math.Min((int)(Math.Sqrt(d0) * 5), 255);
int g3 = Math.Min((int)(Math.Sqrt(d3) * 5), 255);
int g1 = Math.Min((int)(Math.Sqrt((d0 + d3) * 0.5) * 5), 255);
bm.SetPixel(x, y, Color.FromArgb(r, g0, b));
bm.SetPixel(x + 1, y, Color.FromArgb(r, g1, b));
bm.SetPixel(x, y + 1, Color.FromArgb(r, g1, b));
bm.SetPixel(x + 1, y + 1, Color.FromArgb(r, g3, b));
}
}
我正在分析每像素 12 位、GRBG、Little Endian、1920x1280 分辨率的原始图像,但我对数据或 RGB 像素的存储方式感到困惑。图像大小为4915200字节,计算时为4915200/(1920x1280) = 2。这意味着每个像素占用2字节,2字节中的4位用于填充。我尝试使用十六进制编辑器编辑图像,但我不知道像素是如何存储在图像中的。如果您有任何想法,请分享。
您可以将图像加载到 Numpy 数组中并像这样正确地重新整形:
import numpy as np
# Load image and reshape
img = np.fromfile('Image_12bpp_grbg_LittleEndian_1920x1280.raw',dtype=np.uint16).reshape((1280,1920))
print(img.shape)
(1280, 1920)
然后您可以去马赛克和缩放以获得 16 位 PNG。请注意,我不知道你的校准系数所以我猜:
#!/usr/bin/env python3
# Demosaicing Bayer Raw image
#
import cv2
import numpy as np
filename = 'Image_12bpp_grbg_LittleEndian_1920x1280.raw'
# Set width and height
w, h = 1920, 1280
# Read mosaiced image as GRGRGR...
# BGBGBG...
bayer = np.fromfile(filename, dtype=np.uint16).reshape((h,w))
# Extract g0, g1, b, r from mosaic
g0 = bayer[0::2, 0::2] # every second pixel down and across starting at 0,0
g1 = bayer[1::2, 1::2] # every second pixel down and across starting at 1,1
r = bayer[0::2, 1::2] # every second pixel down and across starting at 0,1
b = bayer[1::2, 0::2] # every second pixel down and across starting at 1,0
# Apply (guessed) color matrix for 16-bit PNG
R = np.sqrt(r) * 1200
B = np.sqrt(b) * 2300
G = np.sqrt((g0+g1)/2) * 1300 # very crude
# Stack into 3 channel
BGR16 = np.dstack((B,G,R)).astype(np.uint16)
# Save result as 16-bit PNG
cv2.imwrite('result.png', BGR16)
关键词: Python, raw, image processing, Bayer, de-Bayer, mosaic, demosaic, de-mosaic, GBRG, 12-bit.
That means each pixel takes 2 bytes and 4 bits in 2bytes are used for padding
嗯,有点。这意味着每个 sample 都存储在两个连续的字节中,并带有 4 位填充。但在原始图像中,样本通常不是像素,不完全是像素。原始图像还没有被去马赛克,它们毕竟是原始的。对于 GRGB,拜耳模式如下所示:
文件中的内容是 12+4 位样本的 1920x1280 网格,排列顺序与像素相同,但每个样本只有一个通道,即与其在拜耳模式。
此外,颜色 space 可能是线性的,而不是 Gamma 压缩的。除非您对其进行逆向工程,否则色彩平衡是未知的。一个合适的解码器应该有一个校准过的颜色矩阵,但我没有。
我结合了这两件事并猜测了一个色彩平衡来做一个真正基本的解码(去马赛克不好,只是为了证明上面的信息可能是准确的):
使用此 C# 代码:
Bitmap bm = new Bitmap(1920, 1280);
for (int y = 0; y < 1280; y += 2)
{
int i = y * 1920 * 2;
for (int x = 0; x < 1920; x += 2)
{
const int stride = 1920 * 2;
int d0 = data[i] + (data[i + 1] << 8);
int d1 = data[i + 2] + (data[i + 3] << 8);
int d2 = data[i + stride] + (data[i + stride + 1] << 8);
int d3 = data[i + stride + 2] + (data[i + stride + 3] << 8);
i += 4;
int r = Math.Min((int)(Math.Sqrt(d1) * 4.5), 255);
int b = Math.Min((int)(Math.Sqrt(d2) * 9), 255);
int g0 = Math.Min((int)(Math.Sqrt(d0) * 5), 255);
int g3 = Math.Min((int)(Math.Sqrt(d3) * 5), 255);
int g1 = Math.Min((int)(Math.Sqrt((d0 + d3) * 0.5) * 5), 255);
bm.SetPixel(x, y, Color.FromArgb(r, g0, b));
bm.SetPixel(x + 1, y, Color.FromArgb(r, g1, b));
bm.SetPixel(x, y + 1, Color.FromArgb(r, g1, b));
bm.SetPixel(x + 1, y + 1, Color.FromArgb(r, g3, b));
}
}