从不同的线程克隆部分图像非常慢

时间:2013-03-28 11:01:29

标签: c# multithreading image clone picturebox

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

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

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

应用程序正在快速执行此操作(对于50x50矩形,低于1ms)。

当我从不同的线程克隆它时,需要更多的时间(大约20ms +)。

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

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

提前谢谢。

此致

1 个答案:

答案 0 :(得分:0)

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

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;
        }
    }
}

我希望这能帮助有同样问题的人。

此致