There is a website that contains a single image from a webcam. Each time the site is hit, the most current image of the webcam is displayed. I want to make a real time video by hitting the site continuously.
I have searched and tried several things but cannot get it to refresh at a reasonable rate.
public MainWindow()
{
InitializeComponent();
this.picUri = "http://someurl";
this.thWatchVideo = new Thread(new ThreadStart(Watch));
_image = new BitmapImage();
_image.BeginInit();
_image.CacheOption = BitmapCacheOption.None;
_image.UriCachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
_image.CacheOption = BitmapCacheOption.OnLoad;
_image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
_image.UriSource = new Uri(this.picUri);
_image.EndInit();
this.imgVideo.Source = _image;
this.thWatchVideo.Start();
}
public void Watch()
{
while(true)
{
UpdateImage();
}
}
public void UpdateImage()
{
if (this.imgVideo.Dispatcher.CheckAccess())
{
_image = new BitmapImage();
_image.BeginInit();
_image.CacheOption = BitmapCacheOption.None;
_image.UriCachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
_image.CacheOption = BitmapCacheOption.OnLoad;
_image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
_image.UriSource = new Uri(this.picUri);
_image.EndInit();
this.imgVideo.Source = _image;
}
else
{
UpdateImageCallback del = new UpdateImageCallback(UpdateImage);
this.imgVideo.Dispatcher.Invoke(del);
}
}
Problem is, this is too slow and takes too long to refresh and the app just hangs.
I got this to work in Windows Forms with the PictureBox control but cannot get it to work in WPF. I refuse to believe that WPF is inferior to forms.
This app will always just hang (whether winforms or WPF) because you've got an infinite loop running everything it does on the UI thread. Your app hangs because you're not allowing the UI thread any time to process user input (such as resizing the window or trying to close the app).
With regard to your performance: have you tried profiling your code? I suspect that the problem is to do with you repeatedly hammering a webserver for an image, since you're never likely to get enough requests-per-second to make any kind of real-time video from static images. (There's a reason that we have video streaming codecs!)
instead of recreating whole image try to change only UriSource property.
Check out my answer to this: Showing processed images from an IP camera
Also, make sure the communication is done on a separate thread.
I suggest that the Bitmap image is a dependency object being created on a non-GUI thread. You then invoke UpdateImage on the GUI thread. Since the bitmap image dependency object wasn't created on/(owned by) the GUI thread, you get the "different thread owns it" error.
How about this as a workaround?
Copy the image temporarily to a local file location in your Watch routine.
Add a Thread.Sleep to the watch routine so that you don't hammer the CPU with the endless loop on this thread.
Use BeginInvoke instead of Invoke.
Load and update the image in the UpdateImage routine so that the image and the imgVideo objects are on the GUI thread. Update the image by reading it from your local file copy.
Without knowing the specifics of how you make Watch run on its own thread (using Background worker?) I think this approach will work for you.
Related
I have a Silverlight 5 application that uses ImageTools for Silverlight to save a Canvas to a PNG image. I understand that I need to work with the Canvas on the UI thread and have the following code, which works:
if (saveFileDialog.ShowDialog() == true)
{
var stream = saveFileDialog.OpenFile();
writeableBitmap.Dispatcher.BeginInvoke(delegate
{
ExtendedImage extendedImage = writeableBitmap.ToImage();
new PngEncoder().Encode(extendedImage, stream);
});
}
The problem is that if the Canvas is very large it can take a noticeable time for the code in the BeginInvoke to complete. Since this is running on the UI thread it freezes the browser window during its execution.
After the user selects the location of where to save the exported image, I'd like to popup some child window that tells the user, "Please wait...", then run the image saving code posted above, and afterwards hide the child window automatically, but I'm not having much luck accomplishing that.
For starters, the BeginInvoke code runs asynchronously, so how do I know when it has completed?
If you need to call ToImage() on the UI Thread thats fine, but it doesnt mean you have to encode the image too.
Something like this will ensure the UI stays responsive.
if (saveFileDialog.ShowDialog() == true)
{
using (var stream = saveFileDialog.OpenFile())
{
writeableBitmap.Dispatcher.BeginInvoke(delegate
{
ExtendedImage extendedImage = writeableBitmap.ToImage();
System.Threading.ThreadPool.QueueUserWorkItem(item =>
{
new PngEncoder().Encode(extendedImage, stream);
});
});
}
}
Okay I have a an wpf image object, and it displays live images. So I have used a timer to refresh the image.
public void LoadLiveImage()
{
System.Windows.Media.PixelFormat pf = PixelFormats.Bgr24;
int stride = 4 * ((24 * cameraFrame.img_width + 31) / 32);
BitmapSource bmpImage= BitmapSource.Create(cameraFrame.img_width, cameraFrame.img_height, cameraFrame.img_width, cameraFrame.img_height, pf, null, cameraFrame.img_pixel, stride);
RemoteCameraImage.Source = bmpImage;
}
void dispatcherTimer_Tick(object sender, EventArgs e)
{
LoadLiveImage();
}
No issues, this is working fine.
However, I tried to move this to a thread and no image is displayed.
private void showLiveImage()
{
while (this.isCameraViewOpen)
{
if (RemoteCameraImage.Dispatcher.CheckAccess())
{
System.Windows.Media.PixelFormat pf = PixelFormats.Bgr24;
int stride = 4 * ((24 * cameraFrame.img_width + 31) / 32);
BitmapSource bmpImage = BitmapSource.Create(cameraFrame.img_width, cameraFrame.img_height, cameraFrame.img_width, cameraFrame.img_height, pf, null, cameraFrame.img_pixel, stride);
RemoteCameraImage.Source = bmpImage;
System.Threading.Thread.Sleep(5);
}
else
this.RemoteCameraImage.Dispatcher.Invoke(DispatcherPriority.Normal, new ImageUpdater(this.showLiveImage));
}
}
The showLiveImage isrunning as a thread. The image is received, there is not problem in that. I tested by saving the img_pixel array to a bmp file and file is generated. Just that the image is not displayed on. So I put a messagebox to be shown after the source is assigned, and then I m able to see the image on Image object. SO I think the problem I increased the Sleep time, but even the image is not refreshed. WHAT could be the issue?
EDIT:
After moving the code which was updating the image to another function, it works fine. And I used BeginInvoke() instead of invoke an all works fine.
Sometime ago I had similiar problems and I found this on Stackoverflow, which sovled it for me
Images on second thread
WPF Dispatcher {"The calling thread cannot access this object because a different thread owns it."}
If you have no intention of modifying the image once you have created
it you can freeze it using Freezable.Freeze and then assign to
GeneratedImage in the dispatcher delegate (the BitmapImage becomes
read-only and thus threadsafe as a result of the Freeze). The other
option would be to load the image into a MemoryStream on the
background thread and then create the BitmapImage on the UI thread in
the dispatcher delegate with that stream and the StreamSource property
of BitmapImage.
Try to use the Application.Current.Dispatcher instead of the one you used.
I believe this will do the trick.
Cheers
I'm building a custom control for Windows Phone 7+ that can do augmented reality image processing. The control works wonderfully in practice (when I run the app), but because I have the image processing running on a separate thread, it breaks when I try to open the page in Blend or the Visual Studio designer.
Here's an example of the thread I'm trying to run (basically taken from http://msdn.microsoft.com/en-us/library/hh202982(v=vs.92).aspx) :
public override void OnApplyTemplate()
{
// assigning template stuff, initializing my camera
_myManualResetEvent = new ManualResetEvent(true);
_myCameraProcessingThread = new System.Threading.Thread(ProcessingMethod);
_myCameraProcessingThread.Start();
}
void ProcessingMethod()
{
int[] myBuffer = new int[640 * 480];
while(_someCondition)
{
_myManualResetEvent.WaitOne();
_myCamera.GetPreviewBufferArgb32(myBuffer);
// do my processing stuff
_myManualResetEvent.Set();
}
}
This breaks the ever-loving heck out of Blend. Would love to know why.
It looks like you are doing a lot of run-time stuff in the OnApplyTemplate method.
This will get called when Blend or Visual Studio instantiates the design view of your control.
You should either check to see if you are in design mode using the DesignMode:
if (!DesignMode)
{
_myManualResetEvent = new ManualResetEvent(true);
_myCameraProcessingThread = new System.Threading.Thread(ProcessingMethod);
_myCameraProcessingThread.Start();
}
or move this code into a method/event handler that only gets called when the application actually runs.
We are using the WPF FormattedText object to determine text size in a service that grabs the latest news headlines from an RSS feed. The text retrieved needs to be in a specified canvas size. The service runs the code every 10 seconds and uses up to 2 threads if one takes longer than that. I'm using TaskFactory (which I've overridden the LimitedConcurrencyLevelTaskScheduler to limit to the amount of threads I specified).
This works great, except after several days (the length is variable), we start to get the following exceptions. The same code was working fine before we started using TPL to make it mult-threaded.
I need help figuring out what this is caused by. A few thoughts I'm looking into are: thread collisions holding on to a TTF file, memory issue, the dispatcher (see the stack trace) isn't playing nicely with the TaskFactory, other??
We don't have good profiling setup, but we've looked at the TaskManager when the exception is occurring and memory usage looks normal.
My next attempt is to use the TextBlock object and see if the exception is avoided.
Error Message: The system cannot find the file specified
Error Source: WindowsBase
Error Target Site: UInt16 RegisterClassEx(WNDCLASSEX_D)
Exception Stack Trace:
at MS.Win32.UnsafeNativeMethods.RegisterClassEx(WNDCLASSEX_D wc_d)
at MS.Win32.HwndWrapper..ctor(Int32 classStyle, Int32 style, Int32 exStyle, Int32 x, Int32 y, Int32 width, Int32 height, String name, IntPtr parent, HwndWrapperHook[] hooks)
at System.Windows.Threading.Dispatcher..ctor()
at System.Windows.Threading.Dispatcher.get_CurrentDispatcher()
at System.Windows.Media.TextFormatting.TextFormatter.FromCurrentDispatcher(TextFormattingMode textFormattingMode)
at System.Windows.Media.FormattedText.LineEnumerator..ctor(FormattedText text)
at System.Windows.Media.FormattedText.DrawAndCalculateMetrics(DrawingContext dc, Point drawingOffset, Boolean getBlackBoxMetrics)
at System.Windows.Media.FormattedText.get_Metrics()
at
(my method using the FormattedText, which is in a loop)
private static Size GetTextSize(string txt, Typeface tf, int size)
{
FormattedText ft = new FormattedText(txt, new CultureInfo("en-us"), System.Windows.FlowDirection.LeftToRight, tf, (double)size, System.Windows.Media.Brushes.Black, null, TextFormattingMode.Display);
return new Size { Width = ft.WidthIncludingTrailingWhitespace, Height = ft.Height };
}
EDIT: so far I've tried placing a lock around the code that calls this function, and calling it inside the CurrentDispatcher.Invoke method like so:
return (Size)Dispatcher.CurrentDispatcher.Invoke(new Func<Size>(() =>
{
FormattedText ft = new FormattedText(txt, new CultureInfo("en-us"), System.Windows.FlowDirection.LeftToRight, tf, (double)size, System.Windows.Media.Brushes.Black, null, TextFormattingMode.Display);
return new Size { Width = ft.WidthIncludingTrailingWhitespace, Height = ft.Height };
}));
EDIT: I've found links to others having similar, but not the exact problem.
http://www.eggheadcafe.com/software/aspnet/31783898/problem-creating-an-bitmapsource-from-an-hbitmap-in-threaded-code.aspx ~having a similar problem, but no answers
System.Windows.Media.DrawingVisual.RenderOpen() erroring after a time ~having a similar problem, but no answers
http://connect.microsoft.com/VisualStudio/feedback/details/361469/net-3-5-sp1-breaks-use-of-wpf-under-iis# ~ similar exception, but we're not using 3.5SP1 or IIS 7.
I've also submitted this through the Microsoft Connect site (please vote for it if you are having a similar problem).
https://connect.microsoft.com/WPF/feedback/details/654208/wpf-formattedtext-the-system-cannot-find-the-file-specified-exception-in-a-service
EDIT: Response from Microsoft:
"WPF objects need to be created on Dispatcher threads, not thread-pool threads. We usually recommend dedicating a thread to run the dispatcher loop to service requests to create objects and return
them frozen. Thanks, WPF Team" ~ How would I implement this?
EDIT: final solution thanks to NightDweller
if(Application.Current == null) new Application();
(Size)Application.Current.Dispatcher.CurrentDispatcher.Invoke(new Func<Size>(() =>
{
...});
EDIT: When I deployed the change (new Application();), I got an error logged " Cannot create more than one System.Windows.Application instance in the same AppDomain."
Error Source: PresentationFramework
Error Target Site: Void .ctor()
A shot in the dark:
The stack trace seems to show that WPF does not find a Dispatcher in the thread executing GetTextSize, so it has to create a new one, which involves creating a handle to a window.
Calling this every 10 seconds means 8'640 threads, thus windows per day. According to Mark Russinovich, there is a limit of 32 K windows per session, which may explain the error in RegisterClassEx.
An idea to overcome this is to read the current dispatcher from your main thread and set it in your tasks.
Edit:
I had another look and it looks like one cannot set the Dispatcher of a thread (it's created automatically).
I'm sorry, I am unable to understand what is going on here.
In order to compute the text size, WPF needs a FormattedText instance, which is stored as a member of the Dispatcher class. The existing Dispatchers are stored in a list of weak references. Each one is associated with a specific thread.
Here, it looks like new Dispatcher instances are created many, many times.
So, either the calling thread is new or memory is quite low and the weak references have been discarded.
The first case (new thread) is unlikely as the task scheduler uses the thread pool, which has about 25 threads per core (if I remember correctly), which is not enough to deplete the pool of ATOMs or windows.
In the second case, the depletion of resource is unlikely as the HwndWrapper is IDisposable and the Dispose method takes care of freeing the registered class.
As you already know from the info you provided, All UI elements (FormattedText is one) have to be created on the UI thread.
The code you are looking for is:
return (Size)Application.Current.Dispatcher.CurrentDispatcher.Invoke(new Func<Size>(() =>
{
FormattedText ft = new FormattedText(txt, new CultureInfo("en-us"), System.Windows.FlowDirection.LeftToRight, tf, (double)size, System.Windows.Media.Brushes.Black, null, TextFormattingMode.Display);
return new Size { Width = ft.WidthIncludingTrailingWhitespace, Height = ft.Height };
}));
Notice the Application.Current - you want the "Application" dispatcher which is the dispatcher for the UI thread in WPF applications.
Your current code actually creates a dispatcher for the current thread so you didn't really change the executing thread (see here regarding the dispatcher)
Have you renamed anything? If yes, check that link: WPF Prism: Problem with creating a Shell
Because I have a tool that needs to do a lot of work at one point, I want to show a window with some text and a progressbar while doing the work.
My problem is, that because of the huge load of the work, the window never gets drawn or updated.
I know that I usually should use an extra thread for the work, but I have to use 2 collections and the database service from the current thread.
The current code is something like
StatusWindow SW = new StatusWindow();
StatusViewModel SVM = new StatusViewModel();
SVM.MaxNum = BigNumber;
SW.Show();
for (int i=0; i<BigNumber; i++)
{
List<AType> ItemsToCreate = Func1();
List<AType> ItemsToDelete = Func2();
foreach (AType cItem in ItemsToCreate)
DB.CreateItem(cItem);
foreach (AType cItem in ItemsToDelete)
DB:DeleteItem(cItem);
SVM.CurrentNum = i;
}
SW.Close();
I also read about the Dispatcher, but i don't think it is very usable in this scenario, since there would be too much access to the main thread.
Any suggestions?
Thanks
I recommend reading the article (Build More Responsive Apps With The Dispatcher) from MSDN magazine that describes how WPF works with the Dispatcher when using BackgroundWorker.
You can pass the two collections and whatever else you'd like to worker threads as long as the objects you are accessing can be accessed from different threads.
int[] arrayofInt = new int[10]
ThreadPool.QueueUserWorkItem(s =>
{
//access the array in the worker thread
arrayofInt[0] = 10;
});
When finished with the work, you need to send a message to the dialog that it should be closed now. Do that by firing an event in your thread that is handled by your dialog.