我想要做的是复制图像数据的像素数据的子集.在相机线程中的帧更新期间,我试图在单独的字节数组中创建数据的副本.我的代码似乎首先工作,但是经过几次迭代后,我的缓冲区变量从一系列灰度级(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,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,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,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,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!
解决方法
if (bw.IsBusy) return; // replace this.wbmBackBuffer with pFocusData CopyMemory(this.wbmBackBuffer,FrameSize); var args = new List<object>(); args.Add(pFocusData); bw.RunWorkerAsync(args);
//编辑,所以查看你的代码,我几乎没有问题/建议.
1)if if(!e.Updated)返回后,你的BW会好吗?
2)bw_DoWork完成后,BackgroundWorker.IsBusy属性为false.你对这种行为没问题吗?
3)MoveMemory做什么?它是否将内存从SOURCE复制到DESTINATION而不更改SOURCE中的任何内容?它甚至复制任何东西吗?
4)你在说什么缓冲变量?在每个阶段,验证所有BUFFERS并确定缓冲区不同的确切位置.您需要创建函数DumpMemory(IntPtr unmanagedMemory).您可以将IntPtr转换为byte *并使用fixed()语句来执行此操作.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。