Having an issue accessing a bitmap region from two different threads.
-
I can't for the life of me figure out how to access the region from a tick thread which is calling a bgworker(). Here is the original code
private void t_processFrame_Tick(object sender, EventArgs e)
{
if (!_bw_frameProcessor.IsBusy)
{
_bw_frameProcessor.RunWorkerAsync();
}
}private void _bw_frameProcessor_DoWork(object sender, DoWorkEventArgs e)
{
try
{
GetImage = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
g = Graphics.FromImage(GetImage);
g.CopyFromScreen(screen.Bounds.X, 0, 0, 0, GetImage.Size);pbDesktopFeed.Image = (Bitmap)GetImage; motionDetector.ProcessFrame((Bitmap)pbDesktopFeed.Image); } catch (Exception ex) { }
}
Its kind of frustrating because I have been sitting here for 3 days (I have a high tolerance of trying different variations before I burn myself out) trying to figure out why it works fine in Timer_Tick but not when Timer) Tick is running the Backgroundworker. My guess is that it is because of the Threads between the both. I have tried cloning the bitmap inside the background worker
GetImage = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
Bitmap clone = (Bitmap) GetImage.Clone()
g = Graphics.FromImage(clone);
g.CopyFromScreen(screen.Bounds.X, 0, 0, 0, clone.Size);
pbDesktopFeed.Image = (Bitmap)GetImage;
motionDetector.ProcessFrame((Bitmap)pbDesktopFeed.Image);I have tried cloning the image using AForge:
GetImage = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
g = Graphics.FromImage(GetImage );
g.CopyFromScreen(screen.Bounds.X, 0, 0, 0, GetImage .Size);
pbDesktopFeed.Image = (Bitmap)GetImage;
motionDetector.ProcessFrame(AForge.Imaging.Image.Clone((Bitmap)pbDesktopFeed.Image));This however, works fine when I drop it all into the Timer_Tick event.
private void t_processFrame_Tick(object sender, EventArgs e)
{
try
{
GetImage = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
g = Graphics.FromImage(GetImage);
g.CopyFromScreen(screen.Bounds.X, 0, 0, 0, GetImage.Size);pbDesktopFeed.Image = (Bitmap)GetImage; motionDetector.ProcessFrame((Bitmap)pbDesktopFeed.Image); } catch (Exception ex) { }
}
-
I can't for the life of me figure out how to access the region from a tick thread which is calling a bgworker(). Here is the original code
private void t_processFrame_Tick(object sender, EventArgs e)
{
if (!_bw_frameProcessor.IsBusy)
{
_bw_frameProcessor.RunWorkerAsync();
}
}private void _bw_frameProcessor_DoWork(object sender, DoWorkEventArgs e)
{
try
{
GetImage = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
g = Graphics.FromImage(GetImage);
g.CopyFromScreen(screen.Bounds.X, 0, 0, 0, GetImage.Size);pbDesktopFeed.Image = (Bitmap)GetImage; motionDetector.ProcessFrame((Bitmap)pbDesktopFeed.Image); } catch (Exception ex) { }
}
Its kind of frustrating because I have been sitting here for 3 days (I have a high tolerance of trying different variations before I burn myself out) trying to figure out why it works fine in Timer_Tick but not when Timer) Tick is running the Backgroundworker. My guess is that it is because of the Threads between the both. I have tried cloning the bitmap inside the background worker
GetImage = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
Bitmap clone = (Bitmap) GetImage.Clone()
g = Graphics.FromImage(clone);
g.CopyFromScreen(screen.Bounds.X, 0, 0, 0, clone.Size);
pbDesktopFeed.Image = (Bitmap)GetImage;
motionDetector.ProcessFrame((Bitmap)pbDesktopFeed.Image);I have tried cloning the image using AForge:
GetImage = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
g = Graphics.FromImage(GetImage );
g.CopyFromScreen(screen.Bounds.X, 0, 0, 0, GetImage .Size);
pbDesktopFeed.Image = (Bitmap)GetImage;
motionDetector.ProcessFrame(AForge.Imaging.Image.Clone((Bitmap)pbDesktopFeed.Image));This however, works fine when I drop it all into the Timer_Tick event.
private void t_processFrame_Tick(object sender, EventArgs e)
{
try
{
GetImage = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
g = Graphics.FromImage(GetImage);
g.CopyFromScreen(screen.Bounds.X, 0, 0, 0, GetImage.Size);pbDesktopFeed.Image = (Bitmap)GetImage; motionDetector.ProcessFrame((Bitmap)pbDesktopFeed.Image); } catch (Exception ex) { }
}
It's probably pretty simple: only code that is running on the main (UI) thread can access any control in any way: since you moved it to a BackgroundWorker it isn't running on that thread any more, so when you try to access the Image or similar it's failing with an exception. Start by adding a
try...catch
block with Debug.WriteLine statements to check that and consider either Invoking the relevant controls or moving the Control related code back to the UI thread via the Progress reporting mechanism of the BackgroundWorker."I have no idea what I did, but I'm taking full credit for it." - ThisOldTony "Common sense is so rare these days, it should be classified as a super power" - Random T-shirt AntiTwitter: @DalekDave is now a follower!
-
It's probably pretty simple: only code that is running on the main (UI) thread can access any control in any way: since you moved it to a BackgroundWorker it isn't running on that thread any more, so when you try to access the Image or similar it's failing with an exception. Start by adding a
try...catch
block with Debug.WriteLine statements to check that and consider either Invoking the relevant controls or moving the Control related code back to the UI thread via the Progress reporting mechanism of the BackgroundWorker."I have no idea what I did, but I'm taking full credit for it." - ThisOldTony "Common sense is so rare these days, it should be classified as a super power" - Random T-shirt AntiTwitter: @DalekDave is now a follower!
Turns out it was as simple as creating a public void PreviewImageUpdate() outside of the bg worker
private void t_processFrame_Tick(object sender, EventArgs e) {
// UpdateMotionDetectionPreviiw();
if (!_bw_frameProcessor.IsBusy) {
_bw_frameProcessor.RunWorkerAsync();
}
}private void _bw_frameProcessor_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
_bw_frameProcessor.Dispose();
}private void _bw_frameProcessor_DoWork(object sender, DoWorkEventArgs e) {
UpdateMotionDetectionPreview();
}public void UpdateMotionDetectionPreview() {
try {
GetImage = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
g = Graphics.FromImage(GetImage);
g.CopyFromScreen(screen.Bounds.X, 0, 0, 0, GetImage.Size);if (motionDetector.ProcessFrame(GetImage) > 1.02 f) pbDesktopFeed.Image = GetImage; else pbDesktopFeed.Image = GetImage;
} catch (Exception ex) {}
}However, I do plan to take consideration in using a ScreenCaptureScreen() to relay this image to AForge video player to improve the over performance of the framerate since the PB update is too slow.