1
votes

I am using this code from the project FingertipTuio3D

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;
}

When the code reaches this point vector<Point> contour = contours[i]; it fails with an AccessViolation:

Unhandled exception at 0x00b85039 in FingertipTuio3d.exe: 0xC0000005: Access violation reading location 0x00000008.

That location is in the size_type size() const function of std::vector.

Any idea what is causing the problem, and how it might be fixed?

4
What is the prototype for findContours?John Bode
CV_EXPORTS void findContours( Mat& image, vector<vector<Point> >& contours, int mode, int method, Point offset=Point());Malfist
Well, there goes that hypothesis.John Bode
Do you want to copy the vector when you do: vector<Point> contour = contours[i]; ? I would suggest trying it this way: vector<Point> &contour = contours[i]; so that you don't do any unnecessary copying of data, since it seems you are just tring to access it. Also, what is the point of cloning handMask when calling the function?Nick Banks
It's not my code, I'm attempting to modify someone else's but I don't fully understand it.Malfist

4 Answers

0
votes

Does your findContours actually put anything into each contour?

You are checking that the array exists but not that the individual elements are valid

0
votes

Can you access the elements via an iterator? IOW, if you add the following code immediately after the call to loadContours, what output do you get?

int i = 0;
for (std::vector<std::vector<cv::Point> >::iterator it = contours.begin();
     it != contours.end();
     ++it)
{
  std::cout << "contours[" << i << "].size() == " << it->size() << std::endl;
}
0
votes

because contours is a vector of vector (std::vector> contours;)

and contour is a vector of points(vector contour)

so it cannot do vector contour = contours[i];

if you want to copy contours[i] you need to take another vector of vector.

-2
votes

This is build linked error. look at this:

--#ifdef _DEBUG 
--#pragma comment(lib,"opencv_core249d.lib")
--#else
--#pragma comment(lib,"opencv_core249.lib")    <<---- your checked!!
--#endif  

:-)