1

C# の別のスレッドから部分ビットマップ (四角形で定義された領域) を複製する際に問題があります。

理解のために: 私のアプリケーション (Windows フォーム) では、ユーザーはさまざまな画像処理機能が実行される複数の領域を定義できます (たとえば、色やテキストが認識されます)。画像はフレーム グラバー (30fps) によって提供されます。OCR などの一部のアルゴリズムは非常に時間がかかるため、バックグラウンド ワーカーまたはスレッドで計算する必要があります。

私の問題: ((Bitmap)pictureBox1.Image).Clone(rectangle,((Bitmap)pictureBox1.Image).PixelFormat); を使用してメインスレッドでビットマップを複製すると、

アプリケーションはこれを非常に迅速に実行します (50x50 の長方形の場合、1 ミリ秒未満)。

別のスレッドから複製すると、さらに時間がかかります (約 20 ミリ秒以上)。

「.Clone()」(四角形なし) を使用して画像全体を複製すると、このメソッドがどのスレッドから呼び出されるかに違いはありません。かかる時間も同じです。

イメージを所有するスレッドとして別のスレッドからメソッドが呼び出されると、イメージの一部だけを複製するのに時間がかかる理由を誰かが知っていますか?

前もって感謝します。

よろしく

4

1 に答える 1

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

これが同じ問題を抱えている人に役立つことを願っています。

よろしく

于 2013-04-18T07:25:33.420 に答える