我在WPF中使用EmguCV并且我发现这个示例tp捕获图像,我想在我的其他方法Method3()中使用bs1,但是我得到错误,该对象属于其他一些线程,任何人都知道什么是问题吗? bs1毕竟是一个全局变量
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函数是
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;
}
}
答案 0 :(得分:2)
在WPF中,UI元素只能由创建它们的同一线程访问和使用(freezable元素除外)。在您的代码中,bs1
在主UI线程中创建。作为不同线程的计时器无法访问该资源。
每当您想要对主UI线程上创建的UI元素执行某些操作时,请执行以下操作:
Dispatcher.Invoke(DispatcherPriority.Normal, new Action(()=>DoSomeCodeWithUIElement()));
如果希望操作同步运行,请使用Dispatcher.Invoke
;如果需要异步调用,请使用Dispatcher.BeginInvoke
。
其中DoSomeCodeWithUIElement
是您访问并最终更新UI元素的方法。
答案 1 :(得分:1)
根据您的描述,bs1与Window.Dispatcher关联,因此当您在Method3()
内访问它时,会引发异常。要解决这个问题,你可以做这样的事情
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);
}
}
答案 2 :(得分:1)
在计时器事件(timer_Tick)上,你在与bs1所属的线程不同的线程上
您需要在主线程上执行该事件。类似的东西:
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
}
}}));
}
答案 3 :(得分:1)
如果您创建了一个wpf资源并希望在另一个线程上使用它,则可以在传递之前调用该对象上的Freeze()
。这将使其在另一个线程上使用它是不可变的和合法的。