2015-06-09 16 views
9

Tôi cần vẽ hình ảnh trên thành phần Image ở 30Hz. tôi sử dụng mã này:chuyển đổi nhanh Bitmap sang BitmapSource wpf

public MainWindow() 
    { 
     InitializeComponent(); 

     Messenger.Default.Register<Bitmap>(this, (bmp) => 
     { 
      ImageTarget.Dispatcher.BeginInvoke((Action)(() => 
      { 
       var hBitmap = bmp.GetHbitmap(); 
       var drawable = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
        hBitmap, 
        IntPtr.Zero, 
        Int32Rect.Empty, 
        BitmapSizeOptions.FromEmptyOptions()); 
       DeleteObject(hBitmap); 
       ImageTarget.Source = drawable; 
      })); 
     }); 
    } 

Vấn đề là, với mã này, sử dụng CPU của tôi là khoảng 80%, và, nếu không có sự chuyển đổi đó là khoảng 6%.

Vậy tại sao chuyển đổi bitmap quá dài?
Có phương pháp nhanh hơn (có mã không an toàn) không?

+0

gì được hiển thị nếu không có chuyển đổi? CPU tiêu thụ là khoảng 6% mà không có bất kỳ bitmap hiển thị? – Clemens

+0

có, máy ảnh gửi sự kiện với khung hình mới, nhưng không chuyển đổi và không có gì được hiển thị. – Epitouille

+0

Vậy làm thế nào để bạn biết rằng không phải tất cả tiêu thụ CPU 80% chỉ được sử dụng để hiển thị 30 BitmapSources mỗi giây và chuyển đổi không mất thời gian? – Clemens

Trả lời

20

Đây là phương pháp (theo kinh nghiệm của tôi) nhanh hơn ít nhất bốn lần so với CreateBitmapSourceFromHBitmap.

Yêu cầu bạn đặt đúng PixelFormat của kết quả BitmapSource.

public BitmapSource Convert(System.Drawing.Bitmap bitmap) 
{ 
    var bitmapData = bitmap.LockBits(
     new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), 
     System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat); 

    var bitmapSource = BitmapSource.Create(
     bitmapData.Width, bitmapData.Height, 
     bitmap.HorizontalResolution, bitmap.VerticalResolution, 
     PixelFormats.Bgr24, null, 
     bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride); 

    bitmap.UnlockBits(bitmapData); 
    return bitmapSource; 
} 
3

Tôi đã trả lời bản thân mình trước khi Clemens câu trả lời với:

WriteableBitmap writeableBitmap = new WriteableBitmap(1280, 1024, 96.0, 96.0, PixelFormats.Bgr24, null); 
     public MainWindow() 
     { 
      InitializeComponent(); 

      ImageTarget.Source = writeableBitmap; 

      Messenger.Default.Register<Bitmap>(this, (bmp) => 
      { 
       ImageTarget.Dispatcher.BeginInvoke((Action)(() => 
       { 
        BitmapData data = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat); 
        writeableBitmap.Lock(); 
        CopyMemory(writeableBitmap.BackBuffer, data.Scan0, 
         (writeableBitmap.BackBufferStride * bmp.Height)); 
        writeableBitmap.AddDirtyRect(new Int32Rect(0, 0, bmp.Width, bmp.Height)); 
        writeableBitmap.Unlock(); 
        bmp.UnlockBits(data); 
       })); 
      }); 
     } 

Bây giờ sử dụng CPU của tôi là khoảng 15%

+0

Việc sử dụng lại WriteableBitmap thậm chí còn tốt hơn việc tạo một tệp mới mỗi lần. Bạn có lẽ cũng nên hiển thị khai báo DllImport của CopyMemory. – Clemens

+1

Và bạn đã thử nếu trình tự Lock/AddDirtyRect/Unlock thực sự nhanh hơn WritePixels? Theo kinh nghiệm của tôi, nó ít nhiều giống nhau, và cái sau sẽ tiết kiệm cho bạn một số mã và một DllImport. – Clemens

+0

Tôi đã thử nghiệm với WritePixel và CopyMemory, nó trông giống nhau, nhưng WritePixel dễ đọc hơn. Tôi sẽ chuyển sang giải pháp này – Epitouille

Các vấn đề liên quan