0

I am getting a strange error when run my C# console application.

//get trainingimages
var trainingImages = Directory.GetFiles(
   "C:\\Users\\tub08918\\Google Drive\\Patil Lab\\AlexsFolderPleaseVisitMe\\ISIC-2017_Training_Data\\ISIC-2017_Training_Data",
   "*.jpg"
).ToList();

for (var i = 0; i < trainingImages.Count; i++)
{
   var image = Image.FromFile(trainingImages[i]);
   var vsImage = ConvertBitmap(new Bitmap(image));

   //cnvert to 2d array
   var imgArray = new int[vsImage.Width, vsImage.Height, 3];

   for (var j = 0; j < vsImage.Width; j++)
      for (var z = 0; z < vsImage.Height; z++)
      {
         var p = vsImage.GetPixel(j, z);
         imgArray[j, z, 0] = p.R;
         imgArray[j, z, 1] = p.G;
         imgArray[j, z, 2] = p.B;
      }
}

I get runtime exception:

An unhandled exception of type 'System.OutOfMemoryException' occurred in System.Drawing.dll

Additional information: Out of memory.

But I am doing this image by image so I am confused what parts of my logic are faulty. My Convert Bitmap function looks like this:

public static Bitmap ConvertBitmap(Bitmap image)
{
   // Convert other formats (including CMYK) to RGB.
   var newImage = new Bitmap(newWidth, newHeight);

   // Draws the image in the specified size with quality mode set to HighQuality
   using (var graphics = Graphics.FromImage(newImage))
   {
      graphics.DrawImage(image, 0, 0, newWidth, newHeight);
   }

   return newImage;
}
Community
  • 1
  • 1
woofwoof
  • 317
  • 2
  • 12
  • 8
    Strange? I would say that this is expected to happen with this code. Building disposable object without disposing them. Filling an array with all the bytes from all your images, that could be a lot of memory if you have many images. – Steve Feb 26 '17 at 21:38
  • hmm I thought the were being disposed whenever I exited the loop. How would I dispose of each image then? – woofwoof Feb 26 '17 at 21:42
  • The error could indicate you are accessing a memory location outside the boundary of the image. I would start by verifying the Width and the Height of the image are valid. These numbers should be standard image sizes. – jdweng Feb 26 '17 at 21:45
  • "But I am not saving anything so how". 'Memory' refers to RAM, not hard disk space. It will depend how many images of what size you have. 100 1000x1000 images would consume something like 100*1000*1000*3*4 = 1.2GB of RAM. (and that's just your arrays). – Dave Cousineau Feb 26 '17 at 21:45
  • @woofwoof either use `using` (then the disposable object will be disposed at the end of the using-block) or manually dispose the object. – dognose Feb 26 '17 at 21:45
  • @woofwoof http://stackoverflow.com/a/2926890/11683 – GSerg Feb 26 '17 at 21:45
  • `var vsImage = ConvertBitmap(new Bitmap(image));` should probably be `using(var vsImage = ConvertBitmap(new Bitmap(image))){…` – Jon Hanna Feb 26 '17 at 21:46
  • Thank you for the useful comments I will try to get my code working with this new information. – woofwoof Feb 26 '17 at 21:54
  • So I added dispose for the objects I used and the problem was fixed. Thank you guys and girls for helping! – woofwoof Feb 26 '17 at 22:09
  • @JonHanna - that only solves half the problem... – H H Feb 26 '17 at 22:21
  • @HenkHolterman ah yes, there's the previous one too. – Jon Hanna Feb 26 '17 at 23:43

2 Answers2

2

Please keep in mind that an out of memory exception could be because you've run out of handles for graphics objects, and not just plain old RAM.

You need to dispose of every IDisposable. In your code you have three objects that need to be disposed for every iteration of the loop.

Your code should look like this:

//get trainingimages
var trainingImages = Directory.GetFiles(
   "C:\\Users\\tub08918\\Google Drive\\Patil Lab\\AlexsFolderPleaseVisitMe\\ISIC-2017_Training_Data\\ISIC-2017_Training_Data",
   "*.jpg"
).ToList();

for (var i = 0; i < trainingImages.Count; i++)
{
    using (var image = Image.FromFile(trainingImages[i]))
    {
        using (var bm = new Bitmap(image))
        {
            using (var vsImage = ConvertBitmap(bm))
            {
                var imgArray = new int[vsImage.Width, vsImage.Height, 3];
                for (var j = 0; j < vsImage.Width; j++)
                {
                    for (var z = 0; z < vsImage.Height; z++)
                    {
                        var p = vsImage.GetPixel(j, z);
                        imgArray[j, z, 0] = p.R;
                        imgArray[j, z, 1] = p.G;
                        imgArray[j, z, 2] = p.B;
                    }
                }
            }
        }
    }
}
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
0

Had the same problem in one of my apps. Use using when calling FromFile method. Instead of:

 var image = Image.FromFile(trainingImages[i]);

Use:

using (var image = Image.FromFile(trainingImages[i]))
{
    using (var bitmap = new Bitmap(image))
    {
        using (var vsImage = ConvertBitmap(bitmap))
        {
            //cnvert to 2d array
            var imgArray = new int[vsImage.Width, vsImage.Height, 3];

            for (var j = 0; j < vsImage.Width; j++)
                for (var z = 0; z < vsImage.Height; z++)
                {
                    var p = vsImage.GetPixel(j, z);
                    imgArray[j, z, 0] = p.R;
                    imgArray[j, z, 1] = p.G;
                    imgArray[j, z, 2] = p.B;
                }
        }
    }
}

That's why you get OutOfMemory exceptions, because Image objects do not get disposed or they get disposed too late.

Jure
  • 1,156
  • 5
  • 15
  • 1
    `var vsImage = ConvertBitmap(new Bitmap(image));` needs two `using(){}` blocks. – H H Feb 27 '17 at 08:02