Reputation: 845
I am using EmguCV in WPF and i found this example tp capture image , I want to use bs1 in my some other method Method3(), but i am getting error that object belong to some other thread, anyone has any idea what is the problem ? bs1 is after all a global variable
BitmapSource bs1;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
capture = new Capture(); ///capture image
timer = new DispatcherTimer(); // timer object
timer.Interval = new TimeSpan(500);
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
using ( Image<Bgr, byte> Frame = capture.QueryFrame())
{
if (Frame != null)
{
bs1 = ToBitmapSource(Frame);
webcam.Source = ToBitmapSource(Frame); // ToBitmapSource convert image to bitmapsource webcam is a picture in mainwindow
Frame.Save("fg.jpeg"); //this work but use lot of processing
}
}
}
public void Method3_click (...)
{
use_of_bs1(bs1);
}
private void use_of_bs1()
{
data.Text = "waiting...";
System.Threading.ThreadPool.QueueUserWorkItem(Startwork);
}
private void Startwork(object state)
{
try
{
_work = _worker.bs1_analysis(bs1); // it is where bs1 giving thread errorbs1_analysis is library function
}
catch (Exception ex)
{
Dispatcher.BeginInvoke(new ShowworkInformationDelegate(ShowworkInformation));
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
Dispatcher.BeginInvoke(new ShowWorkInformationDelegate(ShowWorkInformation));
}
/// ToBitmapsource function is
public static BitmapSource ToBitmapSource(Emgu.CV.IImage image)
{
using (System.Drawing.Bitmap source = image.Bitmap)
{
IntPtr ptr = source.GetHbitmap();
BitmapSource bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(ptr, IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
DeleteObject(ptr);
return bs;
}
}
Upvotes: 0
Views: 758
Reputation:
If you create a wpf resource and want to use it on a different thread, you can call Freeze()
on the object before passing it on. That will make it immutable and legal to use on another thread.
Upvotes: 1
Reputation: 21449
In WPF, UI elements can only be accessed and used by the same thread that created them (except for freezable elements). In your code, bs1
is created in the main UI thread. The timer being a different thread cannot access that resource.
Whenever you want to do something with a UI element that is created on the main UI thread, do the following:
Dispatcher.Invoke(DispatcherPriority.Normal, new Action(()=>DoSomeCodeWithUIElement()));
Use Dispatcher.Invoke
if you want the operation to run synchronously or Dispatcher.BeginInvoke
if you want the asynchronous call.
Where DoSomeCodeWithUIElement
is a method in which you access and eventually update UI elements.
Upvotes: 2
Reputation: 7180
On the timer event (timer_Tick) you're on a different thread that the one where bs1 belongs
You need to execute the event on the main thread. Something like:
void timer_Tick(object sender, EventArgs e)
{
Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(
delegate {
using ( Image<Bgr, byte> Frame = capture.QueryFrame())
{
if (Frame != null)
{
bs1 = ToBitmapSource(Frame);
webcam.Source = ToBitmapSource(Frame); // ToBitmapSource convert image to bitmapsource
Frame.Save("fg.jpeg"); //this work but use lot of processing
}
}}));
}
Upvotes: 1
Reputation: 11601
From what you have described, the bs1 was associated with the Window.Dispatcher, so when you accessed it inside Method3()
, there was an exception raised. To fix that issue, you could do something like this
public void Method3()
{
Action<BitmapSource> useBs1 = (source) => use_of_bs1(source);
if(Thread.CurrentThread == this.Dispatcher.Thread)
{
useBs1(bs1);
}
else
{
this.Dispatcher.Invoke(DispatcherPriority.Normal,userBs1, bs1);
}
}
Upvotes: 1