2

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?

Son of Man
  • 1,213
  • 2
  • 7
  • 27
  • 1
    You can check this answer that shows the methods to access individual image pixels https://stackoverflow.com/a/190395/234087 – Fede Nov 10 '21 at 10:06
  • @Fede, Thanks, I will certainly need a datatype variable to load the pixels into as am looping through each image, I need some help with that – Son of Man Nov 10 '21 at 10:09
  • 1
    Images are often managed as byte-arrays with some metadata, like with/height/stride/pixelformat. Or as ushort-arrays for 16-bit grayscale data. – JonasH Nov 10 '21 at 10:14
  • 1
    Can this answer your question? https://stackoverflow.com/questions/3801275/how-to-convert-image-to-byte-array – Infosunny Nov 10 '21 at 10:18
  • @JonasH, am having it difficult to do that because of the expectation that a one dimension array needs a single column and many rows while the images have `width` columns and `height` rows – Son of Man Nov 10 '21 at 10:18
  • @Infosunny, provided the result of the image manipulation is `n rows`*`single column` – Son of Man Nov 10 '21 at 10:20
  • The pxiel data is stored in a regular 1D array, but you keep a separate fields with metadata. For example with stride = 10, meaning that a pixel at position 1, 2 would be stored at index 1 * 10 + 2 = 12. – JonasH Nov 10 '21 at 10:23
  • @JonasH, all that would easier be explained with an answer, I am aware of the pixel manipulation of an image, how do I access a pixel and assign to a one dimension vector to make it clear – Son of Man Nov 10 '21 at 10:27

2 Answers2

2

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
}
Nigel
  • 2,961
  • 1
  • 14
  • 32
0

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
}
Tanque
  • 315
  • 3
  • 16
  • Yet to implement – Son of Man Nov 18 '21 at 03:21
  • Will I be able to compute the mean vector using this matrix? – Son of Man Nov 18 '21 at 03:33
  • I don't know, are you? I don't know the formula, I can only help you with the programming. That said, I thought you already know what kind of Matrix you need. Worst case you need to write your own calculateMeanVector(Matrix matrix) method. – Tanque Nov 18 '21 at 08:08
  • https://stackoverflow.com/questions/32256998/find-covariance-of-math-net-matrix here they are talking about some math library, maybe you can get some ideas there – Tanque Nov 18 '21 at 08:10
  • Why are you creating a new instance of the Vector class in every iteration inside the loop instead of declaring it outside and then just assign – Son of Man Nov 18 '21 at 12:19
  • 1
    I thought you want a seperate vector instance for each of your pictures? depending on what exactly you intend to use the vector for (maybe it works with some buildin matrix? maybe you dont even need a vector, and an array suffices? maybe just add the values directy to your "matrix" or whatever?) I just tried to show how to convert a bitmap to something 1D - the .toArray() gives you a 1D Array, the Vector() constructor makes a Vector from that array, feel free to elaborate on your question, I still have to guess a lot what it is you actually want to know – Tanque Nov 19 '21 at 07:10