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