I would like to use a timer in my C# program with millisecond accuracy to keep a camera in sync with some events and keep shooting a picture every 250ms (or 1/4 sec, or I might adjust it to even shorter times like 200ms or 100ms). The normal timer event can be used for this.
But I wonder what would be the best way to do this.
Also I think I should NOT write the whole capture routine in it, but instead just raise another thread (multi-threading) to process the image with some vision logic on it, as my vision logic takes about 1 seconds, so I will get some queue here.
If my vision algorithms would take 1 seconds per thread, would this mean that on a multicore (12 cores) PC that such code thread would go to the next available free processor or am I thinking to easily about multitasking?
2
I want to add another point to Danny Varod’s already good answer, focusing on the question in your last paragraph.
Assuming you’re handling the events raised by the multimedia timer or another high-resolution timer, you now need to dispatch your heavy processing task in another thread. .NET’s libraries make this relatively easy using the Task Parallelism Library (TPL) if you’re using .NET 4.0, or directly using the ThreadPool for earlier versions.
Let’s say you have this (very sketchy) code:
private void ProcessImage(object imageToProcess)
{
// Do whatever. Process the image, save the results, etc.
// This is the 1-sec process.
}
private void myTimer_Elapsed()
{
Image capturedImage = myCamera.CaptureImage(); // or whatever.
Task.Factory.StartNew(ProcessImage, capturedImage);
}
This starts a new Task (a wrapper around an asynchronous method) that is launched on a ThreadPool thread. If your machine has multiple CPUs and multiple cores, the ThreadPool will have a lot of available threads, and will process many of these requests in parallel. Hopefully, this will allow the processing tasks to keep up with the image capture tasks. You might have to read up on the threadpool and see how to tweak the available threads for machines with lots of CPUs, but the worst case scenario is that the processing tasks get backlogged, but the threadpool (which is at the heart of the Tasks library) will just queue them up and get to them eventually.
Note, though, that you are not guaranteed that the tasks will be executed in the order they are captured.
If you’re using an older version of C#, replace the call to Task.Factory.StartNew
with calls to ThreadPool.QueueUserWorkItem
, which in this case (where we’re not using continuations and aggregated error handling) will be practically identical in usage.
1
-
Use the Multimedia Timer. It works well with even 10mS intervals (and perhaps less).
-
When the timer event occures, you may have to dispatch to the main thread (or another single thread), depending on whether or not your camera API and image processing API support access from multiple threads. Use the Dispatcher class for this.
-
Make sure your event handler is shorter than the timer interval, when the timer event occurs, check if the event handler is busy and if so decide what to do (e.g. ignore event).
-
Decide what to do with the images, either create a new image at each event (not recommended due to GC cost), or reuse image buffer so long as the image size and color depth hasn’t changed. You may want to create an output image for each stage of your image processing, to enable pipe-lining the image processing and enable the image processing to modifying image size/color depth. If your image processing API supports multi-threading, then you will need to make sure you are not using the same image buffer simultaneously (e.g. using pipe-line synchronization or using different images for each event).
If your processing takes ~1Sec, then you will end up with a growing queue of images (or amount of threads) because you won’t be able to keep up. If you can’t wait a long time for the processing to end after the capturing does, you will need to refactor the image processing code. Try moving it to the GPU (using GPGPU).
2