[英]How to draw directly on bitmap (BitmapSource, WriteableBitmap) in WPF?
[英]Draw on BitmapSource high hardware usage
我想在BitmapSource上繪制。
我的相框來源來自位圖類型的網絡攝像頭。 我將其轉換為BitmapSource,繪制一個rect並設置為具有數據綁定的Image控件源。
//convert Bitmap to BitmapSource:
//WinForms -> WPF
public BitmapSource BitmapToBitmapSource(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;
}
//Drawing code:
public static BitmapSource DrawRect(BitmapSource frame)
{
RenderTargetBitmap rtb = new RenderTargetBitmap(frame.PixelWidth, frame.PixelHeight, frame.DpiX, frame.DpiY, PixelFormats.Pbgra32);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext dc = dv.RenderOpen())
{
dc.DrawImage(frame, new Rect(0, 0, frame.Width, frame.Height));
//dc.DrawLine(new Pen(Brushes.White, 1), new Point(0, 0), new Point(frame.Width, frame.Height));
dc.DrawRectangle(null, new Pen(Brushes.Red, 1), new Rect(50, 50, 100, 100));
}
rtb.Render(dv);
rtb.Freeze();
return rtb;
}
我的硬件使用結果:
CPU:24%GPU:5.4%
在2.8Ghz的Intel Core i7-4900MQ上; 4核; 8線程/ NVIDIA Quadro K2100M
結果視頻不流暢,有點慢。
有誰知道我怎么能最快?
將System.Drawing.Bitmap轉換為System.Windows.Media.Imaging.BitmapSource或System.Windows.Media.ImageSource (基類)非常容易,但您必須小心。
首先,所有您需要在每次使用System.Drawing.Bitmap后都將其處置。 這樣,您就可以在內存中騰出可用空間
轉換可以通過兩種方式完成。 使用GDI或內存流。 我個人更喜歡GDI方式。 此外,GDI還允許您使用GPU而不是CPU。 如果要渲染視覺效果,那是您想要的。
記憶方式
public static System.Windows.Media.ImageSource ToImageSource2(this Bitmap bitmap)
{
using (MemoryStream stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Bmp);
stream.Position = 0;
System.Windows.Media.Imaging.BitmapImage result = new System.Windows.Media.Imaging.BitmapImage();
result.BeginInit();
result.CacheOption = System.Windows.Media.Imaging.BitmapCacheOption.OnLoad;
result.StreamSource = stream;
result.EndInit();
result.Freeze();
return result;
}
}
GDI方式
[DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteObject([In] IntPtr hObject);
public static System.Windows.Media.ImageSource ToImageSource(this Bitmap bitmap)
{
System.Windows.Media.ImageSource image;
IntPtr handle = bitmap.GetHbitmap();
try
{
image = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, System.Windows.Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
image.Freeze();
}
finally
{
DeleteObject(handle);
}
return image;
}
測試樣本
public static void Test()
{
System.Windows.Media.ImageSource img;
System.Drawing.Bitmap bmp = (System.Drawing.Bitmap)System.Drawing.Image.FromFile(@"filepath");
//From GDI
img = bmp.ToImageSource();
//From MemoryStream
img = bmp.ToImageSource2();
//Dispose from memory
bmp.Dispose();
}
如果您只需要在圖像周圍繪制邊框,則可以對BitmapSource
進行任何操作,然后在用戶界面中將Image
包裹在適當的Border
:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<Border BorderBrush="Red" BorderThickness="1">
<Image x:Name="Image1" />
</Border>
</Grid>
</Window>
然后查看它是否有所改善,否則您將需要檢查調用方法的方式和頻率。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.