33 #include "objects/KinectUserHand.h" 34 #include "core/DataSkeleton.h" 35 #include "DeviceManager.h" 36 #include "generator/User.h" 37 #include "objects/KinectDevice.h" 38 #include "openNiScolPlugin.h" 41 KinectUserHand::KinectUserHand()
45 KinectUserHand::KinectUserHand(
KinectUser* user, nite::JointType type)
53 KinectUserHand::~KinectUserHand()
57 bool KinectUserHand::GetHandContour(
const cv::Mat &depthMat, cv::Mat &handMat, nite::Point3f v, vector<cv::Point> &handContour, cv::Point2f ¢er, cv::Mat *debugFrame)
59 const float handDepthRange = 300.0f;
60 const float depth = v.z;
61 const int maxHandRadius = ((depth / 100.0f) > 0) ? (int) (700.0f / (depth / 100.0f)) : 128;
62 const float dnear = depth - (handDepthRange / 2);
63 const float dfar = depth + (handDepthRange / 2);
65 const double erodeCoef = depth > 0 ? 30.0f / (depth / 100) : 30.0f;
66 const double blurCoef = (depth / 100) <= 70 ? 11.0f : (depth / 100) <= 90 ? 6.0f : 2.0f;
67 const double epsilon = depth > 0 ? 65.0f / (depth / 100) : 65.0f;
72 cv::circle(handMat, cv::Point((
int)v.x, (
int)v.y), maxHandRadius, 255, CV_FILLED);
73 handMat = handMat & depthMat > dnear & depthMat < dfar;
80 cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size((
int)(2.0f * erodeCoef + 1.0f), (
int)(2.0f * erodeCoef + 1.0f)), cv::Point((
int)erodeCoef, (
int)erodeCoef));
81 cv::erode(handMat, handMat, element);
91 muser->GetParentDevice()->GetGeneratorsSize(width, height);
93 cv::Mat maskrgb(cv::Size(width, height), CV_8UC3);
94 cvtColor(handMat, maskrgb, CV_GRAY2BGR);
95 cv::add(maskrgb, *debugFrame, *debugFrame);
99 vector<vector<cv::Point>> contours;
101 cv::findContours(handMat, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cv::Point(0, 20));
102 int n = contours.size();
105 for (
int i=0; i<n; i++)
107 int size = contours[i].size();
118 vector<cv::Point> tHandContour = contours[maxI];
119 cv::approxPolyDP(cv::Mat(contours[maxI]), tHandContour, epsilon,
true);
123 cv::minEnclosingCircle(tHandContour, center, radius);
124 handContour = tHandContour;
129 cv::Point2f recPoints[4];
130 cv::RotatedRect shapeRect = cv::fitEllipse(tHandContour);
131 shapeRect.points(recPoints);
133 cv::circle(*debugFrame, cv::Point((
int)center.x, (
int)center.y), (
int)radius, 0x00ff00, 1);
134 cv::line(*debugFrame, center, cv::Point((
int)(center.x + (cos(SCOL_PI * shapeRect.angle / 180.0f) * radius)), (
int)(center.y + (sin(SCOL_PI * shapeRect.angle / 180.0f) * radius))), 0x0000ff, 2);
135 for (
int j=0; j<4; j++)
139 cv::line(*debugFrame, recPoints[j], recPoints[j-1], 0x00ff00, 2);
143 cv::line(*debugFrame, recPoints[0], recPoints[3], 0x00ff00, 2);
147 for (
int j=0; j<(int)handContour.size(); j++)
151 cv::line(*debugFrame, handContour[j], handContour[j-1], 128, 2);
155 cv::line(*debugFrame, handContour[0], handContour[handContour.size()-1], 128, 2);
158 cv::circle(*debugFrame, cv::Point((
int)v.x, (
int)v.y), maxHandRadius, 255, 2);
165 void KinectUserHand::DetectFingerTips(cv::Mat &handMat, vector<cv::Point> &handContour, cv::Point2f ¢er, cv::Mat *debugFrame)
167 cv::Mat handContourMat(handContour);
168 const cv::Scalar debugFingerTipColor(0, 0, 255);
172 muser->GetParentDevice()->GetGeneratorsSize(width, height);
175 vector<cv::Point> tmpFingerTips;
177 cv::convexHull(handContourMat, hull,
true,
false);
180 for (
int j=0; (j<(int)hull.size()) && (tmpFingerTips.size() < 5); j++)
183 int pdx = idx == 0 ? handContour.size() - 1 : idx - 1;
184 int sdx = idx == handContour.size() - 1 ? 0 : idx + 1;
186 cv::Point v1 = handContour[sdx] - handContour[idx];
187 cv::Point v2 = handContour[pdx] - handContour[idx];
189 float angle = acos((
float)((v1.x*v2.x + v1.y*v2.y) / (norm(v1) * norm(v2))));
195 int u = handContour[idx].x;
196 int v = handContour[idx].y;
198 tmpFingerTips.push_back(cv::Point2i(u, v));
239 if(mfingerTipsHistory.size() > 5)
240 mfingerTipsHistory.erase(mfingerTipsHistory.begin());
242 mfingerTipsHistory.push_back(tmpFingerTips);
243 std::vector<std::vector<cv::Point>> sortedtips;
245 for (
int j=0; j<(int)mfingerTipsHistory.size(); j++)
247 std::vector<cv::Point> ftips = mfingerTipsHistory[j];
248 for (
int k=0; k<(int)ftips.size(); k++)
250 if (k > ((
int)sortedtips.size() - 1))
252 std::vector<cv::Point> fv;
253 fv.push_back(ftips[k]);
254 sortedtips.push_back(fv);
258 sortedtips[k].push_back(ftips[k]);
264 boost::mutex::scoped_lock l(handMutex);
268 for (
int j=0; j<(int)sortedtips.size(); j++)
270 cv::Point fvec(0, 0);
271 for (
int k=0; k<(int)sortedtips[j].size(); k++)
273 fvec += sortedtips[j][k];
276 if(sortedtips[j].size() > 0)
278 fvec.x /= sortedtips[j].size();
279 fvec.y /= sortedtips[j].size();
282 mfingerTips.push_back(fvec);
288 for (
int j=0; j<(int)mfingerTips.size(); j++)
290 for (
int k=0; k<(int)mfingerTips.size(); k++)
293 cv::circle(*debugFrame, mfingerTips[k], 3, debugFingerTipColor, -1);
294 cv::line(*debugFrame, center, mfingerTips[k], debugFingerTipColor);
334 bool KinectUserHand::Detect(cv::Mat depthMat, cv::Mat depthMatBgr)
336 const int minHandExtension = 80;
337 const int minTorsoExtension = 250;
338 const double grabConvexity = 0.8;
352 if (muser->GetSkeletonData()->GetBoneImgCoordinates(nite::JOINT_TORSO, tVec, 0.7))
358 muser->GetParentDevice()->GetGeneratorsSize(width, height);
361 if ((muser->GetSkeletonData()->GetBoneImgCoordinates(mtype, hVec, 0.7)) &&
362 (hVec.z < tVec.z - minHandExtension)
363 && (hVec.y < (tVec.y + minTorsoExtension)))
365 unsigned char shade = 255 - (
unsigned char)((hVec.z / 1000.0f) * 128.0f);
366 cv::Scalar color(0, 0, shade);
368 vector<cv::Point> handContour;
370 cv::Mat handMat(cv::Size(width, height), CV_8UC1);
371 if (GetHandContour(depthMat, handMat, hVec, handContour, center, 0))
376 boost::mutex::scoped_lock l(handMutex);
379 OBJpostEvent(KINECT_USER_HAND_FOUND_CB, SCOL_PTR muser, (
int)mtype);
382 if(mhandPosHistory.size() > 5)
383 mhandPosHistory.erase(mhandPosHistory.begin());
390 mhandPosHistory.push_back(hpos);
391 nite::Point3f smoothvec;
395 for (
int j=0; j<(int)mhandPosHistory.size(); j++)
397 smoothvec.x += mhandPosHistory[j].x;
398 smoothvec.y += mhandPosHistory[j].y;
399 smoothvec.z += mhandPosHistory[j].z;
402 if(mhandPosHistory.size() > 0)
404 smoothvec.x /= mhandPosHistory.size();
405 smoothvec.y /= mhandPosHistory.size();
406 smoothvec.z /= mhandPosHistory.size();
410 boost::mutex::scoped_lock l(handMutex);
411 mtransVec.x = smoothvec.x - mhandPos.x;
412 mtransVec.y = smoothvec.y - mhandPos.y;
413 mtransVec.z = smoothvec.z - mhandPos.z;
414 mhandPos = smoothvec;
417 bool grasp = cvTools::Convexity(handContour) > grabConvexity;
418 int thickness = grasp ? CV_FILLED : 3;
419 cv::circle(depthMatBgr, cv::Point((
int)mhandPos.x, (
int)mhandPos.y), 5, color, thickness);
421 DetectFingerTips(handMat, handContour, center, &depthMatBgr);
423 if ((mtransVec.x != 0) || (mtransVec.y != 0) || (mtransVec.z != 0))
424 OBJpostEvent(KINECT_USER_HAND_MOVE_CB, SCOL_PTR muser, (
int)
this);
435 boost::mutex::scoped_lock l(handMutex);
438 OBJpostEvent(KINECT_USER_HAND_LOST_CB, SCOL_PTR muser, (
int)mtype);
443 catch (cv::Exception &e)
445 MMechostr(MSKDEBUG, const_cast<char*>(e.what()));
452 vector<cv::Point> KinectUserHand::GetFingersPos()
454 boost::mutex::scoped_lock l(handMutex);
455 vector<cv::Point> vFingers = mfingerTips;
459 nite::Point3f KinectUserHand::GetHandPos()
461 boost::mutex::scoped_lock l(handMutex);
462 nite::Point3f pos = mhandPos;
466 nite::Point3f KinectUserHand::GetLastTransVec()
468 boost::mutex::scoped_lock l(handMutex);
469 nite::Point3f transVec = mtransVec;
473 bool KinectUserHand::IsVisible()
475 boost::mutex::scoped_lock l(handMutex);
479 nite::JointType KinectUserHand::GetType()