利用BitmapSource的高硬件使用率

时间:2019-03-31 21:07:55

标签: c# wpf

我想在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%

在Intel Core i7-4900MQ @ 2.8Ghz上; 4核; 8线程  / NVIDIA Quadro K2100M

结果视频不流畅,有点慢。

有人知道我该如何最快吗?

2 个答案:

答案 0 :(得分:1)

System.Drawing.Bitmap转换为System.Windows.Media.Imaging.BitmapSourceSystem.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();

    }

答案 1 :(得分:0)

如果您只需要在图像周围绘制边框,则可以对BitmapSource不做任何事情,然后在您的UI中,用适当的Image包装Border:< / p>

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

然后查看它是否以某种方式有所改进,否则您将需要检查调用方法的方式和频率。