Search code examples
c#bitmapsystem.drawingunmanaged-memory

New image overlays previous bitmap


There are a number of posts about this, but i still can't figure it out. I am rather new at this, so please be forgiving.

I display an image, then grab a new image, and try to display it. When the new image is displayed, it has remnants of the old image. I have tried Picture1.Image= null to no avail.

Is it an issue with managed memory? I suspect it has to do with how the memory is being managed, that somehow the code copies a new image over and old image in a way that leaves some data from the previous image.

Here is the code to display the data in scaled1 (from this helpful earlier post):

Edit: Code added showing processing of arrays that are plotted. The overlaying behavior stops if the arrays are cleared using the Array.Clear method. Perhaps when this is cleared up I can post a canonical snippet demonstrating the issue.

This resets the question as: Why do arrays need to be cleared when each value of the array is rewritten? How can the array retain information of previous values?

ushort[] frame = null;
byte[] scaled1 = null;
double[][] frameringSin;
double[][] frameringCos;
double[] sumsin;
double[] sumcos;

frame = new ushort[mImageWidth * mImageHeight];
scaled1 = new byte[mImageWidth * mImageHeight];
frameringSin = new double[RingSize][];
frameringCos = new double[RingSize][];
ringsin = new double[RingSize];
ringcos = new double[RingSize];

//Fill array with images
for(int ring=0; ring <nN; ++ring)
                {
                    mCamera.GrabFrameReduced(framering[ring], reduced, out preset);
                }

//Process images
for (int i = 0; i < nN; ++i)
{
     Array.Clear(frameringSin[i], 0, frameringSin.Length);
     Array.Clear(frameringCos[i], 0, frameringSin.Length);
}
Array.Clear(sumsin, 0, sumsin.Length);
Array.Clear(sumcos, 0, sumcos.Length);
for(int r=0;r<nN; ++r)
{
     for (int i = 0; i < frame.Length; ++i)//upto 12 ms
     {
          frameringSin[r][i] = framering[r][i]* ringsin[r] / nN;
          frameringCos[r][i] = framering[r][i] *ringcos[r] / nN;
     }
}

for (int i = 0; i < sumsin.Length; ++i)//up to 25ms
{
    for (int r = 0; r < nN; ++r)
    {
        sumsin[i] += frameringSin[r][i];
        sumcos[i] += frameringCos[r][i];
    }
}

for(int r=0 ; r<nN ;++r)
{
    for (int i = 0; i < sumsin.Length; ++i)
    {
        A[i] = Math.Sqrt(sumsin[i] * sumsin[i] + sumcos[i] * sumcos[i]);
    }

//extract scaling parameters
...
//Scale Image
for (i1 = 0; i1 < frame.Length; ++i1)
    scaled1[i1] = (byte)((Math.Min(Math.Max(min1, frameA[i1]), max1) - min1) * scale1);


bmp1 = new Bitmap(mImageWidth,mImageHeight,System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
var bdata1 = bmp1.LockBits(new Rectangle(new Point(0, 0), bmp1.Size), ImageLockMode.WriteOnly, bmp1.PixelFormat);

 try
 {
      Marshal.Copy(scaled1, 0, bdata1.Scan0, scaled1.Length);
 }
 finally
 {
      bmp1.UnlockBits(bdata1);
 }

 Picture1.Image = bmp1;
 Picture1.Refresh();

Solution

  • Actually, you're not replacing all values in the arrays - your for cycles are wrong. You want them to look like this:

    for (i1 = 0; i1 < frame.Length; i1++)
      scaled1[i1] = (byte)((Math.Min(Math.Max(min1, frameA[i1]), max1) - min1)
                           * scale1);
    

    The difference (i++ vs ++i) is that your way, you're skipping the first and the last index. C# arrays start at 0, while you start at 1 (you increment the loop variable before you run the body for the first time).

    Also, note that for performance reasons, it's very handy if you're going through the array like this:

    for (var i = 0; i < array.Length; i++)
      /* do work with array[i] */
    

    The JIT compiler recognizes this and avoids bounds checks, because it knows there can never be an overflow. When you're doing a lot of work with arrays, this can give you a massive performance boost, even if you access multiple arrays through the same index (one of them will not have the checks, the others will - still saves a lot of work).

    The default JIT isn't very smart about this (it has to be quite fast), so pretty much anything else will reintroduce the bounds check. If performance is a concern for you, you'd want to profile the code anyway, of course.

    EDIT: Ah, my bad. Anyway, I believe your problem isn't having to clear the frameringXXX arrays, but rather, the sumsin and sumcos arrays - you're always adding to those, so you'd be adding to the value that was already there, rather than starting from zero again. So you need to reset those arrays to zeroes first (which is what Array.Clear does).