Basler USB Camera字节缓冲区到图像的转换

Posted

技术标签:

【中文标题】Basler USB Camera字节缓冲区到图像的转换【英文标题】:Basler USB Camera byte buffer to image conversion 【发布时间】:2018-04-25 13:57:08 【问题描述】:

我有 Basler acA3800 USB 相机。

            IGrabResult grabResult = camera.StreamGrabber.RetrieveResult(5000, TimeoutHandling.ThrowException);
            // Image grabbed successfully?
            if (grabResult.GrabSucceeded)
            
                byte[] buffer = grabResult.PixelData as byte[];
                ImageWindow.DisplayImage(0, grabResult);

                pictureBox1.Image = ImageFromRawBgraArray(buffer,3840,2748,PixelFormat.Format8bppIndexed);
                MessageBox.Show(grabResult.PixelTypeValue.ToString());
            

此代码部分显示图像自身窗口。

我有捕获图像的像素数据。原始图像很好,但是当我将其转换为图像时,它已损坏。这是我的转换函数。

    public Image ImageFromRawBgraArray(byte[] arr, int width, int height, PixelFormat pixelFormat)
    
        var output = new Bitmap(width, height, pixelFormat);
        var rect = new Rectangle(0, 0, width, height);
        var bmpData = output.LockBits(rect, ImageLockMode.ReadWrite, output.PixelFormat);

        // Row-by-row copy
        var arrRowLength = width * Image.GetPixelFormatSize(output.PixelFormat) / 8;
        var ptr = bmpData.Scan0;
        for (var i = 0; i < height; i++)
        
            Marshal.Copy(arr, i * arrRowLength, ptr, arrRowLength);
            ptr += bmpData.Stride;
        

        output.UnlockBits(bmpData);
        return output;
    

我认为这与像素类型有关。我选择了 PixelFormat.Format8bppIndexed 的像素格式。其他的不工作。

                MessageBox.Show(grabResult.PixelTypeValue.ToString());

这个消息框给了我像素类型。上面写着“BayerBG8”。这是什么意思?我应该怎么做才能获得清晰的图像?

【问题讨论】:

BayerBG8 的快速 google 找到了我 this page。在上面查找BayerBG2BGR,您会发现使用图像上的特定索引作为 R、G 和 B 是一种相当特殊的转换。您需要提前对字节数组进行某种处理。 请注意the camera's official manual document,第 7.14 节“颜色创建和增强”,详细说明了数据的保存方式。 【参考方案1】:

你得到的奇怪颜色是因为Format8bppIndexed 是调色板,你从不编辑调色板,这意味着它保留了默认生成的 Windows 调色板。但在您的情况下,此调色板无关紧要,因为图像 不是 8 位索引格式;需要对其进行处理以将其转换为 RGB。

BayerBG8 的快速 google 找到了我 this page。那里的拜耳部分显示,在图像上使用特定图案的索引作为 R、G 和 B 是一种相当特殊的转换。

***有a whole article 介绍了这些东西的一般处理方式,但this YouTube video 显示了基础知识:

注意这是一个滑动窗口;对于第一个像素,颜色是

R G
国标

但对于第二个像素,它们将是

G R
B G

向下一行,第一行将使用

国标
RG

您最终会得到一个比给定尺寸小一个像素的图像,因为每行的最后一个像素和最后一行的所有像素都没有获得完整所需的相邻数据像素数据。显然有更高级的算法可以解决这个问题,但对于这种方法,我将仅介绍基本的滑动窗口方法。

public static Byte[] BayerToRgb(Byte[] arr, ref Int32 width, ref Int32 height, ref Int32 stride, Boolean greenFirst, Boolean blueRowFirst)

    Int32 actualWidth = width - 1;
    Int32 actualHeight = height - 1;
    Int32 actualStride = actualWidth*3;
    Byte[] result = new Byte[actualStride*actualHeight];
    for (Int32 y = 0; y < actualHeight; y++)
    
        Int32 curPtr = y*stride;
        Int32 resPtr = y*actualStride;
        Boolean blueRow = y % 2 == (blueRowFirst ? 0 : 1);
        for (Int32 x = 0; x < actualWidth; x++)
        
            // Get correct colour components from sliding window
            Boolean isGreen = (x + y) % 2 == (greenFirst ? 0 : 1);
            Byte cornerCol1 = isGreen ? arr[curPtr + 1] : arr[curPtr];
            Byte cornerCol2 = isGreen ? arr[curPtr + stride] : arr[curPtr + stride + 1];
            Byte greenCol1 = isGreen ? arr[curPtr] : arr[curPtr + 1];
            Byte greenCol2 = isGreen ? arr[curPtr + stride + 1] : arr[curPtr + stride];
            Byte blueCol = blueRow ? cornerCol1 : cornerCol2;
            Byte redCol = blueRow ? cornerCol2 : cornerCol1;
            // 24bpp RGB is saved as [B, G, R].
            // Blue
            result[resPtr + 0] = blueCol;
            // Green
            result[resPtr + 1] = (Byte) ((greenCol1 + greenCol2)/2);
            // Red
            result[resPtr + 2] = redCol;
            curPtr++;
            resPtr+=3;
        
    
    height = actualHeight;
    width = actualWidth;
    stride = actualStride;
    return result;

参数greenFirstblueRowFirst 表示绿色是否是图像上第一个遇到的像素,以及蓝色像素是在第一行还是第二行。对于您的“BG”格式,这两个都应该是 false。

根据此结果,调整宽度、高度和步幅后,您可以使用已使用的方法将其转换为新图像,但使用Format24bppRgb 作为像素格式。

我个人使用一种更高级的方法,该方法将输入步幅考虑在内,并且可以处理索引内容。如果你有兴趣,那个方法can be found here。

请注意,上面的去马赛克方法非常基本,将显示many of the expected artifacts。有更先进的方法可以分析数据并根据图像的拍摄方式获得更准确的结果,但您可能需要进行大量研究才能弄清楚所有这些并自己实施。

这是我做的一个小测试,从a Bayer-filtered image I found online(第一张图片)开始,我将其转换为 8 位数组(此处显示为灰度;第二张图片)。如您所见,我自己的去马赛克(第三张图片)远不如他们从中得到的校正版本(第四张图片)准确,而且值得注意的是,它小了一个像素,因此显示了白色边框。

(请注意,与上面的示例不同,此图像以绿色像素开头,这意味着必须调整解码参数)

【讨论】:

以上是关于Basler USB Camera字节缓冲区到图像的转换的主要内容,如果未能解决你的问题,请参考以下文章

有人用arm开发板用UVC驱动的USB camera采集到640*480的视频过吗?

基于FPGA+USB3.0的UVC Camera实现方案

在 WPF 中以高刷新率显示字节数组图像

camera驱动

camera的构成

Basler巴斯勒 acA2500-14gc Gige接口的那种 我装了Pylon IP以及Pylon Viewer 插上线为什么找不到设备啊