00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include <openni_camera/openni_driver.h>
00038 #include <openni_camera/openni_device.h>
00039 #include <openni_camera/openni_image.h>
00040 #include <openni_camera/openni_depth_image.h>
00041 #include <iostream>
00042 #include <string>
00043 #include <map>
00044 #include <XnCppWrapper.h>
00045 #include <opencv2/opencv.hpp>
00046 #include <boost/thread.hpp>
00047 #include <sys/times.h>
00048
00049 using namespace std;
00050 using namespace openni_wrapper;
00051 using namespace cv;
00052 using namespace boost;
00053
00054 class MyOpenNIExample
00055 {
00056 public:
00057
00058 typedef struct ImgContext : public boost::noncopyable
00059 {
00060
00061 ImgContext () : is_new (false)
00062 {
00063 }
00064
00065 ImgContext (const Mat & img) : image (img), is_new (false)
00066 {
00067 }
00068 Mat image;
00069 mutable boost::mutex lock;
00070 bool is_new;
00071 } ImageContext;
00072 public:
00073 MyOpenNIExample (const vector<unsigned>& device_indices);
00074 ~MyOpenNIExample ();
00075 int run ();
00076 private:
00077 void imageCallback (boost::shared_ptr<Image> image, void* cookie);
00078 void depthCallback (boost::shared_ptr<DepthImage> depth, void* cookie);
00079 void writeImages () const;
00080 map<string, ImageContext*> rgb_images_;
00081 map<string, ImageContext*> gray_images_;
00082 map<string, ImageContext*> depth_images_;
00083 vector< boost::shared_ptr<OpenNIDevice> > devices_;
00084 bool running_;
00085 unsigned selected_device_;
00086
00087 double image_timestamp;
00088 double depth_timestamp;
00089 };
00090
00091 MyOpenNIExample::MyOpenNIExample (const vector<unsigned>& device_indices)
00092 : running_ (false)
00093 , selected_device_ (0)
00094 {
00095 OpenNIDriver& driver = OpenNIDriver::getInstance ();
00096
00097 for (vector<unsigned>::const_iterator indexIt = device_indices.begin (); indexIt != device_indices.end (); ++indexIt)
00098 {
00099 if (*indexIt >= driver.getNumberDevices ())
00100 {
00101 cout << "Index out of range." << driver.getNumberDevices () << " devices found." << endl;
00102 exit (1);
00103 }
00104
00105 boost::shared_ptr<OpenNIDevice> device = driver.getDeviceByIndex (*indexIt);
00106 cout << devices_.size () + 1 << ". device on bus: " << (int)device->getBus () << " @ " << (int)device->getAddress ()
00107 << " with serial number: " << device->getSerialNumber () << " "
00108 << device->getVendorName () << " : " << device->getProductName () << endl;
00109 devices_.push_back (device);
00110
00111 XnMapOutputMode mode;
00112 mode.nXRes = 640;
00113 mode.nYRes = 480;
00114 mode.nFPS = 30;
00115 if (!device->isImageModeSupported (mode))
00116 {
00117 cout << "image stream mode " << mode.nXRes << " x " << mode.nYRes << " @ " << mode.nFPS << " not supported" << endl;
00118 exit (-1);
00119 }
00120
00121 if (!device->isDepthModeSupported (mode))
00122 {
00123 cout << "depth stream mode " << mode.nXRes << " x " << mode.nYRes << " @ " << mode.nFPS << " not supported" << endl;
00124 exit (-1);
00125 }
00126
00127
00128
00129 namedWindow (string (device->getConnectionString ()) + "RGB", WINDOW_AUTOSIZE);
00130 namedWindow (string (device->getConnectionString ()) + "Depth", WINDOW_AUTOSIZE);
00131 namedWindow (string (device->getConnectionString ()) + "Gray", WINDOW_AUTOSIZE);
00132
00133
00134
00135 const int width = 640;
00136 const int height = 480;
00137 rgb_images_[device->getConnectionString ()] = new ImageContext (Mat::zeros (height, width, CV_8UC3));
00138 depth_images_[device->getConnectionString ()] = new ImageContext (Mat::zeros (height, width, CV_32FC1));
00139 gray_images_[device->getConnectionString ()] = new ImageContext (Mat::zeros (height, width, CV_8UC1));
00140
00141
00142 device->registerImageCallback (&MyOpenNIExample::imageCallback, *this, &(*device));
00143 device->registerDepthCallback (&MyOpenNIExample::depthCallback, *this, &(*device));
00144 }
00145
00146 timeval timestamp;
00147 gettimeofday (×tamp, NULL);
00148 image_timestamp = depth_timestamp = timestamp.tv_sec + timestamp.tv_usec * 0.000001;
00149 }
00150
00151 MyOpenNIExample::~MyOpenNIExample ()
00152 {
00153
00154 devices_.clear ();
00155
00156
00157 for (map<string, ImageContext*>::iterator imageIt = rgb_images_.begin (); imageIt != rgb_images_.end (); ++imageIt)
00158 {
00159 delete imageIt->second;
00160 }
00161
00162 for (map<string, ImageContext*>::iterator imageIt = gray_images_.begin (); imageIt != gray_images_.end (); ++imageIt)
00163 {
00164 delete imageIt->second;
00165 }
00166
00167 for (map<string, ImageContext*>::iterator imageIt = depth_images_.begin (); imageIt != depth_images_.end (); ++imageIt)
00168 {
00169 delete imageIt->second;
00170 }
00171 }
00172
00173 void MyOpenNIExample::writeImages () const
00174 {
00175 cout << "write images" << endl;
00176 static unsigned index = 0;
00177 ++index;
00178
00179 cout << "locking rgb images..." << flush;
00180 map<string, ImageContext*>::const_iterator imageIt;
00181 for (imageIt = rgb_images_.begin (); imageIt != rgb_images_.end (); ++imageIt)
00182 imageIt->second->lock.lock ();
00183
00184 cout << "done\nlocking gray images..." << flush;
00185 for (imageIt = gray_images_.begin (); imageIt != gray_images_.end (); ++imageIt)
00186 imageIt->second->lock.lock ();
00187
00188
00189
00190 cout << "locking rgb images..." << flush;
00191 char file_name[255];
00192 for (imageIt = rgb_images_.begin (); imageIt != rgb_images_.end (); ++imageIt)
00193 {
00194 sprintf (file_name, "rgb_%03u.png", index);
00195 imwrite (file_name, imageIt->second->image);
00196 }
00197
00198 for (imageIt = gray_images_.begin (); imageIt != gray_images_.end (); ++imageIt)
00199 {
00200 sprintf (file_name, "gray_%03u.png", index);
00201 imwrite (file_name, imageIt->second->image);
00202 }
00203
00204
00205
00206
00207
00208
00209
00210
00211 for (imageIt = rgb_images_.begin (); imageIt != rgb_images_.end (); ++imageIt)
00212 imageIt->second->lock.unlock ();
00213
00214 for (imageIt = gray_images_.begin (); imageIt != gray_images_.end (); ++imageIt)
00215 imageIt->second->lock.unlock ();
00216
00217
00218 }
00219
00220 void MyOpenNIExample::imageCallback (boost::shared_ptr<Image> image, void* cookie)
00221 {
00222 timeval timestamp;
00223 gettimeofday (×tamp, NULL);
00224
00225 double now = timestamp.tv_sec + timestamp.tv_usec * 0.000001;
00226
00227
00228
00229
00230 image_timestamp = now;
00231 OpenNIDevice* device = reinterpret_cast<OpenNIDevice*>(cookie);
00232 ImageContext* rgb_image_context = rgb_images_[device->getConnectionString ()];
00233 ImageContext* gray_image_context = gray_images_[device->getConnectionString ()];
00234
00235
00236 unique_lock<mutex> rgb_lock (rgb_image_context->lock);
00237 unsigned char* rgb_buffer = (unsigned char*)(rgb_image_context->image.data + (rgb_image_context->image.cols >> 2) * rgb_image_context->image.elemSize () +
00238 (rgb_image_context->image.rows >> 2) * rgb_image_context->image.step);
00239 image->fillRGB (rgb_image_context->image.cols >> 1, rgb_image_context->image.rows >> 1, rgb_buffer, rgb_image_context->image.step);
00240
00241 rgb_image_context->is_new = true;
00242 rgb_lock.unlock ();
00243
00244 unique_lock<mutex> gray_lock (gray_image_context->lock);
00245
00246 unsigned char* gray_buffer = (unsigned char*)(gray_image_context->image.data + (gray_image_context->image.cols >> 2) +
00247 (gray_image_context->image.rows >> 2) * gray_image_context->image.step);
00248 image->fillGrayscale (gray_image_context->image.cols >> 1, gray_image_context->image.rows >> 1, gray_buffer, gray_image_context->image.step);
00249
00250 gray_image_context->is_new = true;
00251 }
00252
00253 void MyOpenNIExample::depthCallback (boost::shared_ptr<DepthImage> depth, void* cookie)
00254 {
00255
00256 timeval timestamp;
00257 gettimeofday (×tamp, NULL);
00258 depth_timestamp = timestamp.tv_sec + timestamp.tv_usec * 0.000001;
00259
00260 OpenNIDevice* device = reinterpret_cast<OpenNIDevice*>(cookie);
00261 ImageContext* depth_image_context = depth_images_[device->getConnectionString ()];
00262
00263
00264 unique_lock<mutex> depth_lock (depth_image_context->lock);
00265 float* buffer = (float*)(depth_image_context->image.data + (depth_image_context->image.cols >> 2) * sizeof(float) +
00266 (depth_image_context->image.rows >> 2) * depth_image_context->image.step );
00267 depth->fillDepthImage (depth_image_context->image.cols >> 1, depth_image_context->image.rows >> 1, buffer, depth_image_context->image.step);
00268
00269 depth_image_context->is_new = true;
00270 }
00271
00272 int MyOpenNIExample::run ()
00273 {
00274 running_ = true;
00275 try
00276 {
00277 while (running_)
00278 {
00279 for (map<string, ImageContext*>::iterator imageIt = rgb_images_.begin (); imageIt != rgb_images_.end (); ++imageIt)
00280 {
00281 if (imageIt->second->is_new && imageIt->second->lock.try_lock ())
00282 {
00283 imshow (imageIt->first + "RGB", imageIt->second->image);
00284 imageIt->second->is_new = false;
00285 imageIt->second->lock.unlock ();
00286 }
00287 }
00288
00289 for (map<string, ImageContext*>::iterator imageIt = gray_images_.begin (); imageIt != gray_images_.end (); ++imageIt)
00290 {
00291 if (imageIt->second->is_new && imageIt->second->lock.try_lock ())
00292 {
00293 imshow (imageIt->first + "Gray", imageIt->second->image);
00294 imageIt->second->is_new = false;
00295 imageIt->second->lock.unlock ();
00296 }
00297 }
00298
00299 for (map<string, ImageContext*>::iterator imageIt = depth_images_.begin (); imageIt != depth_images_.end (); ++imageIt)
00300 {
00301 if (imageIt->second->is_new && imageIt->second->lock.try_lock ())
00302 {
00303 Mat gray_image;
00304 imageIt->second->image.convertTo (gray_image, CV_8UC1, 25.5);
00305 imshow (imageIt->first + "Depth", gray_image);
00306 imageIt->second->is_new = false;
00307 imageIt->second->lock.unlock ();
00308 }
00309 }
00310
00311 unsigned char key = waitKey (30) & 0xFF;
00312
00313 switch (key)
00314 {
00315 case 27:
00316 case 'q':
00317 case 'Q': running_ = false;
00318 break;
00319
00320 case '1':
00321 selected_device_ = 0;
00322 break;
00323 case '2':
00324 selected_device_ = 1;
00325 break;
00326 case '3':
00327 selected_device_ = 2;
00328 break;
00329
00330 case 'r':
00331 case 'R':
00332 devices_[selected_device_]->setDepthRegistration (!devices_[selected_device_]->isDepthRegistered ());
00333 break;
00334 case 's':
00335 case 'S':
00336 if (devices_[selected_device_]->isSynchronizationSupported ())
00337 devices_[selected_device_]->setSynchronization (!devices_[selected_device_]->isSynchronized ());
00338 break;
00339 case 'c':
00340 case 'C':
00341 if (devices_[selected_device_]->isDepthCropped ())
00342 {
00343 depth_images_[devices_[selected_device_]->getConnectionString ()]->lock.lock ();
00344
00345 depth_images_[devices_[selected_device_]->getConnectionString ()]->image.rows = 480;
00346 depth_images_[devices_[selected_device_]->getConnectionString ()]->image.cols = 640;
00347 depth_images_[devices_[selected_device_]->getConnectionString ()]->lock.unlock ();
00348 devices_[selected_device_]->setDepthCropping (0, 0, 0, 0);
00349 }
00350 else if (devices_[selected_device_]->isDepthCroppingSupported ())
00351 {
00352 depth_images_[devices_[selected_device_]->getConnectionString ()]->lock.lock ();
00353
00354 depth_images_[devices_[selected_device_]->getConnectionString ()]->image.rows = 240;
00355 depth_images_[devices_[selected_device_]->getConnectionString ()]->image.cols = 320;
00356 depth_images_[devices_[selected_device_]->getConnectionString ()]->lock.unlock ();
00357 devices_[selected_device_]->setDepthCropping (100, 100, 320, 240);
00358 }
00359 break;
00360
00361 case 'd':
00362 case 'D':
00363 if (devices_[selected_device_]->isDepthStreamRunning ())
00364 devices_[selected_device_]->stopDepthStream ();
00365 else
00366 devices_[selected_device_]->startDepthStream ();
00367 break;
00368 case 'i':
00369 case 'I':
00370 if (devices_[selected_device_]->isImageStreamRunning ())
00371 devices_[selected_device_]->stopImageStream ();
00372 else
00373 devices_[selected_device_]->startImageStream ();
00374 break;
00375
00376 case 'w':
00377 case 'W':
00378 writeImages ();
00379 break;
00380 }
00381 }
00382 }
00383 catch (const OpenNIException& exception)
00384 {
00385 cout << "exception caught: " << exception.what () << endl;
00386 return (-1);
00387 }
00388 catch (...)
00389 {
00390
00391 cout << "unknown exception caught" << endl;
00392 return (-1);
00393 }
00394 return 0;
00395 }
00396
00397 int main (int argc, char** argv)
00398 {
00399 OpenNIDriver& driver = OpenNIDriver::getInstance ();
00400 if (argc == 1)
00401 {
00402 cout << "Usage: " << argv[0] << " (<device-index>)+" << endl;
00403 if (driver.getNumberDevices () > 0)
00404 {
00405 for (unsigned deviceIdx = 0; deviceIdx < driver.getNumberDevices (); ++deviceIdx)
00406 {
00407 cout << "Device: " << deviceIdx << ", vendor: " << driver.getVendorName (deviceIdx) << ", product: " << driver.getProductName (deviceIdx)
00408 << ", connected: " << (int)driver.getBus (deviceIdx) << " @ " << (int)driver.getAddress (deviceIdx) << ", serial number: \'" << driver.getSerialNumber (deviceIdx) << "\'" << endl;
00409 }
00410 }
00411 else
00412 cout << "No devices connected." << endl;
00413 exit (1);
00414 }
00415
00416 vector <unsigned> device_indices;
00417 for (int argIdx = 1; argIdx < argc; ++argIdx)
00418 {
00419 unsigned deviceIdx = (unsigned)atoi (argv[argIdx]);
00420 if (deviceIdx >= driver.getNumberDevices ())
00421 {
00422 if (driver.getNumberDevices () > 0)
00423 {
00424 cout << "Device index out of range. " << driver.getNumberDevices () << " devices found." << endl;
00425 for (unsigned deviceIdx = 0; deviceIdx < driver.getNumberDevices (); ++deviceIdx)
00426 {
00427 cout << "Device: " << deviceIdx << ", vendor: " << driver.getVendorName (deviceIdx) << ", product: "
00428 << driver.getProductName (deviceIdx) << ", connected: " << (int)driver.getBus (deviceIdx) << " @ "
00429 << (int)driver.getAddress (deviceIdx) << ", serial number: \'" << driver.getSerialNumber (deviceIdx) << "\'" << endl;
00430 }
00431 }
00432 else
00433 cout << "No devices connected." << endl;
00434 exit (-1);
00435 }
00436 device_indices.push_back ((unsigned)deviceIdx);
00437 }
00438
00439 cout << "<1,2,3...> to select device" << endl;
00440 cout << "<I> to start or stop image stream of selected device" << endl;
00441 cout << "<D> to start or stop depth stream of selected device" << endl;
00442 cout << "<R> to turn on or off registration for selected device" << endl;
00443 cout << "<S> to turn on or off synchronization for selected device" << endl;
00444 cout << "<C> to turn on or off image cropping for selected device" << endl;
00445 cout << "<W> write current images" << endl;
00446 cout << "<Q> to quit application" << endl;
00447 MyOpenNIExample example (device_indices);
00448
00449 return example.run ();
00450 }