我对Leopard Imaging M021 camera有一个非常好奇的问题。该公司并不真正支持linux,因此相机只会输出原始数据。我需要它在Beagleboard上运行,所以这就是为什么我要努力让它工作。
他们的员工告诉我它在YUY2 format(通常每像素16位),但高4位始终为0,低12位包含如下信息:
使用命令:
fswebcam --device /dev/video0 --resolution 1280x720 --dumpframe test.raw
我得到一个1,843,200字节长的文件,意思是1280x720图像,每像素2个字节(每像素16位)。
但是,我能够实际正确显示图像的唯一方法是使用IrfanView的RAW图像显示并将其设置为每像素12位,未标准化,使用GR的拜耳模式,以及垂直翻转。我不知道为什么需要垂直翻转,因为其他设置会显示偏斜的,奇怪的图像但不会翻转。然后我使用12 BPP并将其翻转。
我想,因为高4位始终为0,这导致它实际上是每像素12位而不是16位?
我需要知道文件中的字节是怎么回事才能自己编写转换算法(除非有人知道一个与IrfanView做同样事情的开源程序)。
使用Python,我制作了一个非常快速的脚本,只需将Y组件拉出并查看它(期望图像的灰度版本),但是我得到了一个非常扭曲的版本。我的代码有问题吗?我是否以错误的顺序提取数据?在IrfanView中,“未规范化”的意思是什么?为什么需要GR Bayer模式设置才能以RGB格式查看图像?
with open('test.raw', 'r+b') as f:
Y0 = []
U = []
Y1 = []
V = []
vals = [Y0, U, Y1, V]
val = f.read(1)
pixel = int.from_bytes(val, byteorder='big')
i = 0
vals[i].append(pixel)
while val:
i += 1
val = f.read(1)
if val != "":
pixel = int.from_bytes(val, byteorder='big')
vals[i % 4].append(pixel)
k = 0
with open("1.test", "w") as f:
for i in range(720):
for j in range(640):
f.write(str(Y0[k]))
f.write(" ")
f.write(str(Y1[k]))
f.write(" ")
k += 1
f.write("\n")
产生的垃圾图片:
我很感激任何人的帮助或建议。
编辑:
进一步可能有用的证据。如果我在matlab中运行它,只需将每2个字节视为精确的像素值:
fid = fopen('test.raw', 'r');
[I, count] = fread(fid , [1280, 720], 'uint16');
imagesc(I')
colormap(gray);
我得到这张图片:
我仍然缺少颜色信息,因为我只是忽视它。它仍然有点倾斜。但它看起来更好。如果放大,图像歪斜的图案是良好的像素,黑色像素,良好的像素,黑色像素等。是否有更了解相机和颜色的人知道这是什么指示?
编辑2:
在Mark Ransom的专家帮助下,我编写了一个很好的OpenCV脚本来读取数据,利用CV_BayerGR2RGB转换为RGB,并查看图像。它有效!
#include <vector>
#include <iostream>
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
int main() {
// Each pixel is made up of 16 bits, with the high 4 bits always equal to 0
unsigned char bytes[2];
// Hold the data in a vector
std::vector<unsigned short int> data;
// Read the camera data
FILE *fp = fopen("test.raw","rb");
while(fread(bytes, 2, 1, fp) != 0) {
// The data comes in little-endian, so shift the second byte right and concatenate the first byte
data.push_back(bytes[0] | (bytes[1] << 8));
}
// Make a matrix 1280x720 with 16 bits of unsigned integers
cv::Mat imBayer = cv::Mat(720, 1280, CV_16U);
// Make a matrix to hold RGB data
cv::Mat imRGB;
// Copy the data in the vector into a nice matrix
memmove(imBayer.data, data.data(), data.size()*2);
// Convert the GR Bayer pattern into RGB, putting it into the RGB matrix!
cv::cvtColor(imBayer, imRGB, CV_BayerGR2RGB);
cv::namedWindow("Display window", cv::WINDOW_AUTOSIZE);
// *15 because the image is dark
cv::imshow("Display window", 15*imRGB);
cv::waitKey(0);
return 0;
}
答案 0 :(得分:4)
您拥有的证据,首先是每个字节的高4位为0,并且您可以从Irfanview看到正确的彩色图片,这告诉我员工不正确且格式实际上并非如此YUY2 - 它的GRGB。
此代码应拉出绿色像素并将其加倍,以便您可以了解图像的外观。请注意,偶数行和奇数行将在以G和(R或B)开头之间交替。
with open('test.raw', 'r+b') as f:
raw_g = []
for y in range(720):
for x in range(1280//4):
if y % 2:
r1, r0, g1, g0, b1, b0, g3, g2 = f.read(8)
else:
g1, g0, r1, r0, g3, g2, b1, b0 = f.read(8)
g0 = g0 << 8 | g1
g2 = g2 << 8 | g3
raw_g.extend([g0, g0, g2, g2])
您可能希望在将这些值>> 4
写入灰度文件之前将其右移。
编辑:代码有一个剩余的错误(额外阅读),我没有意识到这些值是little-endian而不是big-endian。这些更改已应用于上面的代码示例。
由于值似乎有点暗,我还决定应用伽马校正 - 而不是n >> 4
我使用int(255.999 * (n / 4095.0)**(1/2.2))
我担心de-Bayering在一个简短的StackOverflow答案中有点超出了我的能力。