C# C语言中int数组的BMP转换#

C# C语言中int数组的BMP转换#,c#,visual-studio,bitmap,C#,Visual Studio,Bitmap,在C#中,我无法将int(int32[,])的灰度数组转换为BMP格式。 我尝试在阵列中循环设置BMP中的像素颜色,它确实可以工作,但最终速度非常慢,几乎无法使用。 我在谷歌上搜索了很多,但我找不到我问题的答案。 我需要将图像实时放入一个图片盒中,这样方法就需要快速 相关讨论 编辑:数组的深度为8位,但存储为int32 Edit2:刚找到这个代码 private unsafe Task<Bitmap> BitmapFromArray(Int32[,] pixels, int

在C#中,我无法将int(int32[,])的灰度数组转换为BMP格式。 我尝试在阵列中循环设置BMP中的像素颜色,它确实可以工作,但最终速度非常慢,几乎无法使用。 我在谷歌上搜索了很多,但我找不到我问题的答案。 我需要将图像实时放入一个图片盒中,这样方法就需要快速

相关讨论

编辑:数组的深度为8位,但存储为int32

Edit2:刚找到这个代码

    private unsafe Task<Bitmap> BitmapFromArray(Int32[,] pixels, int width, int height)
    {
        return Task.Run(() =>
         {
             Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
             BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
             for (int y = 0; y < height; y++)
             {
                 byte* row = (byte*)bitmapData.Scan0 + bitmapData.Stride * y;
                 for (int x = 0; x < width; x++)
                 {
                     byte grayShade8bit = (byte)(pixels[x, y] >> 4);
                     row[x * 3 + 0] = grayShade8bit;
                     row[x * 3 + 1] = grayShade8bit;
                     row[x * 3 + 2] = grayShade8bit;
                 }
             }
             bitmap.UnlockBits(bitmapData);
             return bitmap;
         });
    }
私有不安全任务BitmapFromArray(Int32[,]像素,int宽度,int高度)
{
返回任务。运行(()=>
{
位图位图=新位图(宽度、高度、像素格式.Format24bppRgb);
BitmapData BitmapData=bitmap.LockBits(新矩形(0,0,宽度,高度),ImageLockMode.WriteOnly,PixelFormat.Format24bppRgb);
对于(int y=0;y>4);
行[x*3+0]=灰色阴影8bit;
行[x*3+1]=灰色阴影8bit;
行[x*3+2]=灰色阴影8bit;
}
}
位图。解锁位(bitmapData);
返回位图;
});
}
似乎工作速度足够快,但图像几乎是黑色的。如果我取下相机的顶部,图像应该是完全白色的,但它只是显示一个真正的深灰色。我猜它是把像素值解释为32位,而不是8位。然后尝试强制转换(ushort)像素[x,y],但不起作用

已解决(必须删除四位移位):

私有不安全任务BitmapFromArray(Int32[,]像素,int宽度,int高度)
{
返回任务。运行(()=>
{
位图位图=新位图(宽度、高度、像素格式.Format24bppRgb);
BitmapData BitmapData=bitmap.LockBits(新矩形(0,0,宽度,高度),ImageLockMode.WriteOnly,PixelFormat.Format24bppRgb);
对于(int y=0;y
仍然不确定为什么用
format8bpindexed
替换
Format24bppRgb
不起作用。有什么线索吗?

I实际上,但当然,你不是从字节数组开始的,你是从二维
Int32
数组开始的。绕过它的简单方法就是提前对其进行转换

将字节数组作为整数是一件相当奇怪的事情。如果这是从灰度图像中读取的,我宁愿假设这是32位ARGB数据,并且你只使用每个值的最低分量(蓝色分量),但是如果将值下移4位会产生统一的暗值,我倾向于相信你的话;否则,下一个颜色组分(绿色)的位会渗进来,也会产生明亮的颜色

不管怎样,撇开沉思和事后猜测不谈,这是我的实际答案

你可能会认为,当你的每一个值被注入一个8位图像时,仅仅是亮度,但这实际上是错误的。
系统中没有特定的类型。绘制
像素格式以指示8位灰度,8位图像为调色板,这意味着图像上的每个值都指调色板上的一种颜色。因此,为了实际生成一个8位灰度图像,其中字节值指示像素的亮度,您需要明确定义一个调色板,其中调色板上0到255的索引包含从(0,0,0)到(255255)的灰色。当然,这很容易生成

此代码将把数组转换为8位图像。它使用前面提到的
BuildImage
函数。请注意,该函数没有使用不安全的代码。使用
Marshal.Copy
意味着从未直接处理原始指针,从而使代码完全处于管理状态

public static Bitmap FromTwoDimIntArrayGray(Int32[,] data)
{
    // Transform 2-dimensional Int32 array to 1-byte-per-pixel byte array
    Int32 width = data.GetLength(0);
    Int32 height = data.GetLength(1);
    Int32 byteIndex = 0;
    Byte[] dataBytes = new Byte[height * width];
    for (Int32 y = 0; y < height; y++)
    {
        for (Int32 x = 0; x < width; x++)
        {
            // logical AND to be 100% sure the int32 value fits inside
            // the byte even if it contains more data (like, full ARGB).
            dataBytes[byteIndex] = (Byte)(((UInt32)data[x, y]) & 0xFF);
            // More efficient than multiplying
            byteIndex++;
        }
    }
    // generate palette
    Color[] palette = new Color[256];
    for (Int32 b = 0; i < 256; b++)
        palette[b] = Color.FromArgb(b, b, b);
    // Build image
    return BuildImage(dataBytes, width, height, width, PixelFormat.Format8bppIndexed, palette, null);
}
TwoDiminArrayGray(Int32[,]数据)中的公共静态位图 { //将二维Int32数组转换为1字节/像素字节数组 Int32 width=data.GetLength(0); Int32 height=data.GetLength(1); Int32 byteIndex=0; 字节[]数据字节=新字节[高度*宽度]; 对于(Int32 y=0;y<高度;y++) { 用于(Int32 x=0;x 请注意,即使整数是完整的ARGB值,上述代码仍将完全相同;如我所说,如果您只使用整数中四个字节中的最低一个,那么它就是完整ARGB整数的蓝色部分。如果图像是灰度的,那么所有三种颜色成分都应该是相同的,因此仍然可以得到相同的结果

假设您发现自己使用的是同一类型的字节数组,其中整数实际上包含完整的32bpp ARGB数据,那么
public static Bitmap FromTwoDimIntArrayGray(Int32[,] data)
{
    // Transform 2-dimensional Int32 array to 1-byte-per-pixel byte array
    Int32 width = data.GetLength(0);
    Int32 height = data.GetLength(1);
    Int32 byteIndex = 0;
    Byte[] dataBytes = new Byte[height * width];
    for (Int32 y = 0; y < height; y++)
    {
        for (Int32 x = 0; x < width; x++)
        {
            // logical AND to be 100% sure the int32 value fits inside
            // the byte even if it contains more data (like, full ARGB).
            dataBytes[byteIndex] = (Byte)(((UInt32)data[x, y]) & 0xFF);
            // More efficient than multiplying
            byteIndex++;
        }
    }
    // generate palette
    Color[] palette = new Color[256];
    for (Int32 b = 0; i < 256; b++)
        palette[b] = Color.FromArgb(b, b, b);
    // Build image
    return BuildImage(dataBytes, width, height, width, PixelFormat.Format8bppIndexed, palette, null);
}
    public static Bitmap fromTwoDimIntArrayGray(Int32[,] data)
    {
        Int32 width = data.GetLength(0);
        Int32 height = data.GetLength(1);
        Int32 stride = width * 4;
        Int32 byteIndex = 0;
        Byte[] dataBytes = new Byte[height * stride];
        for (Int32 y = 0; y < height; y++)
        {
            for (Int32 x = 0; x < width; x++)
            {
                // UInt32 0xAARRGGBB = Byte[] { BB, GG, RR, AA }
                UInt32 val = (UInt32)data[x, y];
                // This code clears out everything but a specific part of the value
                // and then shifts the remaining piece down to the lowest byte
                dataBytes[byteIndex + 0] = (Byte)(val & 0x000000FF); // B
                dataBytes[byteIndex + 1] = (Byte)((val & 0x0000FF00) >> 08); // G
                dataBytes[byteIndex + 2] = (Byte)((val & 0x00FF0000) >> 16); // R
                dataBytes[byteIndex + 3] = (Byte)((val & 0xFF000000) >> 24); // A
                // More efficient than multiplying
                byteIndex+=4;
            }
        }
        return BuildImage(dataBytes, width, height, stride, PixelFormat.Format32bppArgb, null, null);
    }