将 System.Drawing 位图转换为 Dlib Array2D

Posted

技术标签:

【中文标题】将 System.Drawing 位图转换为 Dlib Array2D【英文标题】:Converting System.Drawing Bitmap to Dlib Array2D 【发布时间】:2018-09-29 07:21:54 【问题描述】:

在这种情况下,ShapePredictor 的灰度 Array2D。

这是我正在尝试的,但没有太大成功。

using DlibDotNet;
using Rectangle = System.Drawing.Rectangle;
using System.Runtime.InteropServices;

public static class Extension

    public static Array2D<byte> ToArray2D(this Bitmap bitmap)
    
        var bits = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppPArgb);
        var length = bits.Stride * bits.Height;
        var data = new byte[length];

        Marshal.Copy(bits.Scan0, data, 0, length);
        bitmap.UnlockBits(bits);

        var array = new Array2D<byte>(bitmap.Width, bitmap.Height);

        for (var x = 0; x < bitmap.Width; x++)
            for (var y = 0; y < bitmap.Height; y++)
            
                var offset = x * 4 + y * bitmap.Width * 4;

                array[x][y] = data[offset];
            

        return array;
    

我已经搜索过,但还没有找到明确的答案。

【问题讨论】:

您正在以 32bpp 的速度访问数据,但试图将其放入 Byte 的 Array2D 中。您可能需要Aray2D&lt;Int32&gt;,并且每 4 个字节读取一次。 请注意,出于同样的原因,我正在使用偏移量offset = x * 4 + y * bitmap.Width 是的,但是如果您的二维数组的每个条目中只有一个字节,您的返回类型是否错误?对于 32bpp 像素,您需要完整的 Int32(可能是 UInt32)。我不知道ShapePredictor,所以不知道它期望什么样的数据,但是你不能把四个字节的数据放在一个字节中。 返回类型没问题。 ShapePredictor 适用于灰度(8 位)。从文件加载的Array2D&lt;byte&gt; array = Dlib.LoadPng&lt;byte&gt;("file.png") 按预期工作,但我真正需要的是能够将位图转换为 Array2D,以便我可以处理已加载到内存中的数据。 您需要的不止这些。您还需要代码来实际将您的图像转换为灰度。您的代码中没有这样的东西;您正在以 32bpp alpha 的 1600 万色数据的形式访问它。这种转换最好在之前作为字节访问它。 【参考方案1】:

如前所述,您首先需要将图像转换为灰度。 *** 上有很多答案可以帮助您解决这个问题。我建议在这个答案中使用ColorMatrix 方法:

A: Convert an image to grayscale

我将在下面的代码中使用该答案中显示的MakeGrayscale3(Bitmap original) 方法。

通常,图像会逐行循环进行处理,因此为清楚起见,您应该将 Y 循环作为外循环。它还使数据偏移量的计算更加高效。

对于实际数据,如果图像是灰度的,那么R、G和B字节应该都是一样的。 32 位像素数据中的“ARGB”顺序是指一个UInt32 值,但它们是小端的,这意味着字节的实际顺序是 [B, G, R, A]。这意味着在每次循环迭代中,我们可以只取四个字节中的第一个,它将是蓝色分量。

public static Array2D<Byte> ToArray2D(this Bitmap bitmap)

    Int32 stride;
    Byte[] data;
    // Removes unnecessary getter calls.
    Int32 width = bitmap.Width;
    Int32 height = bitmap.Height;
    // 'using' block to properly dispose temp image.
    using (Bitmap grayImage = MakeGrayscale(bitmap))
    
        BitmapData bits = grayImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppPArgb);
        stride = bits.Stride;
        Int32 length = stride*height;
        data = new Byte[length];
        Marshal.Copy(bits.Scan0, data, 0, length);
        grayImage.UnlockBits(bits);
    
    // Constructor is (rows, columns), so (height, width)
    Array2D<Byte> array = new Array2D<Byte>(height, width);
    Int32 offset = 0;
    for (Int32 y = 0; y < height; y++)
    
        // Offset variable for processing one line
        Int32 curOffset = offset;
        // Get row in advance
        Array2D<Byte>.Row<Byte> curRow = array[y];
        for (Int32 x = 0; x < width; x++)
        
            curRow[x] = data[curOffset]; // Should be the Blue component.
            curOffset += 4;
        
        // Stride is the actual data length of one line. No need to calculate that;
        // not only is it already given by the BitmapData object, but in some situations
        // it may differ from the actual data length. This also saves processing time
        // by avoiding multiplications inside each loop.
        offset += stride;
    
    return array;

【讨论】:

你的代码更精简,虽然我注意到一些错别字,很容易修复。转换仍然不起作用。主要问题是 Array2D 数据的初始化似乎没有记录,这就是我在数组循环中执行此操作的原因。我看到很多人问如何做到这一点,但目前还没有明确的答案。 @O.Coder 我想我找到了。 DlibDotNet 源代码按顺序使用rowscolumns。这意味着 heightwidth。你到处都换了。正如我已经指出的那样,多维数组如果按行查看则更加合乎逻辑,因此访问权限也是array[y][x] 哈哈,天哪。谢谢奈尔古兹。这解决了它。 似乎每次检索行都会执行一次函数调用,因此在 X 循环之外检索它会更有效。我编辑了代码以显示这一点。

以上是关于将 System.Drawing 位图转换为 Dlib Array2D的主要内容,如果未能解决你的问题,请参考以下文章

WPF - 将位图转换为 ImageSource

如何从数据库中检索位图图像?

使用medata数据wpf c#将位图保存为png [重复]

将 System.Drawing.Icon 转换为 System.Media.ImageSource

将 System.Windows.Media.Color 转换为 System.Drawing.Color

如何将十六进制#FFFFFF 转换为 System.Drawing.Color [重复]