Нарисуйте на BitmapSource высокое аппаратное использование - PullRequest
0 голосов
/ 01 апреля 2019

Я хочу рисовать на BitmapSource.

Источник My Frame поступает с веб-камеры в растровом виде. Я конвертирую его в BitmapSource, рисую прямоугольник и устанавливаю источник управления изображениями с привязкой данных.

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

мои результаты использования оборудования:

ЦП: 24% GPU: 5,4%

на Intel Core i7-4900MQ @ 2,8 ГГц; 4core; 8thread / NVIDIA Quadro K2100M

Результат видео не плавный, немного медленный.

Кто-нибудь знает, как я могу сделать быстрее?

Ответы [ 2 ]

1 голос
/ 01 апреля 2019

Преобразование System.Drawing.Bitmap в System.Windows.Media.Imaging.BitmapSource или System.Windows.Media.ImageSource (базовый класс)очень просто, но вы должны быть осторожны.

Прежде всего, вам нужно распоряжаться файлом System.Drawing.Bitmap каждый раз, когда вы его используете.Таким образом, вы освобождаете место в вашей памяти

Преобразование может быть выполнено двумя способами.Использование GDI или потока памяти.Лично я предпочитаю способ GDI.Также GDI позволит вам использовать графический процессор вместо центрального процессора.Это то, что вам нужно, если вы собираетесь визуализировать визуальные эффекты.

ПУТЬ ПОТОКА ПАМЯТИ

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

    }
0 голосов
/ 01 апреля 2019

Если вы делаете не что иное, как рисование границы вокруг изображения, вы можете просто ничего не делать с 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>

Тогда посмотрите, улучшится ли это как-нибудь, иначе вы захотите проверить, как и как часто вы вызываете ваши методы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...