【问题标题】:Show an array of bytes as an image on a form在表单上将字节数组显示为图像
【发布时间】:2021-11-17 22:32:45
【问题描述】:

我编写了一些代码来将字节数组显示为图像。有一个字节数组,其中每个元素代表一个 8 位灰度图像的值。 0 代表最黑的像素,255 代表最白的像素。我的目标是将这个 w*w-pixel 灰度图像转换为pictureBox1.Image 接受的东西。 这是我的代码:

namespace ShowRawImage
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();         
        }

        private void button1_Click(object sender, EventArgs e)
        {
            int i = 0, j = 0, w = 256;
            byte[] rawIm = new byte[256 * 256];
            for(i = 0; i < w; ++i)
            {
                for (j = 0; j < w; ++j)
                {
                    rawIm[i * w + j] = (byte)j; // BitConverter.GetBytes(j);
                }
            }

            MemoryStream mStream = new MemoryStream();
            mStream.Write(rawIm, 0, Convert.ToInt32(rawIm.Length));
            Bitmap bm = new Bitmap(mStream, false);// the error occurs here
            mStream.Dispose();
            pictureBox1.Image = bm;

        }
    }
}

但是我得到这个错误: 参数无效。
The error snapshot
我的错在哪里?

编辑: 在下一步中,我将显示 16 位灰度图像。

【问题讨论】:

  • 查看此处显示的位图构建器方法:How to make colors in a Palette transparent when drawing 8bpp Bitmaps(第一个 sn-p)使用索引调色板。您当然可以使用不同的 PixelFormat。
  • 倒回流——另外,您没有正确构建图像。通常需要设置标题来描述图像内容。甚至可能是一个调色板。
  • 帖子中显示的代码没有多大意义,因为位图不是字节的随机集合......也不清楚你的实际目标是什么 - 一般的“字节数组”不是“一个图像” - 所以一些 edit 来澄清你需要实现的目标会很好。
  • 位图不仅仅是一个数组,它还有header。在最简单的情况下,您可以创建所需大小的位图,然后在其上放置像素
  • 为什么不直接获取图片框的图形并绘制像素..?

标签: c# arrays winforms bmp


【解决方案1】:

Bitmap(Stream, bool) 构造函数需要具有实际图像格式(例如 PNG、GIF 等)的流以及标题、调色板和可能的压缩图像数据。

要从原始数据创建Bitmap,您需要使用Bitmap(int width, int height, int stride, PixelFormat format, IntPtr scan0) 构造函数,但这也很不方便,因为您需要一个可以作为scan0 传递的固定原始数据。

最好只用灰度调色板创建一个 8bpp 位图并手动设置像素:

var bmp = new Bitmap(256, 256, PixelFormat.Format8bppIndexed);

// making it grayscale
var palette = bmp.Palette;
for (int i = 0; i < 255; i++)
    palette.Entries[i] = Color.FromArgb(i, i, i);
bmp.Palette = palette;

现在您可以以字节形式访问其原始内容,其中 0 为黑色,255 为白色:

var bitmapData = bmp.LockBits(new Rectangle(Point.Empty, bmp.Size), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
for (int y = 0; y < bitmapData.Height; y++)
{
    for (int x = 0; x < bitmapData.Width; x++)
    {
        unsafe
        {
            ((byte*) bitmapData.Scan0)[y * bitmapData.Stride + x] = (byte)x;
        }
    }
}
bmp.UnlockBits(bitmapData);

结果图片:

但是如果你不想使用不安全的代码,或者你想通过颜色设置像素,你可以使用支持efficient manipulationthis库(免责声明:由我编写)不管实际的PixelFormat .使用该库,最后一个块可以这样重写:

using (IWritableBitmapData bitmapData = bmp.GetWritableBitmapData())
{
    IWritableBitmapDataRow row = bitmapData.FirstRow;
    do
    {
        for (int x = 0; x < bitmapData.Width; x++)
            row[x] = Color32.FromGray((byte)x); // this works for any pixel format
            // row.SetColorIndex(x, x); // for the grayscale 8bpp bitmap created above
    } while (row.MoveNextRow());
}

或者像这样,使用Parallel.For(这仅是因为在您的示例中所有行都相同,因此图像是水平渐变):

using (IWritableBitmapData bitmapData = bmp.GetWritableBitmapData())
{
    Parallel.For(0, bitmapData.Height, y =>
    {
        var row = bitmapData[y];
        for (int x = 0; x < bitmapData.Width; x++)
            row[x] = Color32.FromGray((byte)x); // this works for any pixel format
            // row.SetColorIndex(x, x); // for the grayscale 8bpp bitmap created above
    });
}

【讨论】:

  • 谢谢。那么 16 位灰度数据呢?你写的库支持 16 位灰度图?
  • @Tirsa:是的。请注意,尽管Graphics 不支持 16bb 灰度位图,因此Graphics.DrawImage 无法渲染或绘制它们。我收集了限制here。所以你可以使用 16bpp 灰度位图,但是要display 它们你需要转换它们的像素格式。
  • 关于 16 bpp 灰度位图的附加说明。没有一个内置编码器可以保存它们。 ImageExtensions 中的 SaveAs* 方法支持它们,尽管它们在保存之前先将它们转换为 8 或 24 bpp 图像。要保留实际的 16bpp 内容,您可以使用 BitmapDataExtensions.Save 方法,该方法使用自定义原始格式。
  • 我正在尝试 Emgu CV 包使用其 Image Box 而不是 picture box 来获得显示 16bpp 图像。我走对了吗?
【解决方案2】:

正如 cmets 中所说 - 位图不仅仅是一个数组。因此,为了达到您的目标,您可以创建所需大小的位图并使用Bitmap.SetPixel 设置像素:

Bitmap bm = new Bitmap(w, w);
for(var i = 0; i < w; ++i)
{
    for (var j = 0; j < w; ++j)
    {
        bm.SetPixel(i,j, Color.FromArgb(j, j, j));
    }
}

【讨论】:

  • 它工作正常,但在我的应用程序中非常耗时。如果 w = 3072 则需要 3400 毫秒才能执行。有什么优雅的方法可以减少它的执行时间?
猜你喜欢
  • 2019-09-21
  • 2012-08-04
  • 1970-01-01
  • 1970-01-01
  • 2013-05-18
  • 2012-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多