C# 用户创建的像素字节数组似乎更新不正确(WPF)

C# 用户创建的像素字节数组似乎更新不正确(WPF),c#,wpf,arrays,intptr,writeablebitmap,C#,Wpf,Arrays,Intptr,Writeablebitmap,我有一个系统,我可以从相机收集8位灰度图像,将数据放入可写位图,并在WPF图像对象上显示图像。这项工作发生在相机线程中。我用这篇文章来帮助我: 我试图做的是复制图像数据的像素数据子集。在相机线程中的帧更新期间,我尝试在单独的字节数组中创建数据的副本。我的代码一开始似乎有效,但经过几次迭代后,我的缓冲区变量从灰度范围(0-255)变为每个数组元素中只有255个值。与每次调用后台工作程序时重置不同,该变量似乎会累积数据并最大化输出。我将在下面展示我的代码 有人能看到我做错了什么并向我描述一下吗?多谢

我有一个系统,我可以从相机收集8位灰度图像,将数据放入可写位图,并在WPF图像对象上显示图像。这项工作发生在相机线程中。我用这篇文章来帮助我:

我试图做的是复制图像数据的像素数据子集。在相机线程中的帧更新期间,我尝试在单独的字节数组中创建数据的副本。我的代码一开始似乎有效,但经过几次迭代后,我的缓冲区变量从灰度范围(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);
    }

}
公共部分类主窗口:窗口
{
[DllImport(“Kernel32.dll”,EntryPoint=“rtlmovemory”)]
公共静态外部无效CopyMemory(IntPtr目标、IntPtr源、,
单位长度);
//声明
var pData=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(byte))*FrameSize);
var pFocusData=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(byte))
*框架尺寸);
BackgroundWorker bw=新的BackgroundWorker();
静态摄像工;
静态线程;
可写位图wbm;
公共IntPtr wbmBackBuffer;
const int FrameSize=1944*2592;
//CameraWorker事件处理程序
void CW_FrameUpdated(对象发送器、CameraworkReventArgs e)
{
如果(!e.Updated)返回;
//e.pData是包含相机帧数据的IntPtr
CopyMemory(this.wbmBackBuffer,e.pData,FrameSize);
this.Dispatcher.Invoke(wbm.Lock);
this.Dispatcher.Invoke(()=>{wbm.AddDirtyRect(
新的Int32Rect(0,0,wbm.PixelWidth,wbm.PixelHeight));};
this.Dispatcher.Invoke(wbm.Unlock);
//以上工作正常,我将流式数据传输到我的视图端口。
//现在我想制作一份像素数据的拷贝,发送到另一个线程
//用于处理。这就是我遇到的问题。
如果(bw.IsBusy)返回;
CopyMemory(pFocusData、e.pData、FrameSize);
var args=新列表();
参数添加(pFocusData);
RunWorkerAsync(args);
}
//BackgroundWorker事件处理程序
void bw_DoWork(对象发送方,DoWorkEventArgs e)
{
//这就是我在调试时看到问题结果的地方。
List argu=e。参数为List;
var pData=(IntPtr)argu[0];
var fullFrame=新字节[FrameSize];
封送处理副本(pData,fullFrame,0,FrameSize);
//对字节数组数据执行操作。
//我从字节数组中提取一个子区域进行处理,但是在
//经过多次迭代,fullFrame中的所有值都等于255
//输入的应该是正在显示的像素数据的副本
//在屏幕上。当屏幕通过实时视频图像不断更新时,
//frameData变量似乎一直在累积,而不是重置
//每次打电话给后台工作人员。
}
void bw_RunWorkerCompleted(对象发送方,RunWorkerCompletedEventArgs e)
{
//使用Dispatcher使用DoWork期间获得的数据更新UI元素。
}
//窗口事件处理程序
私有void主窗口\u已初始化(对象发送方,事件参数e)
{
//设置WBM
wbm=新的可写位图(宽度、高度、96d、96d、像素格式.Gray8、null);
this.wbmBackBuffer=wbm.BackBuffer;
//将相机设置为在另一个线程中抓取帧
cWorker=新的摄像师(摄像机);
cWorker.CameraFrameUpdated+=CW_FrameUpdated;
cThread=newthread(newthreadstart(cWorker.ThreadRun));
cThread.Start();
而(!cThread.IsAlive);
//设置用于处理图像数据的后台工作程序
bw.DoWork+=bw_DoWork;
bw.RunWorkerCompleted+=bw_RunWorkerCompleted;
//将图像数据绑定到名为“查看器”的图像对象
viewer.Source=wbm;
}
私有void主窗口关闭(对象发送器,
System.ComponentModel.CancelEventArgs(e)
{
弗里赫全球元帅(pData);
}
}
编辑:我纠正了Erti Chris Eelmaa指出的打字错误。这只是我在显示代码相关部分时的一个转录错误

编辑#2:

1) 如果(!e.Updated)返回后执行BW操作会发生什么情况;线路?wbm是否会开始出现这种累积错误,您的BW是否会正常

行为上没有区别。wbm仍然很好,我的BW变量也在累积

2) bw_工作完成后,BackgroundWorker.IsBusy属性将为false。你同意这种行为吗

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

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

3) 移动内存做什么?它是否将内存从源复制到目标,而不更改源中的任何内容?它会复制任何东西吗

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

4) 你说的缓冲区变量是什么?在每个阶段,验证所有缓冲器并确定EXA
   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);