首页 > 解决方案 > 将 12 位单色图像转换为 8 位灰度

问题描述

我有一个用于嵌入式开发的图像传感器板,我需要捕获图像流并以 8 位单色/灰度格式输出它们。成像器输出为 12 位单色(每个像素占用 2 个字节)。

在代码中,我有一个IntPtr包含 12 位图像数据的内存缓冲区,我必须从中提取该数据并将其转换为 8 位图像。这在内存中表示如下(用强光激活像素):

在此处输入图像描述

如您所见,每第二个字节都包含我要丢弃的 LSB,从而只保留奇数字节(换句话说)。我可以概念化的最佳解决方案是遍历内存,但这就是问题所在。我不能让它工作。我需要帮助的是 C# 中的算法来执行此操作。

这是一个示例图像,它表示从以下对象直接创建Bitmap对象IntPtr

bitmap = new Bitmap(imageWidth, imageHeight, imageWidth, PixelFormat.Format8bppIndexed, pImage);

单击以展开以查看正确的表示

// Failed Attempt #1
unsafe
{
    IntPtr pImage;  // pointer to buffer containing 12-bit image data from imager
    int i = 0, imageSize = (imageWidth * imageHeight * 2);  // two bytes per pixel
    byte[] imageData = new byte[imageSize];
    do
    {
        // Should I bitwise shift?
        imageData[i] = (byte)(pImage + i) << 8;  // Doesn't compile, need help here!
    } while (i++ < imageSize);
}

// Failed Attempt #2
IntPtr pImage;  // pointer to buffer containing 12-bit image data from imager
imageSize = imageWidth * imageHeight;
byte[] imageData = new byte[imageSize];
Marshal.Copy(pImage, imageData, 0, imageSize);
// I tried with and without this loop. Neither gives me images.
for (int i = 0; i < imageData.Length; i++)
{
    if (0 == i % 2) imageData[i / 2] = imageData[i];
}
Bitmap bitmap;
using (var ms = new MemoryStream(imageData))
{
    bitmap = new Bitmap(ms);
}
// This also introduced a memory leak somewhere.

或者,如果有一种方法可以使用Bitmap, byte[],MemoryStream等有效的方法,我会全力以赴,但我尝试过的一切都失败了。

标签: c#image-processingmemorybitmap

解决方案


这是我的同事帮助制定的算法。它创建了两个新的(非托管)指针;一个 8 位宽,另一个 16 位。

通过一次遍历一个字并移走源代码的最后 4 位,我们得到了一个只有 MSB 的新 8 位图像。每个缓冲区都有相同数量的单词,但由于单词大小不同,当我们迭代它们时,它们会以不同的速度前进。

unsafe
{
    byte* p_bytebuffer = (byte*)pImage;
    short* p_shortbuffer = (short*)pImage;

    for (int i = 0; i < imageWidth * imageHeight; i++)
    {
        *p_bytebuffer++ = (byte)(*p_shortbuffer++ >> 4);
    }
}

在性能方面,这似乎非常快,帧速率没有明显的差异。

特别感谢@Herohtar花费大量时间与我聊天,试图帮助我解决这个问题。


推荐阅读