para - crear bitmap c#
Cómo crear una imagen de mapa de bits a partir de una matriz de bytes de píxeles(visualización de video en vivo) (1)
Necesito mostrar imágenes en vivo en un control WPF. Estoy buscando la manera más rápida de hacer esto usando WPF.
Estoy capturando imágenes de una cámara usando su API dll ( AVT ).
La imagen está escrita por el dll y la cámara sube una devolución de llamada con un IntPtr a una estructura de imagen llamada tFrame (que se describe a continuación). Los datos de píxel se almacenan en la propiedad de ImageBuffer con InPtr a una matriz de bytes.
Sé cómo crear un mapa de bits a partir de la matriz de bytes de píxeles, pero no una imagen de mapa de bits. Por lo tanto, es posible crear un Mapa de bits y luego crear un BitmapImagem a partir de él. Aquí hay una manera de crear un BitmapImage desde un mapa de bits en la memoria . Pero quiero crear BitmapImage directamente desde la fuente de datos (tFrame). ¿Cómo puedo hacer eso?
Sé que BitmapImage tiene un método CopyPixels, pero tiene un valor de SetPixels.
public struct tFrame
{
public IntPtr AncillaryBuffer;
public uint AncillaryBufferSize;
public uint AncillarySize;
public tBayerPattern BayerPattern;
public uint BitDepth;
public tFrameCtx Context;
public tImageFormat Format;
public uint FrameCount;
public uint Height;
public IntPtr ImageBuffer;
public uint ImageBufferSize;
public uint ImageSize;
public uint RegionX;
public uint RegionY;
public tErr Status;
public uint TimestampHi;
public uint TimestampLo;
public uint Width;
}
Así es como creo un mapa de bits a partir de una matriz de bytes de píxeles. Esto fue utilizado en la versión WinForm del software.
private void CreateBitmap(tFrame frame)
{
//This sample is for a 8bpp captured image
PixelFormat pxFormat = PixelFormat.Format8bppIndexed;
//STRIDE
//[https://stackoverflow.com/questions/1983781/why-does-bitmapsource-create-throw-an-argumentexception/1983886#1983886][3]
//float bitsPerPixel = System.Drawing.Image.GetPixelFormatSize(format);
int bitsPerPixel = ((int)pxFormat >> 8) & 0xFF;
//Number of bits used to store the image data per line (only the valid data)
int validBitsPerLine = ((int)frame.Width) * bitsPerPixel;
//4 bytes for every int32 (32 bits)
int stride = ((validBitsPerLine + 31) / 32) * 4;
Bitmap bmp = new Bitmap((int)frame.Width, (int)frame.Height, stride, pxFormat, frame.ImageBuffer);
}
EDIT 1:
Gracias a dr.mo, ahora puedo mostrar 60 imágenes FPS 1024x1024 con ~ 3% de uso de la CPU. Lo que estoy haciendo es:
//@ UI Thread
public WriteableBitmap wbm = new WriteableBitmap(1024, 1024, (double)96, (double)96, System.Windows.Media.PixelFormats.Gray8, null);
this.wbBackBuffer = this.wbm.BackBuffer;
//This can be called by a timer in the UI thread or at the grab Thread for every image, the CPU usage is almost the same.
void UpdateDisplayImage()
{
wbm.Lock();
wbm.AddDirtyRect(new Int32Rect(0, 0, wbm.PixelWidth, wbm.PixelHeight));
wbm.Unlock();
}
//@ Grab Thread
//Update the backbuffer with new camera image data.
UpdateBackBuffer(...);
/// <summary>
/// [http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap.aspx]
/// </summary>
public void UpdateBackBuffer(IntPtr pData, int w, int h, int ch)
{
//Can not acess wbm from outside UI thread
//CopyMemory(wbm.BackBuffer, pData, (uint)(w * h * ch));
//I dont know if it is safe to write to it buffer like this:
CopyMemory(this.wbBackBuffer, pData, (uint)(w * h * ch));
}
Esto debería funcionar. es súper rápido
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Drawing;
using System.Runtime.InteropServices;
using System.IO;
using System.ComponentModel;
public class MakeBitmapSource
{
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
public static extern void CopyMemory(IntPtr Destination, IntPtr Source, uint Length);
public static BitmapSource FromNativePointer(IntPtr pData, int w, int h, int ch)
{
PixelFormat format = PixelFormats.Default;
if (ch == 1) format = PixelFormats.Gray8; //grey scale image 0-255
if (ch == 3) format = PixelFormats.Bgr24; //RGB
if (ch == 4) format = PixelFormats.Bgr32; //RGB + alpha
WriteableBitmap wbm = new WriteableBitmap(w, h, 96, 96, format, null);
CopyMemory(wbm.BackBuffer, pData, (uint)(w * h * ch));
wbm.Lock();
wbm.AddDirtyRect(new Int32Rect(0, 0, wbm.PixelWidth, wbm.PixelHeight));
wbm.Unlock();
return wbm;
}
public static BitmapSource FromArray(byte[] data, int w, int h, int ch)
{
PixelFormat format = PixelFormats.Default;
if (ch == 1) format = PixelFormats.Gray8; //grey scale image 0-255
if (ch == 3) format = PixelFormats.Bgr24; //RGB
if (ch == 4) format = PixelFormats.Bgr32; //RGB + alpha
WriteableBitmap wbm = new WriteableBitmap(w, h, 96, 96, format, null);
wbm.WritePixels(new Int32Rect(0, 0, w, h), data, ch * w, 0);
return wbm;
}
}