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

Viewed 359

I have a folder that contains 200 images. I loaded all these images into an array list of type image called training. I have a problem converting this to a one dimension vector. I need help with this, am writing a PCA based solution for face recognition, Thank You.

 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
           
           
        }

Update

I have a variable called matrix data which has been initialized to size [200,92*112], and then I have this list training, I need to loop through all the images in the list and access a pixel and assign that to the matrix_data. I think am now clear, how do achieve this?

2 Answers

First of all, I'm not sure what you mean when you say "vector". You could be talking about C#'s Vector<T> (documentation here), or you could be talking about a vector as in a 1D array. If it's the latter a C# array will do the trick and most of my answer will still be helpful.

I am going to assume you want a Vector<T>, because its the more difficult option and is useful for parallelization, which you will probably take advantage of in neural network training.

To put all your pixels into a Vector<T>, your first instinct will probably be to use Vector<System.Drawing.Color>. This is a perfectly reasonable approach, but it won't work, because Vector<T> only works for C#'s built-in numbers (byte, int, float, etc.). So we will have to come up with a workaround.

Thankfully a Color only has 4 components that we care about, each of which can be expressed as a single byte: alpha, red, blue, and green. That means we can store the information of a Color inside any 4 byte number. I chose to use uint:

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

Converting back to a color is just as easy:

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

Now all we have to do is iterate through the pixels, convert them to uints, store them in an array, and make a vector from the array:

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);
        }
    }
}

Here's what this looks like in your code:

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
}

Why not something like this:

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);            
        }
    }
}

which you can use to assign to the matrix in your code as you like:

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
}
Related