表征我的RAW相机输出

时间:2014-09-12 01:13:22

标签: python colors camera computer-vision

我对Leopard Imaging M021 camera有一个非常好奇的问题。该公司并不真正支持linux,因此相机只会输出原始数据。我需要它在Beagleboard上运行,所以这就是为什么我要努力让它工作。

他们的员工告诉我它在YUY2 format(通常每像素16位),但高4位始终为0,低12位包含如下信息: YUYV description

使用命令:

fswebcam --device /dev/video0 --resolution 1280x720 --dumpframe test.raw

我得到一个1,843,200字节长的文件,意思是1280x720图像,每像素2个字节(每像素16位)。

但是,我能够实际正确显示图像的唯一方法是使用IrfanView的RAW图像显示并将其设置为每像素12位,未标准化,使用GR的拜耳模式,以及垂直翻转。我不知道为什么需要垂直翻转,因为其他设置会显示偏斜的,奇怪的图像但不会翻转。然后我使用12 BPP并将其翻转。

IrfanView Params

我想,因为高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")

产生的垃圾图片: enter image description here

我很感激任何人的帮助或建议。

编辑:

进一步可能有用的证据。如果我在matlab中运行它,只需将每2个字节视为精确的像素值:

fid = fopen('test.raw', 'r');
[I, count] = fread(fid , [1280, 720], 'uint16');
imagesc(I')
colormap(gray);

我得到这张图片: sort of decent looking picture but no color

我仍然缺少颜色信息,因为我只是忽视它。它仍然有点倾斜。但它看起来更好。如果放大,图像歪斜的图案是良好的像素,黑色像素,良好的像素,黑色像素等。是否有更了解相机和颜色的人知道这是什么指示?

编辑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;
}

1 个答案:

答案 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))

green channel with gamma correction

我担心de-Bayering在一个简短的StackOverflow答案中有点超出了我的能力。