如何将 C# 中的图像数组转换为一维向量?

How to convert an array of images in C# to a one dimension vector?

我有一个包含 200 张图像的文件夹。我将所有这些图像加载到名为 training 的图像类型数组列表中。我在将其转换为一维向量时遇到问题。我需要这方面的帮助,正在编写一个基于 PCA 的人脸识别解决方案,谢谢。

 List<Image> training = new List<Image>();
        //the path to the images
        static string path = "C:/Users/User/Documents/visual studio 2015/Projects/PCA/PCA/training";
        public Form1()
        {
            InitializeComponent();
        }
        //the method below starts the training process
        private void button1_Click(object sender, EventArgs e)
        {
            /*read all the images in the training folder into an array
            in this case the images are already in gray scale so we do not need to convert
            */
            var files = Directory.GetFiles(path);
            foreach(string r in files)
            {
                if(Regex.IsMatch(r, @"\.jpg$|\.png$|\.gif$"))
                {
                    training.Add(Image.FromFile(r));
                }
            }
            //convert the list of images to a one dimension vector
           
           
        }

更新

我有一个名为 matrix data 的变量,其大小已初始化为 [200,92*112],然后我进行了此列表训练,我需要遍历列表中的所有图像并访问 pixel 并将其分配给 matrix_data。我想现在很清楚,如何实现这一点?

为什么不是这样的:

public static IEnumerable<System.Drawing.Color> ColorEnumerable(System.Drawing.Image picture)
{
    System.Drawing.Bitmap btmp = new Bitmap(picture);
    //TODO maybe LockBits first
    for(int i = 0; i < btmp.Height; i++) 
    {
        for(int j = 0; j < btmp.Width; j++)
        {
            yield return btmp.GetPixel(i,j);            
        }
    }
}

您可以根据需要使用它来分配给代码中的矩阵:

foreach(Image image in training)
{
    if(Regex.IsMatch(r, @"\.jpg$|\.png$|\.gif$"))
    {
        training.Add(Image.FromFile(r));
        // you could even populate your matrix here
    }
}
//convert the list of images to a one dimension vector
System.Numeric.Vector<Color> colorVector;
for(int i = 0; i < training.Count(); i++)
{
    colorVector = new Vector(ColorEnumerable(training[i]).ToArray());
    // TODO add colorVector to your matrix or whatever
}

首先,我不确定你说的“矢量”是什么意思。您可以谈论 C# 的 Vector<T> (documentation here),或者您可以谈论一维数组中的向量。如果是后者,C# array 就可以解决问题,我的大部分回答仍然有用。

我假设您想要 Vector<T>,因为它更难选择并且对并行化很有用,您可能会在神经网络训练中利用它。

要将所有像素放入 Vector<T>,您的第一直觉可能是使用 Vector<System.Drawing.Color>。这是一种非常合理的方法,但它行不通,因为 Vector<T> 仅适用于 C# 的内置数字(byte、int、float 等)。所以我们必须想出一个解决方法。

值得庆幸的是,颜色只有 4 个我们关心的分量,每个分量都可以表示为一个字节:alpha、红色、蓝色和绿色。这意味着我们可以将 Color 的信息存储在任何 4 字节的数字中。我选择使用 uint:

private static uint ToUint(Color color)
{
    var bytes = new[] { color.A,color.R,color.G,color.B};
    return BitConverter.ToUInt32(bytes);
}

转换回颜色同样简单:

private static Color ToColor(uint integer)
{
    var bytes = BitConverter.GetBytes(integer);
    return Color.FromArgb(bytes[0], bytes[1], bytes[2], bytes[3]);
}

现在我们要做的就是遍历像素,将它们转换为 uints,将它们存储在一个数组中,并从该数组中生成一个向量:

private static Vector<uint> ConvertImagesToColorVector(IEnumerable<Bitmap> images)
{
    var pixelCount = images.Sum(image => image.Width * image.Height);
    var pixels = new uint[pixelCount];
    var index = 0;
    foreach (var image in images)
    {
        foreach (var pixel in GetPixels(image))
        {
            pixels[index++] = ToUint(pixel);
        }
    }
    return new Vector<uint>(pixels);
}

private static IEnumerable<Color> GetPixels(Bitmap bitmap)
{
    for (var row = 0; row < bitmap.Height; row++)
    {
        for (var column = 0; column < bitmap.Width; column++)
        {
            yield return bitmap.GetPixel(column, row);
        }
    }
}

您的代码如下所示:

private void button1_Click(object sender, EventArgs e)
{
    /*read all the images in the training folder into an array
    in this case the images are already in gray scale so we do not need to convert
    */
    var files = Directory.GetFiles(path);
    var imageFiles = new List<string>();
    foreach (string r in files)
    {
        if (Regex.IsMatch(r, @"\.jpg$|\.png$|\.gif$"))
        {
            training.Add(Image.FromFile(r));
        }
    }

    var vector = ConvertImagesToColorVector(training.Select(i=>new Bitmap(i)));

    //do whatever you want with the vector here. If you need to convert back to a color use ToColor
}