Обновление содержимого источника TransformedBitmap не обновляет отображаемое изображение - PullRequest
1 голос
/ 21 ноября 2011

Мне нужно визуализировать видео в реальном времени с веб-камеры. Я пытаюсь изменить источник моего объекта Image каждый раз, когда появляется новый кадр. Я создаю WritableBitmap, который каждый раз обновляется новым кадром, и TransformedBitmap, который применяет преобразование переворачивания к WritableBitmap в качестве его источника. Если я создаю новый TransformedBitmap для каждого кадра, он работает, и я вижу подачу видео, хотя объем памяти растет очень быстро, в результате чего сборщик мусора очень часто собирает память. Если я пытаюсь повторно использовать одну TransformedBitmap, я не вижу обновлений при рендеринге, всегда отображается первый кадр.

Как я могу использовать тот же объект TransformedBitmap без увеличения объема памяти?

Вот пример кода, использующего два разных файла для эмуляции веб-камеры.

public partial class Window1 : Window
{
    Thread m_thread;
    BitmapImage source1;
    BitmapImage source2;
    byte[] data;
    int stride;
    WriteableBitmap bitmap;
    TransformedBitmap tb;
    public Window1()
    {
        InitializeComponent();
        FileStream stream = new FileStream("1.png", FileMode.Open, FileAccess.Read);

        source1 = new BitmapImage();
        source1.BeginInit();
        source1.StreamSource = stream;
        source1.EndInit();

        FileStream stream2 = new FileStream("2.png", FileMode.Open, FileAccess.Read);
        source2 = new BitmapImage();
        source2.BeginInit();
        source2.StreamSource = stream2;
        source2.EndInit();

        stride = source1.PixelWidth * (source1.Format.BitsPerPixel / 8);
        data = new byte[stride * source1.PixelHeight];

        bitmap = new WriteableBitmap(source1.PixelWidth, source1.PixelHeight, source1.DpiX, source1.DpiY, source1.Format, source1.Palette);
        WritePixels(source1, bitmap, data);

        tb = new TransformedBitmap(bitmap, new ScaleTransform(-1, 1));

        m_thread = new Thread(ThreadFunc);
        m_thread.Start();
    }

    public void ThreadFunc()
    {
        int i = 0;
        while (true)
        {
            Dispatcher.Invoke(new Action(() => {
                BitmapSource source = (i % 2 == 0) ? source2 : source1;
                WritePixels(source, bitmap, data);
                image1.Source = tb;
            }));
            ++i;
            Thread.Sleep(100);
        }
    }

    public void WritePixels(BitmapSource source, WriteableBitmap target, byte[] data)
    {
        int stride = source.PixelWidth * (source.Format.BitsPerPixel / 8);

        source.CopyPixels(data, stride, 0);
        target.WritePixels(new Int32Rect(0, 0, source.PixelWidth, source.PixelHeight), data, stride, 0);
    }
}

1 Ответ

3 голосов
/ 22 ноября 2011

Я понял, проблема была вызвана тем фактом, что TransformedBitmap был тем же самым, поэтому, вероятно, объект Image не распознал изменения, если я использую два разных объекта TransformedBitmap, которые имеют один и тот же источник, а затем после записи нового содержимогоЯ переключаю TransformedBitmap, он работает, у меня отображается новое содержимое.

Итак, код:

public partial class MainWindow : Window
{
    Thread m_thread;
    BitmapImage source1;
    BitmapImage source2;
    byte[] data;
    int stride;
    WriteableBitmap bitmap1;

    TransformedBitmap tb1;
    TransformedBitmap tb2;

    public MainWindow()
    {
        InitializeComponent();
        FileStream stream = new FileStream("1.jpg", FileMode.Open, FileAccess.Read);

        source1 = new BitmapImage();
        source1.BeginInit();
        source1.StreamSource = stream;
        source1.EndInit();

        FileStream stream2 = new FileStream("2.jpg", FileMode.Open, FileAccess.Read);
        source2 = new BitmapImage();
        source2.BeginInit();
        source2.StreamSource = stream2;
        source2.EndInit();

        stride = source1.PixelWidth * (source1.Format.BitsPerPixel / 8);
        data = new byte[stride * source1.PixelHeight];

        bitmap1 = new WriteableBitmap(source1.PixelWidth, source1.PixelHeight, source1.DpiX, source1.DpiY, source1.Format, source1.Palette);
        WritePixels(source1, bitmap1, data);

        tb1 = new TransformedBitmap(bitmap1, new ScaleTransform(-1, -1));
        tb2 = new TransformedBitmap(bitmap1, new ScaleTransform(-1, -1));

        m_thread = new Thread(ThreadFunc);
        m_thread.Start();
    }

    public void ThreadFunc()
    {
        int i = 0;
        while (true)
        {
            Dispatcher.Invoke(new Action(() => {
                BitmapSource source = (i % 2 == 0) ? source2 : source1;
                WritePixels(source, bitmap1, data);
                // this is the trick we have to set different TransformedBitmap as
                // Image.Source
                // so since we don't want to create new one each time we just
                // switch between two
                image1.Source = (i % 2 == 0) ? tb1 : tb2;
            }));
            ++i;
            Thread.Sleep(100);
        }
    }

    public void WritePixels(BitmapSource source, WriteableBitmap target, byte[] data)
    {
        int stride = source.PixelWidth * (source.Format.BitsPerPixel / 8);

        source.CopyPixels(data, stride, 0);
        target.WritePixels(new Int32Rect(0, 0, source.PixelWidth, source.PixelHeight), data, stride, 0);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...