예제 #1
0
ImageSaliencyDetector::ImageSaliencyDetector(const cv::Mat1f& src) {
	if (src.empty()) {
		throw std::invalid_argument("ImageSaliencyDetector: Source image cannot be empty!");
	}

	setSourceImage(src);

	mDensityEstimates.resize(mSrcImage.rows);
	for (int i = 0; i < mSrcImage.rows; ++i) {
		mDensityEstimates[i].resize(mSrcImage.cols);
	}
}
예제 #2
0
std::vector<cv::Point2i> detectFingertips(cv::Mat1f z, float zMin = 0.0f, float zMax = 0.75f, cv::Mat1f& debugFrame = cv::Mat1f()) {
	using namespace cv;
	using namespace std;
	bool debug = !debugFrame.empty();

	vector<Point2i> fingerTips;

	Mat handMask = z < zMax & z > zMin;

	std::vector<std::vector<cv::Point> > contours;
	findContours(handMask.clone(), contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); // we are cloning here since method will destruct the image

	if (contours.size()) {
		for (int i=0; i<contours.size(); i++) {
			vector<Point> contour = contours[i];
			Mat contourMat = Mat(contour);
			double area = cv::contourArea(contourMat);

			if (area > 3000)  { // possible hand
				Scalar center = mean(contourMat);
				Point centerPoint = Point(center.val[0], center.val[1]);

				vector<Point> approxCurve;
				cv::approxPolyDP(contourMat, approxCurve, 20, true);

				vector<int> hull;
				cv::convexHull(Mat(approxCurve), hull);

				// find upper and lower bounds of the hand and define cutoff threshold (don't consider lower vertices as fingers)
				int upper = 640, lower = 0;
				for (int j=0; j<hull.size(); j++) {
					int idx = hull[j]; // corner index
					if (approxCurve[idx].y < upper) upper = approxCurve[idx].y;
					if (approxCurve[idx].y > lower) lower = approxCurve[idx].y;
				}
				float cutoff = lower - (lower - upper) * 0.1f;

				// find interior angles of hull corners
				for (int j=0; j<hull.size(); j++) {
					int idx = hull[j]; // corner index
					int pdx = idx == 0 ? approxCurve.size() - 1 : idx - 1; //  predecessor of idx
					int sdx = idx == approxCurve.size() - 1 ? 0 : idx + 1; // successor of idx

					Point v1 = approxCurve[sdx] - approxCurve[idx];
					Point v2 = approxCurve[pdx] - approxCurve[idx];

					float angle = acos( (v1.x*v2.x + v1.y*v2.y) / (norm(v1) * norm(v2)) );

					// low interior angle + within upper 90% of region -> we got a finger
					if (angle < 1 && approxCurve[idx].y < cutoff) {
						int u = approxCurve[idx].x;
						int v = approxCurve[idx].y;

						fingerTips.push_back(Point2i(u,v));
						
						if (debug) {
							cv::circle(debugFrame, approxCurve[idx], 10, Scalar(1), -1);
						}
					}
				}

				if (debug) {
					// draw cutoff threshold
					cv::line(debugFrame, Point(center.val[0]-100, cutoff), Point(center.val[0]+100, cutoff), Scalar(1.0f));

					// draw approxCurve
					for (int j=0; j<approxCurve.size(); j++) {
						cv::circle(debugFrame, approxCurve[j], 10, Scalar(1.0f));
						if (j != 0) {
							cv::line(debugFrame, approxCurve[j], approxCurve[j-1], Scalar(1.0f));
						} else {
							cv::line(debugFrame, approxCurve[0], approxCurve[approxCurve.size()-1], Scalar(1.0f));
						}
					}

					// draw approxCurve hull
					for (int j=0; j<hull.size(); j++) {
						cv::circle(debugFrame, approxCurve[hull[j]], 10, Scalar(1.0f), 3);
						if(j == 0) {
							cv::line(debugFrame, approxCurve[hull[j]], approxCurve[hull[hull.size()-1]], Scalar(1.0f));
						} else {
							cv::line(debugFrame, approxCurve[hull[j]], approxCurve[hull[j-1]], Scalar(1.0f));
						}
					}
				}
			}
		}
	}

	return fingerTips;
}