Discover MetriCam, the first common and unified real-time 3-D camera SDK for .NET. It supports all major Time-of-Flight cameras e.g., Fotonic, Mesa Imaging, PMD Technologies and ifm electronic. It is also very convenient to use the SDK for grabbing images from a webcam in .NET. Please not also our special edition just for webcams (see pricing and examples below)!
Furthermore, MetriCam also includes support for popular PrimeSense sensors like Kinect and Xtion Pro. The SDK is not only a .NET wrapper for the cameras; it furthermore provides state of the art programming methodology.
Let MetriCam acquire the camera data for you and gain development time by focusing on your main application. Be independent of camera vendors. Have your application always running on newest camera technology:
![]()
![]()
![]()
Coding example
The code example shown in this video is also on the bottom of this page.
Key benefits of MetriCam
With MetriCam it is possible to integrate all major real-time 3-D cameras into your own .NET 4.0 application. You can speed up your own development and concentrate on the problems you wanted to solve using Time-of-Flight cameras or PrimeSense sensors. MetriCam supports:
- multi-camera management (software for calibration of multi-camera setups is not included)
- featuring all fundamental camera features
- thread-safety
- unified interface for all cameras
- events for camera connects and disconnects
- object oriented
- extension with other sensors
Downloads
Get your personal MetriCam evaluation copy right now. Just download the complete package and evaluate it free for 30 days. If you are satisfied using MetriCam for your application development please purchase a developer license for your computer.
MetriCam - The first common and unifed .NET SDK for Time-of-Flight cameras and PrimeSense sensors. MetriCam currently supports cameras from Fotonic, Mesa, PMD, PrimeSense (Kinect / Xtion) and WebCams:
MetriCam - Complete 1.09 MB
Pricing
| PACKAGE | REGULAR PRICE (excl. sales tax) |
|---|---|
| Complete (support for all sensors and WebCam) | € 249,- |
| Single package (support for one sensor type and WebCam) | € 75,- |
| Special Edition (WebCam module only) | € 29,90 |
To get a quote for MetriCam please contact us.
Documents
- Doxygen Documentation
Quickstart guide for MetriCam:
MetriCam Quickstart 303.3 kBMetriCam License:
MetriCam License 130.03 kB
Troubleshooting / Known Issues
IMPORTANT: Your application platform target has to be “x86″. “AnyCPU” and “x64″ is currently not working. However, we are working on a 64-bit version of MetriCam. To have full 64-bit support, the camera manufacturer APIs have to support 64-bit, which is currently not supported by all manufacturer.
PMD CamCube
- If you can’t connect to the camera after having successfully connected before a hard reset often helps. Unplug power and USB of the camera and re-plug it. Basically this is a know issue of the PMD CamCube.
- If you encounter a problem with re-connecting the CamCube within one application session please contact PMD for a plugin (pap / ppp files) update.
MesaCamera.dll
- If you want to connect to a certain camera using its serial number please use SetSerialNumberToConnect as follows:((MesaCamera)camera).SetSerialNumberToConnect(Convert.ToInt32(serialNumber, 16).ToString());Where “serialNumber” is the actual serial number on the back of your camera as a string. You have to convert it in a hexadecimal format first. We will fix this in future releases that the conversion is done within the method.
PrimeSense.dll
- For Kinect and XtionPro please unsure that OpenNI is installed properly. First check if all OpenNI examples are working and the openni.dll is within your path variable or in the working directory of your application.
If you are having trouble installing or using MetriCam please drop us a note: metricam [at] metrilus.de
Code Examples
Example for connecting a PMD CamCube 3. To use another camera within this example, you simply have to add the camera assembly and you basically have to change just one line:
|
1 2 3 4 |
camera = new CamCube3(); //PMD CamCube3
camera = new MesaCamera(); //MESA SR4000
camera = new Fotonic(); //Fotonic C70
camera = new PrimeSense(); //Kinect / Xtion |
Thats it. For further comments, please have a look at the example.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
// This example connects a PMD CamCube, fetches supported channels and gets the distance image, then changes the // integration time and closes the connection. // This example covers the following topics: // - Connecting a camera. // - Fetching DISTANCE data. // - Changing integration time. // - Disconnecting a camera. using System; using System.Collections.Generic; using System.Linq; using System.Text; using MetriCam; namespace SimpleExample { class Program { #region Private Fields private static IMetriCamera camera; #endregion #region Main static void Main(string[] args) { try { // The following line connects a PMD CamCube, if you use another MetriCam-compatible camera, // right-click Reference in the Solution Explorer and select the appropriate MetriCam-DLL. // Replace the following appearances of CamCube3 with the name of the appropriate camera class. // Some methods might not be supported by all cameras (like SetIntegrationTime(int) for WebCam). // Please make sure that the vendor SDK dll is available in the output directory if required. Console.WriteLine("Create new CamCube object."); camera = new CamCube3(); Console.WriteLine("Connect CamCube."); camera.Connect(); Console.WriteLine("Get all supported channels of the camera.\n"); for (int i = 0; i < camera.NumberOfChannels; i++) { Console.WriteLine("\t - " + camera.GetChannelName(i)); } Console.WriteLine("\nTrigger a new frame."); camera.Update(); Console.WriteLine("Receive distance image of camera."); float[,] distances = camera.CalcChannel(camera.GetChannelId(ChannelType.ChannelNameIndex.DISTANCE)); Console.WriteLine("Distance in pixel (20, 30): " + distances[20, 30]); Console.WriteLine("Change integration time to 400"); ((CamCube3)camera).SetIntegrationTime(400); Console.WriteLine("Disconnect CamCube."); camera.Disconnect(); } catch (System.Exception ex) { Console.WriteLine(ex.Message); } Console.WriteLine("Press key to exit."); Console.ReadKey(); } #endregion } } |
Multi-camera applications are as easy as just connecting to a single camera. Please have a look at the following example. You either can connect to multiple cameras of the same type or mix different cameras. E.g. PMD with Mesa or Fotonic with PrimeSense sensors.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
// The following example connects two cameras, fetches some frames from each camera in parallel with two independent threads and // then disconnects the cameras. // This example covers the following topics: // - Connecting multiple cameras. // - Setting & fetching active channels. // - Basic thread synchronization. // - Disconnecting cameras. using System; using System.Collections.Generic; using System.Linq; using System.Text; using MetriCam; using System.Threading; namespace MultiCamera { class Program { #region Private Fields private static IMetriCamera[] camera = new IMetriCamera[2]; private static ManualResetEvent[] waitForFramesFetched = new ManualResetEvent[2]; private static readonly int framesToFetch = 100; #endregion #region Main static void Main(string[] args) { waitForFramesFetched[0] = new ManualResetEvent(false); waitForFramesFetched[1] = new ManualResetEvent(false); try { Console.WriteLine("Create new camera objects."); // If you don't have these cameras available, follow the instructions from SimpleExample to replace the camera types. // Please make sure that the vendor SDK dll is available in the output directory if required. camera[0] = new MesaCamera(); camera[1] = new PrimeSense(); Console.WriteLine("Connecting cameras."); camera[0].Connect(); camera[1].Connect(); // Set the active channels to DISTANCE. If a camera doesn't provide a distance channel, an exception is generated. camera[0].ActiveChannel = camera[0].GetChannelId(ChannelType.ChannelNameIndex.DISTANCE); camera[1].ActiveChannel = camera[1].GetChannelId(ChannelType.ChannelNameIndex.DISTANCE); Console.WriteLine("Starting camera threads."); System.Threading.Thread camera1Thread = new System.Threading.Thread((System.Threading.ParameterizedThreadStart)FetchFrames); System.Threading.Thread camera2Thread = new System.Threading.Thread((System.Threading.ParameterizedThreadStart)FetchFrames); // Create the parameters for the two camera threads. KeyValuePair<int, IMetriCamera> params1 = new KeyValuePair<int,IMetriCamera>(0, camera[0]); KeyValuePair<int, IMetriCamera> params2 = new KeyValuePair<int,IMetriCamera>(1, camera[1]); // Start the threads. camera1Thread.Start(params1); camera2Thread.Start(params2); // Wait for the threads to finish. ManualResetEvent.WaitAll(waitForFramesFetched); Console.WriteLine(); Console.WriteLine("Got " + framesToFetch.ToString() + " frames from both cameras."); } catch (System.Exception ex) { Console.WriteLine(ex.Message); } Console.WriteLine("Press key to exit."); Console.ReadKey(); } #endregion /// <summary> /// This is the method that is run in parallel by the two camera threads. It fetches some frames, then signals it's finished and terminates. /// </summary> /// <param name="obj">A KeyValuePair that holds an index and the reference to the camera object.</param> public static void FetchFrames(Object obj) { KeyValuePair<int, IMetriCamera> parameters = (KeyValuePair<int, IMetriCamera>)obj; IMetriCamera cam = parameters.Value; for (int i = 0; i < framesToFetch; i++) { cam.GetActiveChannel(); Console.Write(cam.ConnectedCameraId.Id); } waitForFramesFetched[parameters.Key].Set(); } } } |
Images can also be stored and process further. Here is an easy example for storing images from a WebCam:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
// This example connects a WebCam, fetches a bitmap or - if bitmap output is not supported - the active channel, stores it to harddisk // and closes the connection. // This example covers the following topics: // - Connecting a camera. // - Fetching a Bitmap object or converting the active channel image to a Bitmap. // - Stroring the Bitmap as BMP-image. // - Disconnecting a camera. using System; using System.Collections.Generic; using System.Linq; using System.Text; using MetriCam; using System.Drawing; namespace StoreOutput { class Program { static void Main(string[] args) { try { // If you chose a different camera here, please make sure that the vendor SDK dll is available in the output directory if required. IMetriCamera camera = new WebCam(); Console.WriteLine("Connecting camera."); camera.Connect(); StoreFrame(camera); Console.WriteLine("Disconnecting camera."); camera.Disconnect(); } catch (System.Exception ex) { Console.WriteLine(ex.Message); } Console.WriteLine("Press key to exit."); Console.ReadKey(); } /// <summary> /// Get a Bitmap object (if supported) from the camera and store it as "bitmap.bmp" in the current directory. /// </summary> /// <param name="camera">Camera from which frame is stored.</param> /// <remarks>If the camera does not support Bitmap output, the frame from the active channel is fetched and converted to a bitmap.</remarks> private static void StoreFrame(IMetriCamera camera) { Bitmap bmp; if (camera is IProvidesBitmapOutput) { Console.WriteLine("Bitmap output is available."); bmp = ((IProvidesBitmapOutput)camera).GetBitmap(); } else { Console.WriteLine("Bitmap output is not available. Converting active channel."); bmp = ConvertToBitmap(camera.GetActiveChannel()); } bmp.Save("example.bmp", System.Drawing.Imaging.ImageFormat.Bmp); } /// <summary> /// Converts a 2-D float array to a grayscale Bitmap. The color depth is reduced to 8 bit. /// </summary> /// <param name="frame">Channel data.</param> /// <returns>Bitmap representation of the channel data.</returns> private static unsafe Bitmap ConvertToBitmap(float[,] frame) { float maxVal = float.MinValue; float minVal = float.MaxValue; // Find minimal and maximal gray value. for (int y = 0; y < frame.GetLength(0); y++) { for (int x = 0; x < frame.GetLength(1); x++) { float val = frame[y, x]; if (val > maxVal) maxVal = val; if (val < minVal) minVal = val; } } Bitmap result = new Bitmap(frame.GetLength(1), frame.GetLength(0), System.Drawing.Imaging.PixelFormat.Format24bppRgb); Rectangle rect = new Rectangle(0, 0, frame.GetLength(1), frame.GetLength(0)); System.Drawing.Imaging.BitmapData bitmapData = result.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); // Scale the gray values to 8-bit range and store them in the bitmap memory. byte* bmpPtr = (byte*)bitmapData.Scan0; for (int y = 0; y < frame.GetLength(0); y++) { byte* linePtr = bmpPtr + bitmapData.Stride * y; for (int x = 0; x < frame.GetLength(1); x++) { byte value = (byte)(byte.MaxValue * (frame[y, x] - minVal) / (maxVal - minVal)); *linePtr++ = value; *linePtr++ = value; *linePtr++ = value; } } result.UnlockBits(bitmapData); return result; } } } |
