【问题标题】:Cloning a partial image from a different thread is very slow从不同的线程克隆部分图像非常慢
【发布时间】:2013-03-28 11:01:29
【问题描述】:

我在从 C# 中的另一个线程克隆部分位图(由矩形定义的区域)时遇到问题。

为了理解: 在我的应用程序(Windows 窗体)中,用户可以定义执行不同图像处理功能的多个区域(例如识别颜色或文本)。图像由图像采集卡 (30fps) 提供。由于某些算法(例如 OCR)需要很长时间,因此它们应该在后台工作人员或线程中计算。

我的问题: 当我在我的主线程中克隆我的位图时 ((Bitmap)pictureBox1.Image).Clone(rectangle,((Bitmap)pictureBox1.Image).PixelFormat);

应用程序执行此操作的速度非常快(对于 50x50 的矩形不到 1 毫秒)。

当我从另一个线程克隆它时,它需要更多时间(大约 20 毫秒以上)。

当我使用“.Clone()”(没有矩形)克隆整个图像时,调用该方法的线程没有区别。需要同样的时间。

有人知道为什么当从另一个线程作为拥有图像的线程调用该方法时,克隆图像的一部分确实需要更多时间吗?

提前谢谢你。

问候

【问题讨论】:

    标签: c# multithreading image clone picturebox


    【解决方案1】:

    我不明白为什么克隆过程不能像从另一个线程调用它那样快,但我终于找到了复制问题的解决方法:

    http://msdn.microsoft.com/en-us/library/aa457087.aspx 显示了一个复制函数,该函数由不拥有图像的线程调用,运行速度很快。

    我使用此复制功能编写了一个图像包装器。到目前为止工作正常

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Drawing;
    using System.Threading;
    using System.Diagnostics;
    
    namespace FeatureConfigurator
    {
        public class ThreadSafeBitmapWrapper
        {
            public event EventHandler<EventArgs> onImageChanged;
            ReaderWriterLockSlim thisLock;
    
            Bitmap iImg;
    
            public ThreadSafeBitmapWrapper()
            {
                this.iImg = new Bitmap(1,1);
                this.thisLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
            }
    
            public ThreadSafeBitmapWrapper(Bitmap img)
            {
                this.iImg = img;
                this.thisLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
            }
    
            public Bitmap GetImage()
            {
                Bitmap img;
                this.thisLock.EnterReadLock();
                try
                {
                    img = this.iImg;
                }
                finally
                {
                    this.thisLock.ExitReadLock();
                }
                return img;
            }
    
            public void SetImage(Bitmap img)
            {
                bool success = true;
                this.thisLock.EnterWriteLock();
                try
                {
                    this.iImg = img;
                }
                catch
                {
                    success = false;
                }
                finally
                {
                    this.thisLock.ExitWriteLock();
                    if (onImageChanged != null && success)
                        onImageChanged(this, new EventArgs());
                }
            }
    
            public Bitmap CloneImage()
            {
                Bitmap clone;
                this.thisLock.EnterReadLock();
                try
                {
                    clone = new Bitmap(iImg);
                }
                finally
                {
                    this.thisLock.ExitReadLock();
                }
                return clone;
            }
    
            internal Bitmap CloneImage(Rectangle rectangle, System.Drawing.Imaging.PixelFormat pixelFormat)
            {
                Bitmap clone;
                this.thisLock.EnterReadLock();
                try
                {
                    Stopwatch w = new Stopwatch();
                    w.Restart();
                    Debug.WriteLine("clone " + w.ElapsedMilliseconds);
                    clone = iImg.Clone(rectangle, pixelFormat);
                    Debug.WriteLine("new BMP " + w.ElapsedMilliseconds);
                }
                finally
                {
                    this.thisLock.ExitReadLock();
                }
                return clone;
            }
    
            /// <summary>
            /// Code from Microsoft C# Help page: http://msdn.microsoft.com/en-us/library/aa457087.aspx
            /// </summary>
            /// <param name="section">The region on the containing image, which should be copied</param>
            /// <returns></returns>
            public Bitmap CloneImage(Rectangle section)
            {
                // Create the new bitmap and associated graphics object
                Bitmap bmp = new Bitmap(section.Width, section.Height);
                // Sets the lock to protect the copy procedure
                this.thisLock.EnterReadLock();
                try
                {
                    using (Graphics g = Graphics.FromImage(bmp))
                    {
                        // Draw the specified section of the source bitmap to the new one
                        g.DrawImage(iImg, 0, 0, section, GraphicsUnit.Pixel);
                    }
                }
                finally
                {
                    this.thisLock.ExitReadLock();
                }
                // Return the bitmap
                return bmp;
            }
        }
    }
    

    我希望这会对遇到同样问题的人有所帮助。

    问候

    【讨论】:

      猜你喜欢
      • 2021-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-23
      • 1970-01-01
      • 2016-05-28
      • 2015-02-08
      • 2021-11-13
      相关资源
      最近更新 更多