00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 import ctypes
00025 import array
00026 import itertools
00027 FORMAT_RGB = 0
00028 FORMAT_BAYER = 1
00029 FORMAT_11_BIT = 0
00030 FORMAT_10_BIT = 1
00031 LED_OFF = 0
00032 LED_GREEN = 1
00033 LED_RED = 2
00034 LED_YELLOW = 3
00035 LED_BLINK_YELLOW = 4
00036 LED_BLINK_GREEN = 5
00037 LED_BLINK_RED_YELLOW = 6
00038
00039
00040 def _try_load(paths, names, extensions):
00041 out_accum = []
00042 try:
00043 return _try_load_np(paths, names, extensions)
00044 except ImportError, e:
00045 out_accum.append(e)
00046 for x in itertools.product(paths, names, extensions):
00047 try:
00048 return ctypes.cdll.LoadLibrary('%s%s%s' % x)
00049 except OSError, e:
00050 out_accum.append(e)
00051 print("Here are all of the things we tried...")
00052 for x in out_accum:
00053 print(x)
00054 raise OSError("Couldn't find shared library, was it built properly?")
00055
00056
00057 def _try_load_np(paths, names, extensions):
00058 import numpy as np
00059 for path, name, extension in itertools.product(paths, names, extensions):
00060 try:
00061 return np.ctypeslib.load_library(name + extension, path)
00062 except OSError:
00063 pass
00064
00065 def _setup_shared_library():
00066 """Types all of the shared library functions
00067
00068 These headers are copied directly from libfreenect.h in order to simplify
00069 updating
00070
00071 Returns:
00072 (fn, freenect_depth_cb, freenect_rgb_cb) where
00073 fn: freenect dynamic library updated with type info
00074 freenect_depth_cb: ctypes callback wrapper for depth
00075 freenect_rgb_cb: ctypes callback wrapper for rgb
00076 """
00077
00078 def mk(res, fun, arg):
00079 fun.restype = res
00080 fun.argtypes = arg
00081 from ctypes import c_int, c_void_p, c_uint32, c_double, c_int16, POINTER
00082 c_int16_p = POINTER(c_int16)
00083 c_double_p = POINTER(c_double)
00084
00085 fn = _try_load(['', '../c/build/lib/', '/usr/local/lib/'],
00086 ['libfreenect'],
00087 ['.so', '.dylib', '.dll'])
00088
00089 mk(c_int, fn.freenect_init, [c_void_p, c_void_p])
00090
00091 mk(c_int, fn.freenect_shutdown, [c_void_p])
00092
00093 mk(c_int, fn.freenect_process_events, [c_void_p])
00094
00095 mk(c_int, fn.freenect_num_devices, [c_void_p])
00096
00097 mk(c_int, fn.freenect_open_device, [c_void_p, c_void_p, c_int])
00098
00099 mk(c_int, fn.freenect_close_device, [c_void_p])
00100
00101 mk(None, fn.freenect_set_user, [c_void_p, c_void_p])
00102
00103 mk(c_void_p, fn.freenect_get_user, [c_void_p])
00104
00105 freenect_depth_cb = ctypes.CFUNCTYPE(None, c_void_p, c_void_p, c_uint32)
00106
00107 mk(None, fn.freenect_set_depth_callback, [c_void_p, freenect_depth_cb])
00108
00109 freenect_rgb_cb = ctypes.CFUNCTYPE(None, c_void_p, c_void_p, c_uint32)
00110
00111 mk(None, fn.freenect_set_rgb_callback, [c_void_p, freenect_rgb_cb])
00112
00113 mk(c_int, fn.freenect_set_rgb_format, [c_void_p, c_int])
00114
00115 mk(c_int, fn.freenect_set_depth_format, [c_void_p, c_int])
00116
00117 mk(c_int, fn.freenect_start_depth, [c_void_p])
00118
00119 mk(c_int, fn.freenect_start_rgb, [c_void_p])
00120
00121 mk(c_int, fn.freenect_stop_depth, [c_void_p])
00122
00123 mk(c_int, fn.freenect_stop_rgb, [c_void_p])
00124
00125 mk(c_int, fn.freenect_set_tilt_degs, [c_void_p, c_double])
00126
00127 mk(c_int, fn.freenect_set_led, [c_void_p, c_int])
00128
00129 mk(c_int, fn.freenect_get_raw_accel, [c_void_p, c_int16_p, c_int16_p, c_int16_p])
00130
00131 mk(c_int, fn.freenect_get_mks_accel, [c_void_p, c_double_p, c_double_p, c_double_p])
00132 return fn, freenect_depth_cb, freenect_rgb_cb
00133
00134
00135
00136 def _populate_namespace():
00137 _fn, depth_cb, rgb_cb = _setup_shared_library()
00138 header = 'freenect_'
00139 for x in dir(_fn):
00140 if x.startswith(header):
00141 globals()[x[len(header):]] = getattr(_fn, x)
00142 return depth_cb, rgb_cb
00143
00144
00145 def raw_accel(dev):
00146 """Convenience wrapper for raw accelerometers
00147
00148 Args:
00149 dev: ctypes dev pointer
00150
00151 Returns:
00152 Tuple of (x, y, z) as ctype.c_int16 values
00153 """
00154 x, y, z = ctypes.c_int16(), ctypes.c_int16(), ctypes.c_int16()
00155 get_raw_accel(dev, ctypes.byref(x), ctypes.byref(y),
00156 ctypes.byref(z))
00157 return x, y, z
00158
00159
00160 def mks_accel(dev):
00161 """Convenience wrapper for mks accelerometers
00162
00163 Args:
00164 dev: ctypes dev pointer
00165
00166 Returns:
00167 Tuple of (x, y, z) as ctype.c_double values
00168 """
00169 x, y, z = ctypes.c_double(), ctypes.c_double(), ctypes.c_double()
00170 get_mks_accel(dev, ctypes.byref(x), ctypes.byref(y),
00171 ctypes.byref(z))
00172 return x, y, z
00173
00174
00175 def runloop(depth=None, rgb=None):
00176 """Sets up the kinect and maintains a runloop
00177
00178 This is where most of the action happens. You can get the dev pointer from the callback
00179 and let this function do all of the setup for you. You may want to use threads to perform
00180 computation externally as the callbacks should really just be used for copying data.
00181
00182 Args:
00183 depth: A function that takes (dev, depth, timestamp), corresponding to C function.
00184 If None (default), then you won't get a callback for depth.
00185 rgb: A function that takes (dev, rgb, timestamp), corresponding to C function.
00186 If None (default), then you won't get a callback for rgb.
00187 """
00188 depth = depth_cb(depth if depth else lambda *x: None)
00189 rgb = rgb_cb(rgb if rgb else lambda *x: None)
00190 ctx = ctypes.c_void_p()
00191 if init(ctypes.byref(ctx), 0) < 0:
00192 print('Error: Cant open')
00193 dev = ctypes.c_void_p()
00194 if open_device(ctx, ctypes.byref(dev), 0) < 0:
00195 print('Error: Cant open')
00196 set_depth_format(dev, 0)
00197 set_depth_callback(dev, depth)
00198 start_depth(dev)
00199 set_rgb_format(dev, FORMAT_RGB)
00200 set_rgb_callback(dev, rgb)
00201 start_rgb(dev)
00202 while process_events(ctx) >= 0:
00203 pass
00204
00205
00206 def _load_numpy():
00207 try:
00208 import numpy as np
00209 return np
00210 except ImportError, e:
00211 print('You need the numpy library to use this function')
00212 raise e
00213
00214
00215 def depth_cb_decorator(func):
00216 """Converts the raw depth data into a python string
00217
00218 Args:
00219 func: A function that takes (dev, data, timestamp), corresponding to C function
00220 except that data is a python string corresponding to the data.
00221
00222 Returns:
00223 Function that takes (dev, depth, timestamp) that returns output of func
00224 """
00225
00226 def depth_cb(dev, depth, timestamp):
00227 nbytes = 614400
00228 return func(dev, ctypes.string_at(depth, nbytes), timestamp)
00229 return depth_cb
00230
00231
00232 def rgb_cb_decorator(func):
00233 """Converts the raw RGB data into a python string
00234
00235 Args:
00236 func: A function that takes (dev, data, timestamp), corresponding to C function
00237 except that data is a python string corresponding to the data.
00238
00239 Returns:
00240 Function that takes (dev, rgb, timestamp) that returns output of func
00241 """
00242
00243 def rgb_cb(dev, rgb, timestamp):
00244 nbytes = 921600
00245 return func(dev, ctypes.string_at(rgb, nbytes), timestamp)
00246 return rgb_cb
00247
00248
00249 @depth_cb_decorator
00250 def depth_cb_np(dev, string, timestamp):
00251 """Converts the raw depth data into a numpy array for your function
00252
00253 Args:
00254 dev: DevPtr object
00255 string: A python string with the depth data
00256 timestamp: An int representing the time
00257
00258 Returns:
00259 (dev, data, timestamp) where data is a 2D numpy array
00260 """
00261 np = _load_numpy()
00262 data = np.fromstring(string, dtype=np.uint16)
00263 data.resize((480, 640))
00264 return dev, data, timestamp
00265
00266
00267 @rgb_cb_decorator
00268 def rgb_cb_np(dev, string, timestamp):
00269 """Converts the raw depth data into a numpy array for your function
00270
00271 Args:
00272 dev: DevPtr object
00273 string: A python string with the RGB data
00274 timestamp: An int representing the time
00275
00276 Returns:
00277 (dev, data, timestamp) where data is a 2D numpy array
00278 """
00279 np = _load_numpy()
00280 data = np.fromstring(string, dtype=np.uint8)
00281 data.resize((480, 640, 3))
00282 return dev, data, timestamp
00283
00284 depth_cb, rgb_cb = _populate_namespace()