Kinect Scol plugin
KinectDevice.cpp
1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OpenSpace3D
4 For the latest info, see http://www.openspace3d.com
5 
6 Copyright (c) 2012 I-maginer
7 
8 This program is free software; you can redistribute it and/or modify it under
9 the terms of the GNU Lesser General Public License as published by the Free Software
10 Foundation; either version 2 of the License, or (at your option) any later
11 version.
12 
13 This program is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16 
17 You should have received a copy of the GNU Lesser General Public License along with
18 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
20 http://www.gnu.org/copyleft/lesser.txt
21 
22 -----------------------------------------------------------------------------
23 */
24 
33 #include "objects/KinectDevice.h"
34 #include "generator/Depth.h"
35 #include "generator/Image.h"
36 #include "generator/User.h"
37 #include "DeviceManager.h"
38 #include "openNiScolPlugin.h"
39 #include <scolplugin.h>
40 
41 // mutex for multi kinect devices
42 boost::mutex enumerateMutex;
43 
44 KinectDevice::KinectDevice(unsigned int id) : Thread()
45 {
46  mId = id;
47  bConnected = false;
48  bMirror = false;
49  iDistCutoff = 10000;
50  fAngCutoff = 20.0f; //Kinect IR camera fov 57.8
51  mDepthGenerator = 0;
52  mImageGenerator = 0;
53  mUserGenerator = 0;
54  msklSmoothing = 0.6f;
55 
56  // frame buffers for hands detection
57  mframeSize = cv::Size(640, 480);
58  mfingersBgr = cv::Mat(mframeSize, CV_8UC3);
59 
60  //openni::OpenNI::addDeviceConnectedListener(this);
61  //openni::OpenNI::addDeviceDisconnectedListener(this);
62  //openni::OpenNI::addDeviceStateChangedListener(this);
63 
64  openni::Status rc = openni::STATUS_OK;
65 
66  // enumerate all devices
67  openni::Array<openni::DeviceInfo> deviceList;
68  openni::OpenNI::enumerateDevices(&deviceList);
69  const char* deviceURI = openni::ANY_DEVICE;
70 
71  if (deviceList.getSize() > mId)
72  deviceURI = deviceList[mId].getUri();
73 
74  rc = NiDevice.open(deviceURI);
75 
76  if (rc == openni::STATUS_OK && NiDevice.isValid())
77  {
78  if (!NiDevice.hasSensor(openni::SENSOR_DEPTH) || !CreateAndStartGenerators())
79  {
80  NiDevice.close();
81  }
82  else
83  {
84  bConnected = true;
85  OBJpostEvent(KINECT_CONNECTED_CB, SCOL_PTR this, 0);
86  }
87  }
88 
89  StartThreading(boost::bind(&KinectDevice::GoThread, this));
90 }
91 
92 KinectDevice::KinectDevice() : Thread()
93 {
94 }
95 
96 KinectDevice::~KinectDevice()
97 {
98  StopThreading();
99 
100  openni::OpenNI::removeDeviceConnectedListener(this);
101  openni::OpenNI::removeDeviceDisconnectedListener(this);
102  openni::OpenNI::removeDeviceStateChangedListener(this);
103 
104  if(bConnected)
105  {
106  bConnected = false;
107 
108  StopAndDestroyGenerators();
109  NiDevice.close();
110 
111  //reset users Id
112  KinectUserList::iterator iSearchedUser = listOfUsers.begin();
113  while (iSearchedUser != listOfUsers.end())
114  {
115  (*iSearchedUser)->SetId(-1);
116  (*iSearchedUser)->SetCalibrated(false);
117  iSearchedUser++;
118  }
119  }
120 }
121 
122 void KinectDevice::onDeviceStateChanged(const openni::DeviceInfo* pInfo, openni::DeviceState state)
123 {
124  MMechostr(MSKDEBUG, ">> Kinect state changed");
125 }
126 
127 void KinectDevice::onDeviceConnected(const openni::DeviceInfo* pInfo)
128 {
129  MMechostr(MSKDEBUG, ">> Kinect connected");
130 }
131 
132 void KinectDevice::onDeviceDisconnected(const openni::DeviceInfo* pInfo)
133 {
134  // just disconnected
135  boost::mutex::scoped_lock l(enumerateMutex);
136  boost::mutex::scoped_lock lg(uGeneratorsCreate);
137  if (bConnected)
138  {
139  bConnected = false;
140  StopAndDestroyGenerators();
141 
142  {
143  boost::mutex::scoped_lock l(uListMutex);
144  KinectUserList::iterator iSearchedUser = listOfUsers.begin();
145  while (iSearchedUser != listOfUsers.end())
146  {
147  (*iSearchedUser)->SetId(-1);
148  (*iSearchedUser)->SetCalibrated(false);
149  iSearchedUser++;
150  }
151  }
152 
153  NiDevice.close();
154  OBJpostEvent(KINECT_DISCONNECTED_CB, SCOL_PTR this, 0);
155  }
156  MMechostr(MSKDEBUG, ">> Kinect disconnected");
157 }
158 
159 openni::Device& KinectDevice::GetDevice()
160 {
161  assert(&NiDevice);
162  return NiDevice;
163 }
164 
165 void KinectDevice::GetGeneratorsSize(int &width, int &height)
166 {
167  width = mframeSize.width;
168  height = mframeSize.height;
169 }
170 
171 void KinectDevice::SetGeneratorsSize(int width, int height)
172 {
173  mframeSize = cv::Size(width, height);
174  mfingersBgr = cv::Mat(mframeSize, CV_8UC3);
175 }
176 
177 bool KinectDevice::IsConnected()
178 {
179  if (!IsRunning())
180  return false;
181  else
182  return bConnected;
183 }
184 
185 void KinectDevice::SetMirrorMode(bool state)
186 {
187  bMirror = state;
188  if (mDepthGenerator)
189  mDepthGenerator->SetMirror(state);
190  if (mImageGenerator)
191  mImageGenerator->SetMirror(state);
192 }
193 
194 bool KinectDevice::GetMirrorMode()
195 {
196  return bMirror;
197 }
198 
199 void KinectDevice::DestroyKinectUser(KinectUser* existingKinectUser)
200 {
201  boost::mutex::scoped_lock l(uListMutex);
202  boost::mutex::scoped_lock lh(updateHandsMutex);
203  listOfUsers.remove(existingKinectUser);
204  SAFE_DELETE(existingKinectUser);
205 }
206 
207 KinectUser* KinectDevice::CreateKinectUser()
208 {
209  boost::mutex::scoped_lock l(uListMutex);
210  boost::mutex::scoped_lock lh(updateHandsMutex);
211  KinectUser* newKinectUser = new KinectUser(this);
212  listOfUsers.push_back(newKinectUser);
213  return newKinectUser;
214 }
215 
216 KinectUser* KinectDevice::GetUser(int userId)
217 {
218  KinectUser* userFound = 0;
219  KinectUserList::iterator iSearchedUser = listOfUsers.begin();
220  while ((iSearchedUser != listOfUsers.end()) && (userFound == 0))
221  {
222  if ((*iSearchedUser)->GetId() == userId)
223  userFound = *iSearchedUser;
224 
225  iSearchedUser++;
226  }
227  return userFound;
228 }
229 
230 void KinectDevice::GetValidUsersMap(KinectUser** tUsers)
231 {
232  boost::mutex::scoped_lock l(uListMutex);
233  KinectUserList::iterator iSearchedUser = listOfUsers.begin();
234  while (iSearchedUser != listOfUsers.end())
235  {
236  int uid = (*iSearchedUser)->GetId();
237  if ((uid > 0) && (uid < 64))
238  tUsers[uid] = *iSearchedUser;
239 
240  iSearchedUser++;
241  }
242 }
243 
244 void KinectDevice::GoThread()
245 {
246  while(IsRunning())
247  {
248  if(!bConnected)
249  {
250  boost::mutex::scoped_lock l(enumerateMutex);
251  openni::Status rc = openni::STATUS_OK;
252 
253  // enumerate all devices
254  openni::Array<openni::DeviceInfo> deviceList;
255  openni::OpenNI::enumerateDevices(&deviceList);
256  const char* deviceURI = openni::ANY_DEVICE;
257 
258  if (deviceList.getSize() > mId)
259  deviceURI = deviceList[mId].getUri();
260 
261  rc = NiDevice.open(deviceURI);
262 
263  if (rc == openni::STATUS_OK && NiDevice.isValid())
264  {
265  if (!NiDevice.hasSensor(openni::SENSOR_DEPTH) || !CreateAndStartGenerators())
266  {
267  NiDevice.close();
268  }
269  else
270  {
271  bConnected = true;
272  OBJpostEvent(KINECT_CONNECTED_CB, SCOL_PTR this, 0);
273  }
274  }
275  else
276  {
277  // wait before retry
278  Sleep(200);
279  }
280  }
281  else
282  {
283  int tick = GetTickCount();
284  {
285  boost::mutex::scoped_lock l(updateMutex);
286  if (mImageGenerator && mImageGenerator->UpdateData())
287  {
288  if (mUserGenerator && mDepthGenerator)
289  {
290  boost::mutex::scoped_lock l(uListMutex);
291  if (mDepthGenerator->UpdateData(mUserGenerator->UpdateData()))
292  {
293  DetectUsers();
294  DetectHands();
295  }
296  }
297  }
298  }
299 
300  // limit the update at 60 fps to avoid too fast callbacks
301  int elapsedTime = 16 - (GetTickCount() - tick);
302  if (elapsedTime > 0)
303  Sleep(elapsedTime);
304  }
305  }
306 }
307 
308 unsigned int KinectDevice::GetId()
309 {
310  return mId;
311 }
312 
313 int KinectDevice::GetExistingAvailableId()
314 {
315  int found = -1;
316  OpenNIUserList::iterator iuser = listOfAvalaibleUsers.begin();
317  if (iuser != listOfAvalaibleUsers.end())
318  {
319  found = (int)*iuser;
320  listOfAvalaibleUsers.erase(iuser);
321  }
322 
323  return found;
324 }
325 
326 void KinectDevice::AddExistingId(unsigned int id)
327 {
328  OpenNIUserList::iterator iuser = listOfAvalaibleUsers.find(id);
329  if (iuser == listOfAvalaibleUsers.end())
330  {
331  listOfAvalaibleUsers.insert(id);
332  }
333 }
334 
335 void KinectDevice::RemoveExistingId(unsigned int id)
336 {
337  OpenNIUserList::iterator iuser = listOfAvalaibleUsers.find(id);
338  if (iuser != listOfAvalaibleUsers.end())
339  {
340  listOfAvalaibleUsers.erase(iuser);
341  }
342 }
343 
344 bool KinectDevice::CreateAndStartGenerators()
345 {
346  boost::mutex::scoped_lock l(uGeneratorsCreate);
347  SAFE_DELETE(mDepthGenerator);
348  SAFE_DELETE(mImageGenerator);
349  SAFE_DELETE(mUserGenerator);
350 
351  //test if generator is ready
352  mImageGenerator = new Image(this);
353 
354  //not ready
355  if (!mImageGenerator->UpdateData())
356  {
357  SAFE_DELETE(mImageGenerator);
358  return false;
359  }
360 
361  SAFE_DELETE(mImageGenerator);
362 
363  NiDevice.setDepthColorSyncEnabled(true);
364 
365  // Create generators
366  mUserGenerator = new User(this);
367 
368  //create them after User which define the device image size
369  mImageGenerator = new Image(this);
370  mDepthGenerator = new Depth(this);
371 
372  //init smoothing
373  mUserGenerator->SetSmoothing(msklSmoothing);
374 
375  //init cutoff
376  mDepthGenerator->SetDistCutoff(iDistCutoff);
377  mDepthGenerator->SetAngCutoff(fAngCutoff);
378 
379  if (NiDevice.isImageRegistrationModeSupported(openni::IMAGE_REGISTRATION_DEPTH_TO_COLOR))
380  NiDevice.setImageRegistrationMode(openni::IMAGE_REGISTRATION_DEPTH_TO_COLOR);
381 
382  SetMirrorMode(bMirror);
383  return true;
384 }
385 
386 void KinectDevice::StopAndDestroyGenerators()
387 {
388  // Stop all the generators
389  boost::mutex::scoped_lock l(uGeneratorsCreate);
390 
391  SAFE_DELETE(mDepthGenerator);
392  SAFE_DELETE(mImageGenerator);
393  SAFE_DELETE(mUserGenerator);
394  mfingersBgr.setTo(0);
395  listOfAvalaibleUsers.clear();
396 }
397 
398 Depth* KinectDevice::GetDepthGenerator()
399 {
400  return mDepthGenerator;
401 }
402 
403 Image* KinectDevice::GetImageGenerator()
404 {
405  return mImageGenerator;
406 }
407 
408 User* KinectDevice::GetUserGenerator()
409 {
410  return mUserGenerator;
411 }
412 
413 void KinectDevice::SetSkeletonSmoothing(float value)
414 {
415  boost::mutex::scoped_lock l(updateMutex);
416  msklSmoothing = value;
417 
418  if (mUserGenerator && mUserGenerator->IsValid())
419  mUserGenerator->SetSmoothing(msklSmoothing);
420 }
421 
422 float KinectDevice::GetSkeletonSmoothing()
423 {
424  return msklSmoothing;
425 }
426 
427 void KinectDevice::SetDistCutoff(int dist)
428 {
429  boost::mutex::scoped_lock l(updateMutex);
430  iDistCutoff = dist;
431  if (mDepthGenerator)
432  mDepthGenerator->SetDistCutoff(dist);
433 }
434 
435 int KinectDevice::GetDistCutoff()
436 {
437  return iDistCutoff;
438 }
439 
440 void KinectDevice::SetAngCutoff(float ang)
441 {
442  boost::mutex::scoped_lock l(updateMutex);
443  fAngCutoff = ang;
444  if (mDepthGenerator)
445  mDepthGenerator->SetAngCutoff(ang);
446 }
447 
448 float KinectDevice::GetAngCutoff()
449 {
450  return fAngCutoff;
451 }
452 
453 void KinectDevice::DetectHands()
454 {
455  if (mDepthGenerator->IsValid())
456  {
457  cv::Mat mat(mframeSize, CV_16SC1, (unsigned char*)mDepthGenerator->GetBuffer());
458  cv::Mat matRGB(mframeSize, CV_8UC3);
459  matRGB.setTo(0);
460 
461  //cv::Mat rbgmat(mframeSize, CV_8UC3, (unsigned char*) GetImageGenerator()->GetBuffer());
462  //rbgmat.copyTo(mfingersBgr);
463 
464  //mfingersDepth.convertTo(mfingersDepth8, CV_8UC1, 255.0f / 3000.0f);
465 
466  //reset bgr
467  //cvtColor(mfingersDepth8, mfingersBgr, CV_GRAY2BGR);
468 
469  {
470  boost::mutex::scoped_lock l(updateHandsMutex);
471  KinectUserList::iterator iSearchedUser = listOfUsers.begin();
472  while (iSearchedUser != listOfUsers.end())
473  {
474  if ((*iSearchedUser)->GetId() != -1)
475  (*iSearchedUser)->DetectUserHands(mat, matRGB);
476 
477  iSearchedUser++;
478  }
479  }
480 
481  boost::mutex::scoped_lock lf(uFingersUpdate);
482  {
483  matRGB.copyTo(mfingersBgr);
484  }
485  }
486 }
487 
488 void KinectDevice::DetectUsers()
489 {
490  if (!mUserGenerator || !mDepthGenerator)
491  return;
492 
493  int ucnt = 0;
494  int ucntUser = 0;
495 
496  KinectUser* user = 0;
497 
498  user = GetUser(-1);
499 
500  //attribute an available user Id if possible
501  //get user pixels and depth pixels
502  if (user && mUserGenerator->IsValid() && mDepthGenerator->IsValid())
503  {
504  if (listOfAvalaibleUsers.size() > 0)
505  {
506  const nite::UserId* ubuf = mUserGenerator->GetBuffer();
507  const unsigned short* dbuf = mDepthGenerator->GetCuttedBuffer();
508 
509  int maxcnt = 0;
510  int bestid = 0;
511  if ((ubuf != 0) && (dbuf != 0))
512  {
513  OpenNIUserList::iterator iuser = listOfAvalaibleUsers.begin();
514  int width = 0;
515  int height = 0;
516  mDepthGenerator->GetDepthSize(width, height);
517 
518  //find the most visible user in depth
519  while ((iuser != listOfAvalaibleUsers.end()) && (user != 0))
520  {
521  ucnt = 0;
522  int uavailable = (int)*iuser;
523 
524  //count user pixels
525  for (int i=0; i < (width * height); i++)
526  {
527  if (ubuf[i] == uavailable)
528  {
529  if ((ubuf[i] * dbuf[i]) > 0)
530  ucnt++;
531  }
532  }
533 
534  if ((ucnt > 0) && (ucnt > maxcnt))
535  {
536  maxcnt = ucnt;
537  bestid = uavailable;
538  }
539 
540  iuser++;
541  }
542  }
543 
544  if (bestid != 0)
545  {
546  RemoveExistingId(bestid);
547  user->SetId(bestid);
548  OBJpostEvent(KINECT_NEW_USER_CB, (int)user, 0);
549  }
550  }
551  }
552 }
553 
554 void KinectDevice::GetHandsPixels(PtrObjBitmap Bcolor, PtrObjBitmap Balpha)
555 {
556  boost::mutex::scoped_lock l(uGeneratorsCreate);
557  if(mDepthGenerator)
558  {
559  //Scol bitmap are 32bits aligned
560  int sbpl = Bcolor->TailleW * 3;
561  int dbpl = Bcolor->BPL;
562 
563  cv::Mat mat(mframeSize, CV_8UC3);
564  {
565  try
566  {
567  boost::mutex::scoped_lock lf(uFingersUpdate);
568  mfingersBgr.copyTo(mat);
569  }
570  catch(std::exception &e)
571  {
572  MMechostr(MSKDEBUG, "KinectDevice::GetHandsPixels : %s", e.what());
573  }
574  }
575 
576  if (mframeSize != cv::Size(Bcolor->TailleW, Bcolor->TailleH))
577  return;
578 
579  if (sbpl == dbpl)
580  memcpy(Bcolor->bits, mat.data, Bcolor->TailleW * Bcolor->TailleH * Bcolor->BytesPP);
581  else
582  for (long y=0; y<Bcolor->TailleH; y++)
583  {
584  for (long x=0; x<Bcolor->TailleW; x++)
585  {
586  unsigned long srcByte = (x * 3) + (sbpl * y);
587  unsigned long destByte = (x * Bcolor->BytesPP) + (dbpl * y);
588 
589  Bcolor->bits[destByte] = mat.data[srcByte];
590  Bcolor->bits[destByte + 1] = mat.data[srcByte + 1];
591  Bcolor->bits[destByte + 2] = mat.data[srcByte + 2];
592  }
593  }
594 
595  if (Balpha)
596  {
597  int dabpl = Balpha->BPL;
598 
599  //copy alpha
600  for (long y=0; y<Balpha->TailleH; y++)
601  {
602  for (long x=0; x<Balpha->TailleW; x++)
603  {
604  unsigned long sr = mat.data[(x * 3) + (sbpl * y)];
605  unsigned long sg = mat.data[((x * 3) + (sbpl * y)) + 1];
606  unsigned long sb = mat.data[((x * 3) + (sbpl * y)) + 2];
607  unsigned long destByte = (x * Balpha->BytesPP) + (dabpl * y);
608 
609  Balpha->bits[destByte] = (sr + sg + sb) == 0 ? 0 : 0xFF;
610  }
611  }
612  }
613  }
614 }
615 
616 void KinectDevice::GetDepthBuffer(PtrObjBitmap Bcolor)
617 {
618  boost::mutex::scoped_lock l(uGeneratorsCreate);
619  if(mDepthGenerator)
620  mDepthGenerator->GetBuffer(Bcolor);
621 }
622 
623 void KinectDevice::GetImageBuffer(PtrObjBitmap Bcolor)
624 {
625  boost::mutex::scoped_lock l(uGeneratorsCreate);
626  if(mImageGenerator)
627  mImageGenerator->GetBuffer(Bcolor);
628 }
629 
630 void KinectDevice::GetImageGreyBuffer(PtrObjBitmap Bcolor)
631 {
632  boost::mutex::scoped_lock l(uGeneratorsCreate);
633  if(mImageGenerator)
634  mImageGenerator->GetGreyBuffer(Bcolor);
635 }
636 
637 void KinectDevice::GetValidUserPixels(PtrObjBitmap Bcolor, PtrObjBitmap Balpha)
638 {
639  boost::mutex::scoped_lock l(uGeneratorsCreate);
640  if(mUserGenerator)
641  mUserGenerator->GetValidUserPixels(Bcolor, Balpha);
642 }
643 
644 void KinectDevice::GetValidUserPixelsRGB(PtrObjBitmap Bcolor, PtrObjBitmap Balpha)
645 {
646  boost::mutex::scoped_lock l(uGeneratorsCreate);
647  if(mUserGenerator)
648  mUserGenerator->GetValidUserPixels(Bcolor, Balpha);
649 
650  if(mImageGenerator)
651  mImageGenerator->GetBuffer(Bcolor);
652 }
653 
654 bool KinectDevice::GetSklMutexLock()
655 {
656  return uSklMutex.try_lock();
657 }
658 
659 void KinectDevice::ReleaseSklMutex()
660 {
661  uSklMutex.unlock();
662 }
Kinect user handling. .
Definition: KinectUser.h:38
User generator handling. .
Definition: User.h:37
Image generator handling. .
Definition: Image.h:37
Create Singleton type. .
Definition: Thread.h:37
Depth generator handling. .
Definition: Depth.h:38