编程语言
首页 > 编程语言> > c# – 用户创建的像素字节数组似乎无法正确更新(WPF)

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

作者:互联网

我有一个系统,我可以从相机收集8位灰色图像,将数据放入WriteableBitmap并在WPF图像对象上显示图像.这项工作发生在相机线程中.我用这篇文章来帮助我: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 if(!e.Updated)返回后,如果你做了BW的话,会发生什么?线? wbm是否会开始出现这种累积错误,你的BW会好吗?

行为没有区别. wbm仍然很好,我的BW变量累积.

2)bw_DoWork完成后,BackgroundWorker.IsBusy属性为false.你对这种行为没问题吗?

我的意图是在BW完成时只处理一个新帧.我认为IsBusy会持续到运行RunWorkerCompleted为止?我不需要处理每一帧.

我试图为CW_FrameUpdated的每次调用创建一个新的BW,但这也没有解决问题.

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

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

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

我将设置DumpMemory函数,让你知道我发现了什么.与此同时,这里是数据流和相关变量的名单.

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

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

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

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

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

pData通过CopyMemory复制到pFocusData.

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

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

好消息是上面发布的代码是正确的并且有效.我最终使用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 if(!e.Updated)返回后,如果你做了BW的话,会发生什么?线? wbm是否会开始出现这种累积错误,你的BW会好吗?

2)bw_DoWork完成后,BackgroundWorker.IsBusy属性为false.你对这种行为没问题吗?

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

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

标签:c,arrays,wpf,intptr,writeablebitmap
来源: https://codeday.me/bug/20190708/1406786.html