c# - 将 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
等有效的方法,我会全力以赴,但我尝试过的一切都失败了。
解决方案
这是我的同事帮助制定的算法。它创建了两个新的(非托管)指针;一个 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花费大量时间与我聊天,试图帮助我解决这个问题。
推荐阅读
- regex - 电子邮件的正则表达式模式
- firebase - 目标 Kernel_snapshot 失败 Flutter
- regex - 从 AT 命令 AT+COPS 返回短字母数字运算符名称的 Bash 正则表达式
- selenium - Symfony,PHPUnit:客户端 Webdriver 身份验证
- java - 有没有办法禁用 MotionLayout 可见性更改动画?
- r - 替换特定列中的点
- html - 垂直和水平更改移动和桌面的块顺序
- r - 如何分析(非常不完整的)循环数据
- powerbi - 删除小数前的零 - PowerBI
- apollo - 如何使用 SSR 将响应标头中的数据传递给 ApolloProvider?