Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

How to set 'nmixures' and 'bShadowDetection' values in 'BackgroundSubtractorMOG2'?

I am using OpenCV 3.1 but the problem is that i am unable to make object of BackgroundSubtractorMOG2 class. I have written a function to detect face, eyes, nose and hand(with fingers and count the fingers). The problem is that visual studio gives an error saying that BackgroundSubtractorMOG2 is abstract class. Can someone please help me with that, I am also getting an error int the following lines:

 bg.operator ()(frame, fore); 
 bg.operator()(frame, fore, 0);

Following is my code. How can i resolve this issue. Thank in advance.

#include <opencv/cv.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/objdetect.hpp>
#include <opencv2/video/background_segm.hpp>

#include <iostream>
#include<algorithm>
#include <vector>

using namespace std;
using namespace cv;

String face_cascade_name = "haarcascade_frontalface_alt.xml";
String eyes_cascade_name = "haarcascade_eye_tree_eyeglasses.xml";
String nose_cascade_name = "haarcascade_mcs_nose.xml";
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
CascadeClassifier nose_cascade;
double dist(Point x, Point y)
{
    return (x.x - y.x)*(x.x - y.x) + (x.y - y.y)*(x.y - y.y);
}
pair<Point, double> circleFromPoints(Point p1, Point p2, Point p3)
{
    double offset = pow(p2.x, 2) + pow(p2.y, 2);
    double bc = (pow(p1.x, 2) + pow(p1.y, 2) - offset) / 2.0;
    double cd = (offset - pow(p3.x, 2) - pow(p3.y, 2)) / 2.0;
    double det = (p1.x - p2.x) * (p2.y - p3.y) - (p2.x - p3.x)* (p1.y - p2.y);
    double TOL = 0.0000001;
    if (abs(det) < TOL) { cout << "POINTS TOO CLOSE" << endl; return make_pair(Point(0, 0), 0); }

    double idet = 1 / det;
    double centerx = (bc * (p2.y - p3.y) - cd * (p1.y - p2.y)) * idet;
    double centery = (cd * (p1.x - p2.x) - bc * (p2.x - p3.x)) * idet;
    double radius = sqrt(pow(p2.x - centerx, 2) + pow(p2.y - centery, 2));

    return make_pair(Point(centerx, centery), radius);
}
void detectAndDisplay(Mat image)
{
    std::vector<Rect> faces;
    Mat image_gray;

    cvtColor(image, image_gray, CV_BGR2GRAY);
    equalizeHist(image_gray, image_gray);

    face_cascade.detectMultiScale(image_gray, faces, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30));

    cout << faces.size() << std::endl;

    for (size_t i = 0; i < faces.size(); i++) {
        rectangle(image, Point(faces[i].x, faces[i].y), Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height), Scalar(255, 0, 0), 3, 8);

        Mat faceROI = image_gray(faces[i]);
        vector<Rect> eyes;
        vector<Rect> noses;
        eyes_cascade.detectMultiScale(faceROI, eyes, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30));
        nose_cascade.detectMultiScale(faceROI, noses, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30));
        cout << noses.size() << std::endl;
        for (size_t j = 0; j < eyes.size(); j++) {
            Point center(faces[i].x + eyes[j].x + eyes[j].width*0.5, faces[i].y + eyes[j].y + eyes[j].height*0.5);
            int radius = cvRound((eyes[j].width + eyes[j].height)*0.25);
            circle(image, center, radius, Scalar(0, 255, 0), 4, 8, 0);
        }
        for (size_t j = 0; j < noses.size(); j++) {
            Point center(faces[i].x + noses[j].x + noses[j].width*0.5, faces[i].y + noses[j].y + noses[j].height*0.5);
            int radius = cvRound((noses[j].width + noses[j].height)*0.25);
            circle(image, center, radius, Scalar(0, 0, 255), 4, 8, 0);
        }
    }
}
int Face_And_Hand_Detector() {
    VideoCapture cap(0);
    Mat image;
    Mat frame;
    Mat back;
    Mat fore;
    vector<pair<Point, double> > palm_centers;

    BackgroundSubtractorMOG2 bg;
    bg.set("nmixtures", 3);
    bg.set("detectShadows", false);

    namedWindow("Frame");
    namedWindow("Background");
    int backgroundFrame = 500;
    if (!cap.isOpened()) {
        return -1;
    }
    while (true) {
        cap >> image;
        vector<vector<Point> > contours;
        //Get the frame
        cap >> frame;

        //Update the current background model and get the foreground
        if (backgroundFrame>0)
        {

            bg.operator ()(frame, fore); 
            backgroundFrame--;
        }
        else
        {
            bg.operator()(frame, fore, 0);

        }

        //Get background image to display it
        bg->getBackgroundImage(back);


        //Enhance edges in the foreground by applying erosion and dilation
        erode(fore, fore, Mat());
        dilate(fore, fore, Mat());


        //Find the contours in the foreground
        findContours(fore, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
        for (int i = 0; i<contours.size(); i++)
            //Ignore all small insignificant areas
            if (contourArea(contours[i]) >= 5000)
            {
                //Draw contour
                vector<vector<Point> > tcontours;
                tcontours.push_back(contours[i]);
                drawContours(frame, tcontours, -1, cv::Scalar(0, 0, 255), 2);

                //Detect Hull in current contour
                vector<vector<Point> > hulls(1);
                vector<vector<int> > hullsI(1);
                convexHull(Mat(tcontours[0]), hulls[0], false);
                convexHull(Mat(tcontours[0]), hullsI[0], false);
                drawContours(frame, hulls, -1, cv::Scalar(0, 255, 0), 2);

                //Find minimum area rectangle to enclose hand
                RotatedRect rect = minAreaRect(Mat(tcontours[0]));

                //Find Convex Defects
                vector<Vec4i> defects;
                if (hullsI[0].size()>0)
                {
                    Point2f rect_points[4]; rect.points(rect_points);
                    for (int j = 0; j < 4; j++)
                        line(frame, rect_points[j], rect_points[(j + 1) % 4], Scalar(255, 0, 0), 1, 8);
                    Point rough_palm_center;
                    convexityDefects(tcontours[0], hullsI[0], defects);
                    if (defects.size() >= 3)
                    {
                        vector<Point> palm_points;
                        for (int j = 0; j<defects.size(); j++)
                        {
                            int startidx = defects[j][0]; Point ptStart(tcontours[0][startidx]);
                            int endidx = defects[j][1]; Point ptEnd(tcontours[0][endidx]);
                            int faridx = defects[j][2]; Point ptFar(tcontours[0][faridx]);
                            //Sum up all the hull and defect points to compute average
                            rough_palm_center += ptFar + ptStart + ptEnd;
                            palm_points.push_back(ptFar);
                            palm_points.push_back(ptStart);
                            palm_points.push_back(ptEnd);
                        }

                        //Get palm center by 1st getting the average of all defect points, this is the rough palm center,
                        //Then U chose the closest 3 points ang get the circle radius and center formed from them which is the palm center.
                        rough_palm_center.x /= defects.size() * 3;
                        rough_palm_center.y /= defects.size() * 3;
                        Point closest_pt = palm_points[0];
                        vector<pair<double, int> > distvec;
                        for (int i = 0; i<palm_points.size(); i++)
                            distvec.push_back(make_pair(dist(rough_palm_center, palm_points[i]), i));
                        sort(distvec.begin(), distvec.end());

                        //Keep choosing 3 points till you find a circle with a valid radius
                        //As there is a high chance that the closes points might be in a linear line or too close that it forms a very large circle
                        pair<Point, double> soln_circle;
                        for (int i = 0; i + 2<distvec.size(); i++)
                        {
                            Point p1 = palm_points[distvec[i + 0].second];
                            Point p2 = palm_points[distvec[i + 1].second];
                            Point p3 = palm_points[distvec[i + 2].second];
                            soln_circle = circleFromPoints(p1, p2, p3);//Final palm center,radius
                            if (soln_circle.second != 0)
                                break;
                        }

                        //Find avg palm centers for the last few frames to stabilize its centers, also find the avg radius
                        palm_centers.push_back(soln_circle);
                        if (palm_centers.size()>10)
                            palm_centers.erase(palm_centers.begin());

                        Point palm_center;
                        double radius = 0;
                        for (int i = 0; i<palm_centers.size(); i++)
                        {
                            palm_center += palm_centers[i].first;
                            radius += palm_centers[i].second;
                        }
                        palm_center.x /= palm_centers.size();
                        palm_center.y /= palm_centers.size();
                        radius /= palm_centers.size();

                        //Draw the palm center and the palm circle
                        //The size of the palm gives the depth of the hand
                        circle(frame, palm_center, 5, Scalar(144, 144, 255), 3);
                        circle(frame, palm_center, radius, Scalar(144, 144, 255), 2);

                        //Detect fingers by finding points that form an almost isosceles triangle with certain thesholds
                        int no_of_fingers = 0;
                        for (int j = 0; j<defects.size(); j++)
                        {
                            int startidx = defects[j][0]; Point ptStart(tcontours[0][startidx]);
                            int endidx = defects[j][1]; Point ptEnd(tcontours[0][endidx]);
                            int faridx = defects[j][2]; Point ptFar(tcontours[0][faridx]);
                            //X o--------------------------o Y
                            double Xdist = sqrt(dist(palm_center, ptFar));
                            double Ydist = sqrt(dist(palm_center, ptStart));
                            double length = sqrt(dist(ptFar, ptStart));

                            double retLength = sqrt(dist(ptEnd, ptFar));
                            //Play with these thresholds to improve performance
                            if (length <= 3 * radius&&Ydist >= 0.4*radius&&length >= 10 && retLength >= 10 && max(length, retLength) / min(length, retLength) >= 0.8)
                                if (min(Xdist, Ydist) / max(Xdist, Ydist) <= 0.8)
                                {
                                    if ((Xdist >= 0.1*radius&&Xdist <= 1.3*radius&&Xdist<Ydist) || (Ydist >= 0.1*radius&&Ydist <= 1.3*radius&&Xdist>Ydist))
                                        line(frame, ptEnd, ptFar, Scalar(0, 255, 0), 1), no_of_fingers++;
                                }


                        }

                        no_of_fingers = min(5, no_of_fingers);
                        cout << "NO OF FINGERS: " << no_of_fingers << endl;
                    }
                }

            }
        if (backgroundFrame>0)
            putText(frame, "Recording Background", cvPoint(30, 30), FONT_HERSHEY_COMPLEX_SMALL, 0.8, cvScalar(200, 200, 250), 1, CV_AA);
        imshow("Frame", frame);
        imshow("Background", back);
        if (!face_cascade.load(face_cascade_name)) {
            cout << "no face xml" << std::endl;
            return -1;
        }
        if (!eyes_cascade.load(eyes_cascade_name)) {
            cout << "no eyes xml" << std::endl;
            return -1;
        }
        if (!nose_cascade.load(nose_cascade_name)) {
            cout << "no nose xml" << std::endl;
            return -1;
        }

        if (!image.data)
        {
            cout << "cant open image or find it" << std::endl;
            return -1;
        }

        detectAndDisplay(image);

        namedWindow("Face", WINDOW_NORMAL);
        imshow("Face", image);

        int c = waitKey(10);
        if ((char)c == 'x') { break; }
    }
    return 0;
}

int main() {
    Face_And_Hand_Detector();
    return 0;
}