将System.Drawing Bitmap转换为Dlib Array2D

时间:2018-04-18 22:39:43

标签: c# .net dlib

在这种情况下,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;
    }

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

1 个答案:

答案 0 :(得分:1)

如前所述,您首先需要将图像转换为灰度。 StackOverflow上有很多答案可以帮助您解决这个问题。我建议在这个答案中使用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;
}