在 C# 中读取 ROS CompressedImage 数据字节数组
Reading a ROS CompressedImage data byte array in C#
我想访问 16UC1 格式的 png 图像的每个单独像素值的值,我将其作为 byte[] 接收。
我对 C# 中的图像处理真的很陌生,我被这个问题困了好几天了。
我可以通过以下方式使用 "typical" bgr8 格式的 jpg/png 字节数组:
private static Bitmap getBitmap(byte[] array)
{
return new Bitmap(new MemoryStream(array));
}
我为 16UC1 格式尝试了很多东西。我得到的最远的是:
private Bitmap getBitmap(byte[] array)
{
var bitmap = new Bitmap(640,480,PixelFormat.Format16bppRgb555);
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, 640, 480), ImageLockMode.WriteOnly, PixelFormat.Format16bppRgb555);
System.Runtime.InteropServices.Marshal.Copy(bitmapData.Scan0, array, 0, array.Length);
bitmap.UnlockBits(bitmapData);
return bitmap;
}
这至少是returns一张位图,虽然它是全黑的。
尝试 PixelFormat.Format16bppGrayScale
而不是 PixelFormat.Format16bppRgb555
给我一个 "General error in GDI+".
当通过例如将字节数组写入文件时通过
File.WriteAllBytes(filename, array);
我可以使用 IrfanView 等图像查看器查看图像,但 Windows 照片查看器失败。
不需要将文件作为位图读取。出于性能原因,我想避免文件操作。我只是想访问该图像的每个单独的 xy 像素。
更新:
我开始使用 Emgu.CV 并按照 Dan 在下面的建议应用 imdecode。
private Bitmap getCompressedDepthBitmap(byte[] data)
{
Mat result = new Mat(new Size(640, 480), DepthType.Cv16U, 1);
CvInvoke.Imdecode(data,LoadImageType.AnyDepth, result);
return result.Bitmap;
}
这又给我一个黑色图像。 (通过 WriteAllBytes 保存字节数组,我看到了有用的内容。)我也试过
Image<Gray, float> image = result.ToImage<Gray, float>();
image.Save(Path.Combine(localPath, "image.png"));
这也给了我一张黑色图像。
我现在正计划以某种方式标准化垫子,也许这有助于...
感谢您的关注和支持!
在浪费了数小时的工作时间和绝望之后,我终于找到了解决方案...
我在上面的描述中遗漏了一件重要的事情,即图像数据 byte[] 来自 ROS sensor_msgs/CompressedImage.msg.
应该包含png数据的数据字节数组有时以12字节开头header;似乎只有当数据是(1 通道)压缩深度图像时。我无意中发现了这个信息 here.
删除这些令人讨厌的 12 个字节并像往常一样继续工作:
var bitmap = new Bitmap(new MemoryStream(dataSkip(12).ToArray()));
我想访问 16UC1 格式的 png 图像的每个单独像素值的值,我将其作为 byte[] 接收。
我对 C# 中的图像处理真的很陌生,我被这个问题困了好几天了。
我可以通过以下方式使用 "typical" bgr8 格式的 jpg/png 字节数组:
private static Bitmap getBitmap(byte[] array)
{
return new Bitmap(new MemoryStream(array));
}
我为 16UC1 格式尝试了很多东西。我得到的最远的是:
private Bitmap getBitmap(byte[] array)
{
var bitmap = new Bitmap(640,480,PixelFormat.Format16bppRgb555);
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, 640, 480), ImageLockMode.WriteOnly, PixelFormat.Format16bppRgb555);
System.Runtime.InteropServices.Marshal.Copy(bitmapData.Scan0, array, 0, array.Length);
bitmap.UnlockBits(bitmapData);
return bitmap;
}
这至少是returns一张位图,虽然它是全黑的。
尝试 PixelFormat.Format16bppGrayScale
而不是 PixelFormat.Format16bppRgb555
给我一个 "General error in GDI+".
当通过例如将字节数组写入文件时通过
File.WriteAllBytes(filename, array);
我可以使用 IrfanView 等图像查看器查看图像,但 Windows 照片查看器失败。
不需要将文件作为位图读取。出于性能原因,我想避免文件操作。我只是想访问该图像的每个单独的 xy 像素。
更新: 我开始使用 Emgu.CV 并按照 Dan 在下面的建议应用 imdecode。
private Bitmap getCompressedDepthBitmap(byte[] data)
{
Mat result = new Mat(new Size(640, 480), DepthType.Cv16U, 1);
CvInvoke.Imdecode(data,LoadImageType.AnyDepth, result);
return result.Bitmap;
}
这又给我一个黑色图像。 (通过 WriteAllBytes 保存字节数组,我看到了有用的内容。)我也试过
Image<Gray, float> image = result.ToImage<Gray, float>();
image.Save(Path.Combine(localPath, "image.png"));
这也给了我一张黑色图像。 我现在正计划以某种方式标准化垫子,也许这有助于...
感谢您的关注和支持!
在浪费了数小时的工作时间和绝望之后,我终于找到了解决方案...
我在上面的描述中遗漏了一件重要的事情,即图像数据 byte[] 来自 ROS sensor_msgs/CompressedImage.msg.
应该包含png数据的数据字节数组有时以12字节开头header;似乎只有当数据是(1 通道)压缩深度图像时。我无意中发现了这个信息 here.
删除这些令人讨厌的 12 个字节并像往常一样继续工作:
var bitmap = new Bitmap(new MemoryStream(dataSkip(12).ToArray()));