c# - 用户创建的像素字节数组似乎无法正确更新(WPF)

标签 c# wpf arrays intptr writeablebitmap

我有一个系统,可以从相机收集8位灰度图像,将数据放入WriteableBitmap并将图像显示在WPF Image对象上。这项工作发生在相机线程中。我用这篇文章来帮助我:How to create a BitmapImage from a pixel byte array (live video display)

我正在尝试做的是复制图像数据的像素数据的子集。在相机线程中更新帧期间,我试图在单独的字节数组中创建数据的副本。我的代码起初似乎可以运行,但是经过几次迭代后,我的缓冲区变量从具有一定范围的灰度级(0-255)变为每个数组元素中只有255的值。该变量似乎是在累积数据并最大化,而不是在每次调用后台工作程序时重置。我将在下面介绍我的代码。

谁能看到并描述我做错了什么?谢谢。

public partial class MainWindow : Window
{
    [DllImport("Kernel32.dll",EntryPoint="RtlMoveMemory")]
    public static extern void CopyMemory(IntPtr Destination, IntPtr Source, 
        uint Length);  

    // Declarations

    var pData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(byte))*FrameSize);
    var pFocusData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(byte))
           *FrameSize);

    BackgroundWorker bw = new BackgroundWorker();
    static CameraWorker cWorker;
    static Thread cThread;

    WriteableBitmap wbm;
    public IntPtr wbmBackBuffer;
    const int FrameSize = 1944*2592;

    // CameraWorker Event Handler
    void CW_FrameUpdated(object sender, CameraWorkerEventArgs e)
    {
       if (!e.Updated) return;
       // e.pData is an IntPtr containing the camera frame data
       CopyMemory(this.wbmBackBuffer, e.pData, FrameSize);
       this.Dispatcher.Invoke(wbm.Lock);
       this.Dispatcher.Invoke(()=>{ wbm.AddDirtyRect(
            new Int32Rect(0,0,wbm.PixelWidth,wbm.PixelHeight)); });
       this.Dispatcher.Invoke(wbm.Unlock);

       // The above works and I get streaming data to my view port. 
       // Now I want to make a copy of the pixel data to send to another thread
       // for processing. This is where I am having trouble. 
       if (bw.IsBusy) return;
       CopyMemory(pFocusData, e.pData, FrameSize);
       var args = new List<object>();
       args.Add(pFocusData);
       bw.RunWorkerAsync(args);
    }

    // BackgroundWorker event handlers

    void bw_DoWork(object sender, DoWorkEventArgs e)
    {

       // This is where I see the result of the problem when debugging. 

       List<object> argu = e.Argument as List<object>;
       var pData = (IntPtr) argu[0];
       var fullFrame = new byte[FrameSize];

       Marshal.Copy(pData,fullFrame,0,FrameSize);

       // Perform operations on the byte array data.

       // I extract a subregion from the byte array to process, however after a 
       // couple of iterations, all values in fullFrame equal 255. The pData that 
       // is coming in should be a copy of the pixel data that is being displayed 
       // on the screen. While the screen keeps updating with a live video image, 
       // the frameData variable appears to keep accumulating rather than resetting 
       // with each backgroundworker call. 

    }

    void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {

       // Update UI elements using Dispatcher with data obtained during DoWork.

    }

    // Window event handlers 

    private void MainWindow_Initialized(object sender, EventArgs e)
    {
       // Set up the WBM
       wbm = new WriteableBitmap(width,height,96d,96d,PixelFormats.Gray8,null);
       this.wbmBackBuffer = wbm.BackBuffer;

       // Set up the camera to grab frames in another thread
       cWorker = new CameraWorker(camera);
       cWorker.CameraFrameUpdated += CW_FrameUpdated;
       cThread = new Thread(new ThreadStart(cWorker.ThreadRun));
       cThread.Start();
       while(!cThread.IsAlive);

       // Set up the background worker for processing image data
       bw.DoWork += bw_DoWork;
       bw.RunWorkerCompleted += bw_RunWorkerCompleted;

       // Bind the image data to the Image object that has the name "viewer"
       viewer.Source = wbm;
    }

    private void MainWindow_Closing(object sender, 
                                    System.ComponentModel.CancelEventArgs e)
    {
        Marshal.FreeHGlobal(pData);
    }

}


编辑:我更正了Erti-Chris Eelmaa指出的错字。在显示代码相关部分方面,这只是我的一个抄写错误。

编辑#2:

1)如果if(!e.Updated)返回后再做BW东西会怎样?线? wbm会开始出现此累积错误,并且您的带宽会好吗?

行为没有差异。 wbm仍然可以,并且我的BW变量会累积。

2)bw_DoWork完成后,BackgroundWorker.IsBusy属性将为false。您对此行为还可以吗?

我的意图是仅在BW完成时处理新帧。我以为IsBusy可以持续到RunWorkerCompleted运行为止?我不需要处理每一帧。

我试图为每个CW_FrameUpdated调用简单地创建一个新的BW,但这也不能解决问题。

3)MoveMemory做什么?是否在不更改SOURCE中任何内容的情况下将内存从SOURCE复制到DESTINATION?它甚至复制任何东西吗?

RtlMoveMemory(CopyMemory)应该将字节从一个内存区域复制到另一个区域。我以为通过AllocHGlobal函数分配了两个大小相等的独立空间,我可以将8MB数据从一个变量快速复制到另一个变量。从我一直在阅读的内容来看,似乎我在做托管内存不喜欢的事情。我需要数据的快速深层副本。我会再次尝试System.Buffer.BlockCopy,以防万一我第一次错过东西。

4)您在说什么缓冲区变量?在每个阶段,验证所有缓冲液,并确定缓冲液不同的确切位置。您需要创建函数DumpMemory(IntPtr unmanagedMemory)。您可以将IntPtr强制转换为字节,然后使用fixed()语句执行。*

我将设置DumpMemory函数,并让您知道我发现了什么。同时,这是相关变量的数据流和花名册。

pData(IntPtr):非托管内存,其中包含1944 * 2592字节的Gray8格式的图像数据,没有标题

wbm(WriteableBitmap):WPF变量,绑定到主窗口上的Image对象

wbmBackBuffer(IntPtr):指向与wbm.BackBuffer相同位置的局部变量

pData使用CopyMemory复制到wbmBackBuffer,并且由于wbm绑定到Image对象,因此在主窗口上更新当前图像帧

pFocusData(IntPtr):这是一个本地指针,它以整帧数据的大小分配给内存

pData通过CopyMemory复制到pFocusData。

fullFrame(字节[]):这是pFocusData的字节数组副本。这是我看到积累发生的地方。

编辑#3:我终于解决了这个问题。事实证明,我选择的子阵列中存在逻辑错误。我的视口大约是800 * 400,而图像阵列大约是3.5倍。我没有正确缩放坐标,因此我的样本区域都在查看帧数据的一个较小且相似的区域。通过遵循第四个建议,并使用内存转储来准确查看每个步骤的运行情况,我注意到了这一点。它帮助我看到代码最终没有错,而我认为积累的实际上只是相机在一个很小的区域内饱和。

好消息是,上面发布的代码正确且有效。最终,我最终使用了Buffer.BlockCopy并创建了一个重复的帧,并通过相机工作程序事件args进行了传递。

非常感谢您的帮助Erti-Chris Eelmaa!

最佳答案

你累了,现在是圣诞节的时候了:P

   if (bw.IsBusy) return;
  // replace this.wbmBackBuffer with pFocusData
   CopyMemory(this.wbmBackBuffer, e.pData, FrameSize); 
   var args = new List<object>();
   args.Add(pFocusData);
   bw.RunWorkerAsync(args);


//编辑,因此在查看您的代码时,我有几个问题/建议。

1)如果您在if (!e.Updated) return;行之后进行BW任务会怎样? wbm会开始出现此累积错误,并且您的带宽会好吗?

2)bw_DoWork完成后,BackgroundWorker.IsBusy属性将为false。您对此行为还可以吗?

3)MoveMemory做什么?是否在不更改SOURCE中任何内容的情况下将内存从SOURCE复制到DESTINATION?它甚至复制任何东西吗?

4)您在说什么缓冲区变量?在每个阶段,验证所有缓冲液,并确定缓冲液不同的确切位置。您需要创建函数DumpMemory(IntPtr unmanagedMemory)。您可以将IntPtr强制转换为byte *并使用fixed()语句执行此操作。

关于c# - 用户创建的像素字节数组似乎无法正确更新(WPF),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20751138/

相关文章:

c# - 我可以确定字符串是否可以被 newtonsoft 反序列化吗?

c# - Parallel.ForEach 期间使用的线程数

WPF 绑定(bind)到 Listbox selectedItem

c# - MVVM WPF 从 View 内部导航 View

javascript - 在嵌套的 for 循环中,从较长的循环开始有什么好处吗?或相反亦然?

javascript - MongoDB选择_id数组的位置?

php - 在 PHP 中删除数组项的最佳方法是什么?

C# 套接字 ReceiveAsync

c# - 类型的 sizeof() 运算符

c# - 为什么关闭最后一个子窗口会最小化其父窗口?