将 12 位单色图像转换为 8 位灰度
Convert 12-bit Monochrome Image to 8-bit Grayscale
我有一个用于嵌入式开发的图像传感器板,我需要为其捕获图像流并以 8 位单色/灰度格式输出它们。成像器输出为 12 位单色(每个像素占用 2 个字节)。
在代码中,我有一个 IntPtr
到具有 12 位图像数据的内存缓冲区,我必须从中提取该数据并将其转换为 8 位图像。这在内存中表示如下(用亮光激活像素):
如您所见,每隔一个字节包含我要丢弃的 LSB,从而只保留奇数字节(换句话说)。我可以概念化的最佳解决方案是遍历内存,但这就是问题所在。我无法让它工作。我需要帮助的是 C# 中的算法来执行此操作。
这是一个示例图像,表示从 IntPtr
直接创建 Bitmap
对象,如下所示:
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
等来做到这一点,那么我洗耳恭听,但我已经尝试失败。
这是我的同事帮助制定的算法。它创建了两个新的(非托管)指针;一个 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 spending a substantial amount of time in chat with me 试图帮助我解决这个问题。
我有一个用于嵌入式开发的图像传感器板,我需要为其捕获图像流并以 8 位单色/灰度格式输出它们。成像器输出为 12 位单色(每个像素占用 2 个字节)。
在代码中,我有一个 IntPtr
到具有 12 位图像数据的内存缓冲区,我必须从中提取该数据并将其转换为 8 位图像。这在内存中表示如下(用亮光激活像素):
如您所见,每隔一个字节包含我要丢弃的 LSB,从而只保留奇数字节(换句话说)。我可以概念化的最佳解决方案是遍历内存,但这就是问题所在。我无法让它工作。我需要帮助的是 C# 中的算法来执行此操作。
这是一个示例图像,表示从 IntPtr
直接创建 Bitmap
对象,如下所示:
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
等来做到这一点,那么我洗耳恭听,但我已经尝试失败。
这是我的同事帮助制定的算法。它创建了两个新的(非托管)指针;一个 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 spending a substantial amount of time in chat with me 试图帮助我解决这个问题。