评论

收藏

[C++] Bitmap使用注意事项

编程语言 编程语言 发布于:2021-12-15 11:25 | 阅读数:448 | 评论:0

报错:对象当前正在其他地方使用
System.Drawing.Bitmap如果跨线程使用,或者同时被多方调用,就会报错​​对象当前正在其他地方使用​​
解决方案是新开线程就新建一个Bitmap副本,并且保证一个Bitmap对象同时只被一个地方使用
复现这个问题的例子如下:
string file="one image path";
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(file);
Task.Run(() =>
{
  try
  {
    while (true)
    {
      for (int i = 0; i < bmp.Width; i++)
        for (int j = 0; j < bmp.Height; j++)
        {
          var c1 = bmp.GetPixel(i, j);
        }
      Thread.Sleep(100);
    }

  }
  catch (Exception ex)
  {

  }
});

Task.Run(() =>
{
  try
  {
    while (true)
    {
      for (int i = 0; i < bmp.Width; i++)
        for (int j = 0; j < bmp.Height; j++)
        {
          var c1 = bmp.GetPixel(i, j);
        }
      Thread.Sleep(100);
    }

  }
  catch (Exception ex)
  {

  }
});
正确的使用方式是:
string file="one image path";
System.Drawing.Bitmap bmp1 = new System.Drawing.Bitmap(file);
Task.Run(() =>
{
  try
  {
    var cpbmp1 = (Bitmap)bmp1.Clone();
    while (true)
    {
      for (int i = 0; i < cpbmp1.Width; i++)
        for (int j = 0; j < cpbmp1.Height; j++)
        {
          var c1 = cpbmp1.GetPixel(i, j);
        }
      Thread.Sleep(100);

    }
  }
  catch (Exception ex)
  {

  }
});

Task.Run(() =>
{
  try
  {
    var cpbmp2 = (Bitmap)bmp1.Clone();
    while (true)
    {
      for (int i = 0; i < cpbmp2.Width; i++)
        for (int j = 0; j < cpbmp2.Height; j++)
        {
          var c1 = cpbmp2.GetPixel(i, j);
        }
      Thread.Sleep(100);

    }
  }
  catch (Exception ex)
  {

  }
});
使用byte[]也会遇到同样的问题
GetPixel效率问题
System.Drawing.Bitmap原生的GetPixel方法效率较低,可以使用C# Bitmap图片GetPixel 和 SetPixel 效率问题中的写法,经过测试,速度大概可以提高7倍。
测试代码如下:
int times = 10;

//no. 2
System.Drawing.Bitmap bmp1 = new System.Drawing.Bitmap(file);
Stopwatch sw = new Stopwatch();
sw.Start();
for (int number = 0; number < times; number++)
  for (int i = 0; i < bmp1.Width; i++)
    for (int j = 0; j < bmp1.Height; j++)
    {
      var c1 = bmp1.GetPixel(i, j);
    }
sw.Stop();
Console.WriteLine($"{nameof(Bitmap)}:{sw.ElapsedMilliseconds}");

//no. 1
OldLockBitmap oldLockBitmap = new OldLockBitmap(bmp1);
oldLockBitmap.LockBits();
sw.Restart();
for (int number = 0; number < times; number++)
  for (int i = 0; i < bmp1.Width; i++)
    for (int j = 0; j < bmp1.Height; j++)
    {
      var c1 = oldLockBitmap.GetPixel(i, j);
    }
sw.Stop();
oldLockBitmap.UnlockBits();
Console.WriteLine($"{nameof(OldLockBitmap)}1:{sw.ElapsedMilliseconds}");
关于速率问题的讨论:c# faster way of setting pixel colours


关注下面的标签,发现更多相似文章