Images Example

The Ultraleap Tracking Service creates the tracking data provided in a LEAP_TRACKING_EVENT() struct by analyzing a set of stereo images taken by the Ultraleap Hand Tracking Camera. The image set used to create a frame of data can be obtained by calling LeapRequestImages(). LeapC writes the set of stereo images to a buffer that you supply; stacked with the left image on top of the right image.

After you call LeapRequestImages(), LeapC dispatches a LEAP_IMAGE_COMLETE_EVENT message through the usual message pump when the image buffer has been completely written. The message struct also contains the image properties.


The ImageSample.c program uses the callback mechanism defined by ExampleConnection.c described in the other examples. Instead of printing out frame information, though, ImageSample uses the frame information to request the associated set of stereo images.

For simplicity, ImageSample only handles a single image request at a time. The code skips images for any frames until the current pending request is complete. In general, you will receive the image before the next frame. If the system becomes overloaded, image completion could slip a few frames behind. The method used in the example would skip the images for the interveaning frames, which might not be acceptable.

It is also possible to lose image requests under load. In this case, the example’s method would stop drawing frames altogether. Adding a request time-out to correct this pitfall is left as an exercise for the reader.

The buffer size needed for a set of images is determined by the image dimensions, the image bytes-per-pixel, and the number of images in the set. For a typical image from a Leap Motion Controller, this size is:

640 (width) * 240 (height) * 1 (byte-per-pixel) * 2 (images) = 307200 bytes

The Stereo IR 170 (another Ultraleap Hand Tracking Camera), provides images with different resolutions and hence require different buffer sizes. Because of this, you should always determine the required buffer size dynamically, using an image request error callback as illustrated in this example.

Whenever a request error occurs (allocating a buffer that is too small is an error) the LEAP_IMAGE_FRAME_REQUEST_ERROR_EVENT struct provides the current, required buffer size. You can update the size used to allocate your image buffer with this value and either re-request the image or skip it and do better on the next one.

 1 #undef __cplusplus
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 #include "LeapC.h"
 6 #include "ExampleConnection.h"
 8 /** Callback for when the connection opens. */
 9 static void OnConnect(){
10   printf("Connected.\n");
11 }
13 /** Callback for when a device is found. */
14 static void OnDevice(const LEAP_DEVICE_INFO *props){
15   printf("Found device %s.\n", props->serial);
16 }
18 /** Callback for when a frame of tracking data is available. */
19 static void OnFrame(const LEAP_TRACKING_EVENT *frame){
20   printf("Frame %lli with %i hands.\n", (long long int)frame->info.frame_id, frame->nHands);
21   for(uint32_t h = 0; h < frame->nHands; h++){
22     LEAP_HAND* hand = &frame->pHands[h];
23     printf("    Hand id %i is a %s hand with position (%f, %f, %f).\n",
24                 hand->id,
25                 (hand->type == eLeapHandType_Left ? "left" : "right"),
26                 hand->palm.position.x,
27                 hand->palm.position.y,
28                 hand->palm.position.z);
29   }
30 }
32 /** Callback for when an image is available. */
33 static void OnImage(const LEAP_IMAGE_EVENT *imageEvent){
34     printf("Received image set for frame %lli with size %lli.\n",
35            (long long int)imageEvent->info.frame_id,
36            (long long int)imageEvent->image[0].properties.width*
37            (long long int)imageEvent->image[0].properties.height*2);
38 }
40 int main(int argc, char** argv) {
41   //Set callback function pointers
42   ConnectionCallbacks.on_connection          = &OnConnect;
43   ConnectionCallbacks.on_device_found        = &OnDevice;
44   ConnectionCallbacks.on_frame               = &OnFrame;
45   ConnectionCallbacks.on_image               = &OnImage;
47   LEAP_CONNECTION *connection = OpenConnection();
48   LeapSetPolicyFlags(*connection, eLeapPolicyFlag_Images, 0);
50   printf("Press Enter to exit program.\n");
51   getchar();
52   return 0;
53 }
54 //End-of-Sample.c

Note that this example does not attempt to display image data graphically. See Textured Quad Example for an example that uses the GLUT library to create window context for drawing the images.

Back to top