8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

快速将 Bitmap 转换为 BitmapSource wpf

Mr P 2月前

78 0

我需要以 30Hz 的频率在图像组件上绘制图像。我使用以下代码:public MainWindow() { InitializeComponent(); Messenger.Default.Register (这,(bmp)=&...

我需要以 30Hz 的频率在组件上绘制图像。我 Image 使用以下代码:

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

问题是,使用此代码,我的 CPU 使用率约为 80%,而如果没有转换,则约为 6%。

那么为什么转换位图这么长?
有没有更快的方法(使用不安全的代码)?

帖子版权声明 1、本帖标题:快速将 Bitmap 转换为 BitmapSource wpf
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Mr P在本站《winforms》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 那么你怎么知道 80% 的 CPU 消耗并非全部都用于每秒显示 30 个 BitmapSource,而且转换根本不需要时间?

  • 你可能是对的,我测试时没有显示(但保留转换),使用率约为 40%。(这有点正常,但有点高)。之后,我在 ImageTarget.Source = drawable; 后添加了 GC.Collect();,我的 CPU 使用率约为 45%。所以 80% 可能是内存泄漏。

  • 根据我的经验,这里有一种方法,它至少比 CreateBitmapSourceFromHBitmap .

    生成的 BitmapSource 的 PixelFormat 正确性

    public static 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;
    }
    
  • 我在克莱门斯回答之前就已经自己回答了:

    [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
    public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
    
    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);
            }));
        });
    }
    

    现在我的 CPU 使用率大约是 15%

  • 重复使用 WriteableBitmap 甚至比每次都创建一个新的更好。您可能还应该显示 CopyMemory 的 DllImport 声明。

  • 您是否尝试过 Lock/AddDirtyRect/Unlock 序列是否真的比 WritePixels 更快?根据我的经验,它们大致相同,后者可以为您节省一些代码和 DllImport。

  • 我已经测试过 WritePixel 和 CopyMemory,它们看起来一样,但 WritePixel 更易读。我打算改用这个解决方案

  • @Epitouille 在 CopyMemory 行中显示错误消息“system.accessviolationexception 尝试读取或写入受保护的内存”

  • 引用 10

    直接复制到 BackBuffer 比 WritePixels 稍快。WritePixels 本质上只是一步完成 Lock、MemCpy、AddDirtyRect 和 Unlock 操作……但它还会对输入缓冲区执行一系列健全性检查,这可能会降低速度。这对您的用例来说可能无关紧要,但如果您想榨干每一毫秒的性能,请直接复制到 BackBuffer!

返回
作者最近主题: