如何从C#中的16位图像中读取像素数据而不是元数据?

时间:2018-12-18 10:08:45

标签: c# image byte

我有16位深度的图像,我想只读取像素数据并将其存储到字节[]

我尝试了以下代码:

FileInfo fileInfo = new FileInfo("C:\\Image stitch API\\Temp\\output.tif");
byte[] data = new byte[fileInfo.Length];

我还尝试了以下方法:

Image img;
img = Image.FromFile("C:\\Image stitch API\\Temp\\output.tif");
ImageConverter ic = new ImageConverter();
byte[] data = (byte[])ic.ConvertTo(img, typeof(byte[]))

这里所有数据都来自图像,但是我只需要像素数据?

有人可以帮忙吗?

2 个答案:

答案 0 :(得分:1)

如果您可以将图像加载为位图,则很容易获得如下所示的像素信息。

    Bitmap bitmap = new Bitmap("somefile.ext");
    Color color = bitmap.GetPixel(x,y) 

GetPixel()将返回Color(结构)类型,您可以按如下所示获取单个通道值作为字节。

    byte g = slateBlue.G;
    byte b = slateBlue.B;
    byte r = slateBlue.R;
    byte a = slateBlue.A;

关于您的评论,我建议您使用Netvips来以字节数组形式处理图像(这比system.drawing更好更快。)这样,您就可以将图像带作为字节数组如下所示。

    var imageBands = inputImage.Bandsplit();
    var R = imageBands [0];
    var B = imageBands [1];
    var G = imageBands [2];

如果您不想切换库,则可以使用System.Drawing获得字节数组,如下所示。

byte[] image = new[] {R, B, G};

答案 1 :(得分:0)

从图像中获取图像数据的最快方法是使用LockBitsMarshal.Copy

强烈建议不要使用GetPixelLockBits的工作方式是保留内存,用于放置图像的字节并在其中复制图像的字节。 UnlockBits然后将清理该保留的内存。

现在,问题是,GetPixel您访问的每个单个像素执行相同的锁定和解锁操作。一次使用LockBits相当快,但是一遍又一遍地使用它成千上万像素真的会使事情变慢。

请注意,有两种使用LockBits的方法;您可以使用sourceImage.PixelFormat获得原始像素格式的数据,也可以通过提供不同的格式使LockBits将数据转换到所需的格式。在这段代码中,我将输出强制为像素格式Format32bppArgb

/// <summary>
/// Gets the raw bytes from an image.
/// </summary>
/// <param name="sourceImage">The image to get the bytes from.</param>
/// <returns>The raw bytes of the image</returns>
public static Byte[] GetImageDataAs32bppArgb(Bitmap sourceImage)
{
    BitmapData sourceData = sourceImage.LockBits(
        new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    Byte[] data = new Byte[sourceData.Stride * sourceImage.Height];
    Marshal.Copy(sourceData.Scan0, data, 0, data.Length);
    sourceImage.UnlockBits(sourceData);
    return data;
}

Stride通常可以与width * bpp不同,因为位图的行始终与4个字节的倍数对齐,因此通常您也需要返回该位并对其进行跟踪,但是由于这是一个32位格式,其数据总是对齐到4个字节,因此这里没有任何实际差异。

注意,您的问题永远不会指定需要数据的顺序。典型的ARGB数据实际上是按字节顺序B,G,R,A,因为在IBM PC架构上普通的整数存储是低位字节序的,这意味着Int32值“ FFEEDDCC”的实际字节在内存中被反转为[CC DD EE FF]。但是您对此处给出的其他答案的评论似乎表明您使用了字节顺序[RR,GG,BB,AA]或'ABGR',这实际上不是我曾经使用过的格式见过。但是,如果您确实需要更改它,那只是交换红色和蓝色的简单额外循环:

for (Int32 i = 0; i < data.Length; i += 4)
{
    Byte b = data[i]; // save Blue
    data[i] = data[i + 2]; // set first component to the Red value
    data[i + 2] = b; // set third component to the Blue value
}