【问题标题】:Updating the content of the TransformedBitmap's source doesn't update the rendered picture更新 TransformedBitmap 源的内容不会更新渲染的图片
【发布时间】:2011-11-21 16:52:17
【问题描述】:

我需要从网络摄像头渲染实时视频源。每次新帧到达时,我都会尝试更改 Image 对象的来源。我创建了每次使用新帧更新的 WritableBitmap 和在 WritableBitmap 上应用翻转转换的 TransformedBitmap 作为其源。如果我为每一帧创建新的 TransformedBitmap 它可以工作并且我看到视频源,尽管内存占用增长非常快,导致 GC 非常频繁地收集内存。如果我尝试重用单个 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);
    }
}

【问题讨论】:

  • 我明白了,问题是由于 TransformedBitmap 是相同的,所以如果我使用两个具有相同源的不同 TransformedBitmap 对象,可能 Image 对象无法识别更改,并且然后在编写新内容后,我切换它工作的 TransformedBitmap,我渲染了新内容。

标签: c# wpf


【解决方案1】:

我明白了,问题是由于 TransformedBitmap 相同,所以如果我使用两个具有相同源的不同 TransformedBitmap 对象,然后在编写新内容后,可能 Image 对象无法识别更改我切换它工作的 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);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-13
    • 1970-01-01
    • 1970-01-01
    • 2018-12-13
    • 1970-01-01
    • 1970-01-01
    • 2020-09-05
    相关资源
    最近更新 更多