【问题标题】:New image overlays previous bitmap新图像覆盖以前的位图
【发布时间】:2014-07-15 01:12:22
【问题描述】:

有很多关于这个的帖子,但我仍然无法弄清楚。我对此很陌生,所以请原谅。

我显示一个图像,然后抓取一个新图像,并尝试显示它。当显示新图像时,它具有旧图像的残余。我试过Picture1.Image= null 无济于事。

这是托管内存的问题吗?我怀疑这与内存的管理方式有关,即代码以某种方式将新图像复制到旧图像上,从而留下了前一个图像中的一些数据。

这是在scaled1 中显示数据的代码(来自this 有用的早期帖子):

编辑: 添加的代码显示处理所绘制的数组。如果使用Array.Clear 方法清除数组,则覆盖行为会停止。也许当这被清除后,我可以发布一个规范的 sn-p 来展示这个问题。

这将问题重新设置为:为什么在重写数组的每个值时都需要清除数组?数组如何保留先前值的信息?

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

【问题讨论】:

  • 我们说的是 Windows 窗体吗?如果是,Picture1PictureBox 吗?
  • 是的,这是 Windows 窗体,Picture1PictureBox。 @Luaan 可能想插话,因为他建议使用代码 sn-p。
  • 好的,当你说“它有旧图像的残余”时,你是什么意思?
  • 看起来像是两张图片相互重叠。
  • @luaan 你显然比我更清楚这里发生了什么,所以我就让你去吧。但首先,如果我们谈论的是修改亮度和对比度,这让我想起了不久前来自Scott Hanselman's blog 的帖子。我从未使用过 ImageProcessor 库,但听起来它可能为您提供了一个很好的方法来做到这一点。许可证有点限制,但您可以查看它。

标签: c# bitmap system.drawing unmanaged-memory


【解决方案1】:

实际上,您并没有替换数组中的所有值 - 您的 for 循环是错误的。你希望它们看起来像这样:

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

区别(i++++i)是您的方式,您跳过了第一个和最后一个索引。 C# 数组从 0 开始,而您从 1 开始(您在第一次运行主体之前增加循环变量)。

另外,请注意,出于性能原因,如果您像这样遍历数组,这将非常方便:

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

JIT 编译器会识别这一点并避免边界检查,因为它知道永远不会发生溢出。当您对数组进行大量工作时,即使您通过同一个索引访问多个数组(其中一个不会进行检查,其他的会 - 仍然可以节省大量工作)。

默认的 JIT 在这方面不是很聪明(它必须非常快),所以几乎所有其他的东西都会重新引入边界检查。如果性能是您关心的问题,那么您当然希望对代码进行概要分析。

编辑:啊,我的错。无论如何,我相信你的问题不是必须清除 frameringXXX 数组,而是 sumsinsumcos 数组 - 你总是添加到那些,所以你会添加到原来的值已经在那里,而不是再次从零开始。因此,您需要先将这些数组重置为零(Array.Clear 就是这样做的)。

【讨论】:

  • 根据this 等帖子,for 循环在前自增或后自增中没有区别。我还检查了,i=0 在第一个增量中,它确实转到了最后一个值。
  • @DanG 哎呀。那很有意思。当然,这确实是有道理的,但我很确定它在某些语言上有所作为。好吧,我的坏:D
  • 是的,正确答案是编辑:问题是添加到 sumsinsumcos 而不归零。嗬!所以这里没有深刻而微妙的答案,只是我的经验不足:)。 ps - 我确实记得 PL/我在循环开始或结束时有一个增量索引。
猜你喜欢
  • 1970-01-01
  • 2020-03-25
  • 1970-01-01
  • 2013-07-21
  • 1970-01-01
  • 1970-01-01
  • 2015-01-13
  • 1970-01-01
  • 2014-03-21
相关资源
最近更新 更多