2015-06-09 16 views
9

Ho bisogno di disegnare un'immagine sul componente Image a 30Hz. Io uso questo codice:conversione veloce Bitmap in Bitmap Origine 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; 
      })); 
     }); 
    } 

Il problema è che con questo codice, il mio utilizzo della CPU è di circa 80%, e, senza la conversione è circa il 6%.

Quindi, perché la conversione di bitmap è così lunga?
Ci sono metodi più veloci (con codice non sicuro)?

+0

ciò che viene visualizzato se non c'è conversione? Il consumo della CPU è di circa il 6% senza alcuna bitmap visualizzata? – Clemens

+0

sì, la fotocamera invia un evento con una nuova cornice, ma nessuna conversione e non viene visualizzato nulla. – Epitouille

+0

Quindi, come fai a sapere che non tutto il consumo dell'80% della CPU viene utilizzato solo per la visualizzazione di 30 BitmapSources al secondo e la conversione non richiede assolutamente nulla? – Clemens

risposta

20

Ecco un metodo che (per la mia esperienza) è almeno quattro volte più veloce di CreateBitmapSourceFromHBitmap.

È necessario impostare lo PixelFormat corretto della BitmapSource risultante.

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

mi ha risposto prima di Clemens risposta con:

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

Ora il mio utilizzo della CPU è di circa il 15%

+0

Riutilizzare un WriteableBitmap è persino meglio che crearne uno nuovo ogni volta. Probabilmente dovresti anche mostrare la dichiarazione DllImport di CopyMemory. – Clemens

+1

E hai provato se la sequenza Lock/AddDirtyRect/Unlock è molto più veloce di WritePixels? Per la mia esperienza è più o meno lo stesso, e quest'ultimo ti farà risparmiare un po 'di codice e un DllImport. – Clemens

+0

Ho provato con WritePixel e CopyMemory, sembra uguale, ma WritePixel è più leggibile. Ho intenzione di passare a questa soluzione – Epitouille