Advertisement
lamiastella

Hands.cpp

Jun 7th, 2017
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.17 KB | None | 0 0
  1. #include "Hand.h"
  2. #include "Util.h"
  3. #include "Visualizer.h"
  4.  
  5. Hand::Hand()
  6. {
  7.  
  8. }
  9.  
  10. Hand::Hand(cv::Mat xyzMap, float angle_threshhold, int cluster_thresh)
  11. {
  12.     CLUSTER_THRESHOLD = cluster_thresh;
  13.     ANGLE_THRESHHOLD = angle_threshhold;
  14.     analyzeHand(xyzMap);
  15. }
  16.  
  17. Hand::~Hand()
  18. {
  19.  
  20. }
  21.  
  22. void Hand::analyzeHand(cv::Mat xyzMap)
  23. {
  24.  
  25.     cv::Mat normalizedDepthMap;
  26.     cv::Mat channel[3];
  27.     cv::split(xyzMap, channel);
  28.     cv::normalize(channel[2], normalizedDepthMap, 0, 255, cv::NORM_MINMAX, CV_8UC1);
  29.  
  30.     // Resize input
  31.     cv::Mat input;
  32.     cv::pyrUp(normalizedDepthMap, input, cv::Size(normalizedDepthMap.cols * 2, normalizedDepthMap.rows * 2));
  33.     cv::pyrUp(input, input, cv::Size(input.cols * 2, input.rows * 2));
  34.  
  35.     cv::Mat threshold_output;
  36.     std::vector< std::vector<cv::Point> > contours;
  37.     std::vector<cv::Vec4i> hierarchy;
  38.  
  39.     // Find contours
  40.  
  41.     cv::threshold(input, threshold_output, 100, 255, cv::THRESH_BINARY);
  42.     cv::findContours(threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
  43.  
  44.     // Find contour polygon
  45.  
  46.     std::vector< std::vector< cv::Point> > contours_poly(contours.size());
  47.     for (int i = 0; i < contours.size(); i++) {
  48.         cv::approxPolyDP(cv::Mat(contours[i]), contours_poly[i], 3, true);
  49.     }
  50.  
  51.     // Find largest contour
  52.     std::vector<cv::Point> contour = Hand::findComplexContour(contours);
  53.  
  54.     // Find approximated convex hull
  55.  
  56.     std::vector<cv::Point> hull;
  57.     std::vector<cv::Point> completeHull;
  58.     std::vector<int> indexHull;
  59.     if (contour.size() > 1) {
  60.         cv::convexHull(contour, completeHull, 0, 1);
  61.         cv::convexHull(contour, indexHull, 0, 0);
  62.         hull = Hand::clusterConvexHull(completeHull, Hand::CLUSTER_THRESHOLD);
  63.     }
  64.  
  65.     // Find convexityDefects
  66.  
  67.     std::vector<cv::Vec4i> defects;
  68.     if (indexHull.size() > 3) {
  69.         cv::convexityDefects(contour, indexHull, defects);
  70.     }
  71.  
  72.     // Find max and min distances
  73.     double minVal, maxVal;
  74.     cv::Point minLoc, maxLoc;
  75.     cv::minMaxLoc(channel[2], &minVal, &maxVal, &minLoc, &maxLoc);
  76.  
  77.     // Find center of contour
  78.  
  79.     cv::Point center = Hand::findCenter(contour);
  80.     centroid_xyz = xyzMap.at<cv::Vec3f>(center.y / 4, center.x / 4);
  81.     centroid_ij = cv::Point2i(center.x, center.y); // SCALING
  82.  
  83.                                                    // Generate visual
  84.     cv::Mat img = cv::Mat::zeros(input.rows, input.cols, CV_8UC3);
  85.     cout << "img cols before: " << img.cols << endl;
  86.     cout << "img rows before: " << img.rows << endl;
  87.    
  88.     cv::Scalar color = cv::Scalar(0, 255, 0);
  89.  
  90.     // Draw contours
  91.     cv::circle(img, center, 5, cv::Scalar(255, 0, 0), 2);
  92.  
  93.     for (int i = 0; i < contours.size(); i++) {
  94.         cv::drawContours(img, contours_poly, i, color, 1, 8, std::vector<cv::Vec4i>(), 0, cv::Point());
  95.     }
  96.  
  97.     // Draw hull
  98.  
  99.     cv::Point index;
  100.     cv::Point index_right;
  101.     cv::Point index_left;
  102.     double farthest = 0;
  103.  
  104.     if (hull.size() > 1) {
  105.         for (int i = 0; i < hull.size(); i++) {
  106.             cv::Point p1 = hull[i];
  107.             cv::Point p2 = hull[(i + 1) % hull.size()];
  108.             //cv::line(img, p1, p2, cv::Scalar(255, 0, 0), 1);
  109.  
  110.             if (p1.y < centroid_ij.y && Util::euclideanDistance2D(p1, centroid_ij) > farthest) {
  111.                 farthest = Util::euclideanDistance2D(p1, centroid_ij);
  112.                 index = p1;
  113.                 index_right = hull[(i + 1) % hull.size()];
  114.                 index_left = hull[(i - 1) % hull.size()];
  115.             }
  116.         }
  117.     }
  118.  
  119.     // Draw defects (filter)
  120.  
  121.     std::vector<cv::Point> endpoints;
  122.     std::vector<cv::Point> fingerDefects;
  123.     cv::Point lastStart;
  124.     int found = -1;
  125.     for (int i = 0; i < defects.size(); i++) {
  126.         cv::Vec4i defect = defects[i];
  127.         cv::Point start = contour[defect[0]];
  128.         cv::Point end = contour[defect[1]];
  129.         cv::Point farPt = contour[defect[2]];
  130.         // Depth from edge of contour
  131.         // std::cout << "Depth: " << depth << "\tThreshold: " << cv::norm(maxLoc - center) << "\t";
  132.         // Defect conditions: depth is sufficient, inside contour, y value is above center
  133.         int depth = defect[3];
  134.  
  135.         // maxLoc largest depth
  136.         // first condition replace with meters distance from the edge
  137.         // second test if inside the hull (no change)
  138.         // above the center (no change)
  139.         if (cv::norm(maxLoc - center) * 15 < depth && cv::pointPolygonTest(hull, farPt, false) > 0 && farPt.y < center.y) {
  140.             cv::Vec3f pt1 = xyzMap.at<cv::Vec3f>(farPt.y / 4, farPt.x / 4);
  141.             if (Util::euclidianDistance3D(pt1, centroid_xyz) > 0.05) {
  142.                 endpoints.push_back(start);
  143.                 endpoints.push_back(end);
  144.                 fingerDefects.push_back(farPt);
  145.             }
  146.         }
  147.     }
  148.  
  149.     // Cluster fingertip locations
  150.  
  151.     endpoints = Hand::clusterConvexHull(endpoints, Hand::CLUSTER_THRESHOLD);
  152.     for (int i = 0; i < endpoints.size(); i++) {
  153.         cv::Point endpoint = endpoints[i];
  154.  
  155.         cv::Point closestDefect;
  156.         int minDefectDistance = 1 << 29;
  157.         for (int i = 0; i < fingerDefects.size(); i++) {
  158.             if (cv::norm(endpoint - fingerDefects[i]) < minDefectDistance) {
  159.                 minDefectDistance = cv::norm(endpoint - fingerDefects[i]);
  160.                 closestDefect = fingerDefects[i];
  161.             }
  162.         }
  163.         cv::Vec3f endPoint_xyz = Util::averageAroundPoint(xyzMap, cv::Point2i(endpoint.x / 4, endpoint.y / 4), 10);
  164.         cv::Vec3f closestDefect_xyz = Util::averageAroundPoint(xyzMap, cv::Point2i(closestDefect.x / 4, closestDefect.y / 4), 10);
  165.         double finger_length = Util::euclidianDistance3D(endPoint_xyz, closestDefect_xyz);
  166.         if (finger_length < 0.08 && finger_length > 0.025 && endpoint.y < closestDefect.y) {
  167.             fingers_xyz.push_back(endPoint_xyz);
  168.             fingers_ij.push_back(cv::Point2i(endpoint.x, endpoint.y)); // SCALING
  169.  
  170.             defects_xyz.push_back(Util::averageAroundPoint(xyzMap, cv::Point2i(closestDefect.x / 4, closestDefect.y / 4), 5));
  171.             defects_ij.push_back(cv::Point2i(closestDefect.x, closestDefect.y)); // SCALING
  172.         }
  173.     }
  174.     if ((float)cv::countNonZero(channel[2]) / (xyzMap.rows*xyzMap.cols) > 0.3) {
  175.         return;
  176.     }
  177.  
  178.     // If there is one or less visible fingers
  179.     if (fingers_xyz.size() <= 1)
  180.     {
  181.         fingers_xyz.clear();
  182.         fingers_ij.clear();
  183.  
  184.         cv::Vec3f indexFinger = Util::averageAroundPoint(xyzMap, cv::Point2i(index.x / 4, index.y / 4), 10);
  185.         fingers_xyz.push_back(indexFinger);
  186.         fingers_ij.push_back(cv::Point2i(index.x, index.y)); // SCALING
  187.  
  188.         double angle = Util::TriangleAngleCalculation(index_left.x, index_left.y, index.x, index.y, index_right.x, index_right.y);
  189.         if (defects_ij.size() != 0) {
  190.             for (int i = 0; i < fingers_xyz.size(); i++) {
  191.                 cv::circle(img, fingers_ij[i], 5, cv::Scalar(0, 0, 255), 3);
  192.                 cv::line(img, defects_ij[i], fingers_ij[i], cv::Scalar(255, 0, 255), 2);
  193.                 cv::circle(img, defects_ij[i], 5, cv::Scalar(0, 255, 255), 2);
  194.                 cv::line(img, defects_ij[i], centroid_ij, cv::Scalar(255, 0, 255), 2);
  195.             }
  196.         }
  197.         else if (angle > ANGLE_THRESHHOLD) {
  198.             cv::circle(img, fingers_ij[0], 5, cv::Scalar(0, 0, 255), 3);
  199.             cv::line(img, fingers_ij[0], centroid_ij, cv::Scalar(255, 0, 255), 2);
  200.         }
  201.  
  202.     }
  203.     else {
  204.         for (int i = 0; i < fingers_xyz.size(); i++) {
  205.             cv::circle(img, fingers_ij[i], 5, cv::Scalar(0, 0, 255), 3);
  206.             cv::line(img, defects_ij[i], fingers_ij[i], cv::Scalar(255, 0, 255), 2);
  207.             cv::circle(img, defects_ij[i], 3, cv::Scalar(0, 255, 255), 2);
  208.             cv::line(img, defects_ij[i], centroid_ij, cv::Scalar(255, 0, 255), 2);
  209.         }
  210.     }
  211.     cout << "img cols after: " << img.cols << endl;
  212.     cout << "img rows after: " << img.rows << endl;
  213.  
  214.     //cv::namedWindow("Contours", CV_WINDOW_AUTOSIZE);
  215.     //cv::imshow("Contours", img);
  216.  
  217.  
  218. }
  219.  
  220. std::vector<cv::Point> Hand::findComplexContour(std::vector< std::vector<cv::Point> > contours) {
  221.     std::vector<cv::Point> contour;
  222.     int maxPoints = 0;
  223.     for (int i = 0; i < contours.size(); i++) {
  224.         if (contours[i].size() > maxPoints) {
  225.             maxPoints = contours[i].size();
  226.             contour = contours[i];
  227.         }
  228.     }
  229.     return contour;
  230. }
  231.  
  232. std::vector<cv::Point> Hand::clusterConvexHull(std::vector<cv::Point> convexHull, int threshold) {
  233.     std::vector<cv::Point> clusterHull;
  234.     int i = 0;
  235.     while (i < convexHull.size()) {
  236.         // Select a point from cluster
  237.         std::vector<cv::Point> cluster;
  238.         cv::Point hullPoint = convexHull[i];
  239.         cluster.push_back(hullPoint);
  240.         i++;
  241.         while (i < convexHull.size()) {
  242.             cv::Point clusterPoint = convexHull[i];
  243.             double distance = cv::norm(hullPoint - clusterPoint);
  244.             if (distance < threshold) {
  245.                 cluster.push_back(clusterPoint);
  246.                 i++;
  247.             }
  248.             else {
  249.                 break;
  250.             }
  251.         }
  252.         hullPoint = cluster[cluster.size() / 2];
  253.         cv::Point center = findCenter(convexHull);
  254.         int maxDist = cv::norm(hullPoint - center);
  255.         for (int i = 0; i < cluster.size(); i++) {
  256.             if (cv::norm(cluster[i] - center) > maxDist) {
  257.                 maxDist = cv::norm(cluster[i] - center);
  258.                 hullPoint = cluster[i];
  259.             }
  260.         }
  261.         clusterHull.push_back(hullPoint);
  262.     }
  263.     return clusterHull;
  264. }
  265.  
  266. cv::Point Hand::findCenter(std::vector<cv::Point> contour) {
  267.     cv::Point center;
  268.     cv::Moments M = cv::moments(contour, false);
  269.     center = cv::Point((int)M.m10 / M.m00, (int)M.m01 / M.m00);
  270.     return center;
  271. }
  272.  
  273. bool Hand::touchObject(std::vector<double> &equation, const double threshold)
  274. {
  275.     if (equation.size() == 0) {
  276.         return false;
  277.     }
  278.  
  279.     for (int i = 0; i < fingers_xyz.size(); i++) {
  280.         double x = fingers_xyz[i][0];
  281.         double y = fingers_xyz[i][1];
  282.         double z = fingers_xyz[i][2];
  283.         if (z == 0) {
  284.             return false;
  285.         }
  286.  
  287.         double z_hat = equation[0] * x + equation[1] * y + equation[2];
  288.         double r_squared = (z - z_hat) * (z - z_hat);
  289.  
  290.         if (r_squared < threshold) {
  291.             return true;
  292.         }
  293.     }
  294.  
  295.     return false;
  296. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement