#include "handDetect.h"
#include "svm.h"
#include "opencv2/opencv.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#define SSTR( x ) dynamic_cast< std::ostringstream & >( \
        ( std::ostringstream() << std::dec << x ) ).str()

using namespace cv;
using namespace std;

handDetect detect;
svm svmFingerNumber;
int dist;
Mat destMat;
Mat frame;
Mat face;
Mat small;
Mat binaryImage;
int numberOfFingersCH = 0;
int numberOfFingersSVM = 0;
int sredina=0;
float maxSize;
int corner_x=0;
int corner_y=0;
int smallDistance=0;
std::vector<cv::Point> locations;   // output, locations of non-zero pixels
CvSVM svmClassifier; //(SVM_TrainingData, SVM_Classes, Mat(), Mat(), SVM_params);
RNG rng(12345);

string intToString(int number)
{
    stringstream ss;
    ss << number;
    string str = ss.str();
    return str;
}

void printText(Mat src, string text)
{
    int fontFace = FONT_HERSHEY_SIMPLEX;
    putText(src, text, Point(src.cols/4, src.rows/10), fontFace, 1.0f, Scalar(255,255,255), 2);
}

int findBiggestContour(vector<vector<Point> > contours)
{
    int indexOfBiggestContour = -1;
    int sizeOfBiggestContour = 0;
    for (int i = 0; i < contours.size(); i++)
    {
        if(contours[i].size() > sizeOfBiggestContour)
        {
            sizeOfBiggestContour = contours[i].size();
            indexOfBiggestContour = i;
        }
    }
    return indexOfBiggestContour;

}

int findMaxDepth(vector<Vec4i>  ConvDef)
{
    int indexMaxDepth = -1;
    int sizeOfConvDef = 0;
    for (int i = 0; i < ConvDef.size(); i++)
    {
        if(ConvDef[i][3] > sizeOfConvDef)
        {
            sizeOfConvDef = ConvDef[i][3];
            indexMaxDepth = i;
        }
    }
    return indexMaxDepth;
}

int findMinDepth(vector<Vec4i>  ConvDef)
{
    int indexMinDepth = 0;
    if(ConvDef.size() > 0)
    {
        int sizeOfConvDef = ConvDef[0][3];
        for (int i = 1; i < ConvDef.size(); i++)
        {
            if(ConvDef[i][3] < sizeOfConvDef)
            {
                sizeOfConvDef = ConvDef[i][3];
                indexMinDepth = i;
            }
        }
    }
    return indexMinDepth;
}

float distanceP2P(Point a, Point b)
{
    float d = sqrt(fabs(pow(a.x - b.x, 2) + pow(a.y - b.y, 2))) ;
    return d;
}

float getAngle(Point s, Point f, Point e)
{
    float l1 = distanceP2P(f, s);
    float l2 = distanceP2P(f, e);
    float dot = (s.x - f.x)*(e.x - f.x) + (s.y - f.y)*(e.y - f.y);
    float angle = acos(dot/(l1*l2));
    angle = angle*180/3.14;
    return angle;
}

Mat mergeContours(Mat image)
{
    vector<Vec4i> hierarchy;
    std::vector<Point> merged_contour_points;
    vector<vector<Point> > contours;
    vector<Point2f> mc(contours.size());
    vector<Moments> mu(contours.size());
    findContours(image, contours, hierarchy,CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
    int x = findBiggestContour(contours);
    Point2f mcx;
    Moments mux;
    Point2f mci;
    Moments mui;
    mux = moments(contours[x], false);
    mcx = Point2f(mux.m10/mux.m00, mux.m01/mux.m00);//get mass center of biggest contour
    Mat merged_contours= Mat::zeros( small.size(), CV_8UC1 );
    drawContours( merged_contours, contours, x, Scalar(255,255,255), CV_FILLED, 8, vector<Vec4i>(), 0, Point() );
    //connect biggest contour with close and big contours
    for (int i = 0; i < contours.size(); i++)
    {
        mui = moments( contours[i], false );
        mci = Point2f( mui.m10/mui.m00 , mui.m01/mui.m00 );
        if((contourArea(contours[i])>200)&(distanceP2P(mcx,mci)<80)&(i!=x))
        {
            drawContours( merged_contours, contours, i, Scalar(255,255,255), CV_FILLED, 8, vector<Vec4i>(), 0, Point() );
            line( merged_contours, mci, mcx, Scalar(255,255,255), 20, 8 );
        }
    }
    return merged_contours;
}

void drawRotatedRectAndEllipse(Mat image)
{
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    cv::findContours(image, contours, hierarchy,CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
    vector<RotatedRect> minRect( contours.size() );
    vector<RotatedRect> minEllipse( contours.size() );
    for( int i = 0; i < contours.size(); i++ )
    {
        minRect[i] = minAreaRect( Mat(contours[i]) );
        if( contours[i].size() > 5 )
        {
            minEllipse[i] = fitEllipse( Mat(contours[i]) );
        }

    }
    for( int i = 0; i < contours.size(); i++ )
    {
        Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
        Point2f rect_points[4];
        minRect[i].points( rect_points );
        for( int j = 0; j < 4; j++ )
        {
            line( image, rect_points[j], rect_points[(j+1)%4], color, 1, 8 );
            float distance=distanceP2P(rect_points[j], rect_points[(j+1)%4]);
        }

    }
}

Point MinDistance(vector<Point> a, vector<Point> b)
{
    Point c;
    double MinDist = 10000000;
    for (int i = 0; i < a.size(); i++)
    {
        for (int j = 0; j < b.size(); j++)
        {
            double Dist = distanceP2P(a[i], b[j]);
            if (Dist < MinDist)
            {
                MinDist = Dist;
            }
        }
    }
    return c;
}

vector<int> getFingerTips(vector<Vec4i> ConvDef)
{
    vector<int> fingerTips;
    if(ConvDef.size()>0)
    {
        fingerTips.push_back(ConvDef[0][0]);
        fingerTips.push_back(ConvDef[0][1]);
        for(int k=1; k<ConvDef.size(); k++)
        {
            fingerTips.push_back(ConvDef[k][1]);
        }
    }
}

void drawMinRectAndEllipse(Mat image)
{
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    findContours(image, contours, hierarchy,CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
    vector<vector<Point> > contours_poly( contours.size() );
    vector<Rect> boundRect( contours.size() );
    vector<Point2f>center( contours.size() );
    vector<float>radius( contours.size() );

    for( int i = 0; i < contours.size(); i++ )
    {
        approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
        boundRect[i] = boundingRect( Mat(contours_poly[i]) );
        minEnclosingCircle( (Mat)contours_poly[i], center[i], radius[i] );
    }

    for( int i = 0; i< contours.size(); i++ )
    {
        Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
        rectangle( image, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );
        circle( image, center[i], (int)radius[i], color, 2, 8, 0 );
        float distance = distanceP2P(boundRect[i].tl(), boundRect[i].br());
        maxSize = boundRect[i].width;
        if(boundRect[i].height > maxSize)
        {
            maxSize=boundRect[i].height;
        }
    }
}

vector<Vec4i> removeRedundantDefectPoints(vector<Vec4i> convDef1, vector<Point> contours )
{
    vector<Point> defect_points;
    vector<Vec4i> convDef2;
    vector<Vec4i> convDef;
    int bigAngle = 0;
    int dist1 = 0;
    int maxDepth = 0;
    int minDepth = 0;
    smallDistance = 0;
    for(int k = 0; k<convDef1.size(); k++)
    {
        if(convDef1[k][3]>4*256)
        {
            convDef.push_back(convDef1[k]);
        }
    }
    for(int k=0; k<convDef.size(); k++)
    {
        if(convDef[k][3]>4*256)  // filter defects by depth, approximate distance to farthest point
        {
            int ind_0 = convDef[k][0];
            int ind_1 = convDef[k][1];
            int ind_2 = convDef[k][2];
            float angle = getAngle(contours[ind_0], contours[ind_2], contours[ind_1]);
            float distance = distanceP2P(contours[ind_0], contours[ind_1]);
            float startangle1 = getAngle(contours[(convDef[k][0]-20+contours.size())%contours.size()],contours[convDef[k][0]],contours[(convDef[k][0]+20)%contours.size()]); //start point angle
            float endangle1 = getAngle(contours[(convDef[k][1]-20+contours.size())%contours.size()],contours[convDef[k][1]],contours[(convDef[k][1]+20)%contours.size()]); //end point angle
            int start_point1;
            int end_point1;
            int start_point2;
            int end_point2;
            int ind_01 = convDef[k][0];
            int ind_11 = convDef[k][1];
            int ind_21 = convDef[k][2];
            if(convDef.size()!=1) // get start and end point of current defect and neighboring defects
            {
                if(k == 0)
                {
                    start_point1 = convDef[(convDef.size()-1)][1];
                    end_point1 = convDef[k][0];
                    start_point2 = convDef[k][1];
                    end_point2 = convDef[k+1][0];
                }
                else if(k == (convDef.size()-1))
                {
                    start_point1 = convDef[k][0];
                    end_point1 =  convDef[k-1][1];
                    start_point2 = convDef[k][1];
                    end_point2 = convDef[0][0];
                }
                else
                {
                    start_point1 = convDef[k][0];
                    end_point1 = convDef[k-1][1];
                    start_point2 = convDef[k][1];
                    end_point2 = convDef[k+1][0];
                }
                float dist1 = distanceP2P(contours[start_point1], contours[end_point1]); //distance between start point and previous end point
                float dist2 = distanceP2P(contours[start_point2], contours[end_point2]); //distance between end point and following start point
                float angle1 = getAngle(contours[ind_01],contours[ind_21],contours[ind_11]); //angle between start point, end point, and farthest point
                float distance2 = distanceP2P(contours[ind_01],contours[ind_11]); //distance between start and end point
                if(!(contours[ind_0].y < 5|contours[ind_1].y < 5)) //eliminate defect if it's to close to picture edge
                {
                    if((dist1<20|dist2<20)|(((convDef.size()==2)&(dist1>20&dist2>20)&(k==maxDepth))))
                    {
                        if(!((dist1>22&startangle1>95)|(dist2>22&endangle1>95))|(convDef[k][3]>7000)) //eliminate edge point if angle is too large
                        {
                            if(!((distance2>40)&(convDef[k][3]<2000)&((dist1>20)|(dist2>20))))
                            {
                                if(!(((distance2>40)&(convDef[k][3]<3000))|((distance2>55)&(convDef[k][3]<3500))))
                                {
                                    convDef2.push_back(convDef[k]);
                                    if(distanceP2P(contours[ind_01],contours[ind_11])<60)
                                        smallDistance++;
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                convDef2.push_back(convDef[k]);
            }
        }
    }
    return convDef2;
}

void drawFingerTips(vector<Point> start_point, vector<Point> end_point, Mat image)
{
    int fingersOverFive = 0;
    if(start_point.size()>4)
    {
        fingersOverFive = start_point.size()-4;
        for(int i = 0; i< fingersOverFive; i++)
        {
            start_point.erase(start_point.begin());
            end_point.erase(end_point.begin());
        }
    }
    for( int i = 0; i< start_point.size(); i++ )
    {
        if(distanceP2P(start_point[i],end_point[(i-1+end_point.size())%end_point.size()])>30)
        {
            cv::circle(image,start_point[i],5,Scalar(255,255,255),-1);
            cv::circle(image,end_point[i],5,Scalar(255,255,255),-1);
        }

        else
        {
            cv::circle(image,end_point[i],5,Scalar(255,255,255),-1);
        }
    }
}

void getFingerNumber(Mat image)
{
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    Mat merged_contours_image = mergeContours(image);
    findContours(merged_contours_image, contours, hierarchy,CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
    int x = findBiggestContour(contours);
    numberOfFingersSVM = svmFingerNumber.testOneSample(merged_contours_image, 42);
    int fontFace = FONT_HERSHEY_SIMPLEX;
    putText(frame,string("SVM: ") + string(intToString(numberOfFingersSVM)),Point(frame.cols/4, frame.rows/5),fontFace, 1.0f,Scalar(255,255,255),2);
    if(contours.size()>0)
    {
        vector<std::vector<int> >hull( contours.size() );
        vector<vector<Vec4i> > convDef(contours.size() );
        vector<vector<Vec4i> > convDef1 (contours.size() );
        vector<vector<Vec4i> > convDef2 (contours.size() );
        vector<vector<Point> > hull_points(contours.size());
        vector<vector<Point> > defect_points(contours.size());
        vector<vector<Point> > start_points(contours.size());
        vector<vector<Point> > end_points(contours.size());
        vector<vector<Point> > start_points_small(contours.size());
        vector<vector<Point> > end_points_small(contours.size());
        vector<vector<Point> > defect_points_pom(contours.size());
        vector<Point2f>center( contours.size() );
        vector<float>radius( contours.size() );
        for( int i = 0; i < contours.size(); i++ )
        {
            vector<Point2f> mc( contours.size() );
            vector<Moments> mu(contours.size() );
            convexHull( contours[i], hull[i], false );
            convexityDefects( contours[i],hull[i], convDef[i]);
            for(int k = 0; k<hull[i].size(); k++)
            {
                int ind=hull[i][k];
                hull_points[i].push_back(contours[i][ind]);
            }
            convDef2[i] = removeRedundantDefectPoints(convDef[i], contours[i]);
            int maxDepth = findMaxDepth(convDef2[i]);
            int minDepth = findMinDepth(convDef2[i]);
            for(int k=0; k < convDef2[i].size(); k++)
            {
                Point fingerTips;
                Point fingerTips_start;
                Point fingerTips_end;
                float dist1=distanceP2P(contours[i][convDef2[i][k][0]],contours[i][convDef2[i][(k-1+convDef2[i].size())%convDef2[i].size()][1]]);
                float dist2=distanceP2P(contours[i][convDef2[i][(k+1)%convDef2[i].size()][0]],contours[i][convDef2[i][k][1]]);
                float startangle3=getAngle(contours[i][(convDef2[i][k][0]-20+contours[i].size())%contours[i].size()],contours[i][convDef2[i][k][0]],contours[i][(convDef2[i][k][0]+20)%contours[i].size()]);
                float endangle3=getAngle(contours[i][(convDef2[i][k][1]-20+contours[i].size())%contours[i].size()],contours[i][convDef2[i][k][1]],contours[i][(convDef2[i][k][1]+20)%contours[i].size()]);
                if(!(dist1>20&dist2>20&convDef2[i].size()>2))
                {
                    if(!((convDef2[i].size() == 2)&(dist1>20&dist2>20)&(k == minDepth)))
                    {
                        if(!(((convDef2[i].size() == 3)&(smallDistance<3)&(k == minDepth))|((convDef2[i].size() == 1)&(distanceP2P(contours[i][convDef2[i][k][0]],contours[i][convDef2[i][k][1]])>60)))) //|((convDef2[i].size()==1)&(convDef2[i][k][3]<3500)))){
                        {
                            defect_points[i].push_back(contours[i][convDef2[i][k][2]]);
                            defect_points_pom[i].push_back(contours[i][convDef2[i][k][2]]);
                            fingerTips_start.x = contours[i][convDef2[i][k][0]].x + corner_x;
                            fingerTips_start.y=contours[i][convDef2[i][k][0]].y + corner_y;
                            fingerTips_end.x = contours[i][convDef2[i][k][1]].x + corner_x;
                            fingerTips_end.y = contours[i][convDef2[i][k][1]].y + corner_y;
                            start_points[i].push_back(fingerTips_start);
                            end_points[i].push_back(fingerTips_end);
                            start_points_small[i].push_back(contours[i][convDef2[i][k][0]]);
                            end_points_small[i].push_back(contours[i][convDef2[i][k][1]]);
                            cv::circle(face, contours[i][convDef2[i][k][1]], 5, Scalar(100,100,100),-1);
                            cv::circle(face, contours[i][convDef2[i][k][2]], 5, Scalar(122,122,122),-1);
                            cv::circle(face, contours[i][convDef2[i][k][0]], 5, Scalar(122,122,122),-1);

                            cv::line(face, contours[i][convDef2[i][k][2]], contours[i][convDef2[i][k][0]], Scalar(100,100,100),1);
                            cv::line(face, contours[i][convDef2[i][k][2]], contours[i][convDef2[i][k][1]], Scalar(100,100,100),1);
                        }
                    }
                }
            }
            if(defect_points[i].size()>4)
            {
                numberOfFingersCH = 5;
            }
            else if(defect_points[i].size() == 3&!(smallDistance >= 3))
            {
                numberOfFingersCH = 3;
            }
            else
            {
                numberOfFingersCH=defect_points[i].size()+1;
            }
            if(numberOfFingersCH == numberOfFingersSVM)
            {
                //drawFingerTips(start_points[i],end_points[i], frame);
            }
            printText(frame,string("Konveksna ljuska: ") + string(intToString(numberOfFingersCH)));
        }
    }
}

int checkIfHand(Mat image)
{
    int hand=0;
    int ZeroPixels=0;
    int TotalNumberOfPixels = face.rows * face.cols;
    ZeroPixels = TotalNumberOfPixels - countNonZero(face);
    vector<vector<Point> > contour;
    vector<Vec4i> hierarchy;
    destMat = (image.row(0));
    imshow ("dest",destMat);
    if(countNonZero(destMat)>0)
    {
        findNonZero(destMat, locations);
    }
    sredina=locations.size()/2;
    cout<<"locations "<<locations.size()<<endl;
    cout<<"locations "<<sredina<<endl;
    cout<<"The number of pixels that are zero is "<<ZeroPixels<<endl;
    cout<<"The number of pixels "<<TotalNumberOfPixels/10<<endl;
    cv::findContours(image, contour, hierarchy,CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
    for( int i = 0; i < contour.size(); i++ )
    {
        cout<<"is "<< contour.size()<<endl;
        if((contourArea(contour[i])>3000)*(contourArea(contour[i])<15000)*(TotalNumberOfPixels/1>ZeroPixels))  //po retcima se nalaze konture
        {
            hand=1;
            drawContours( image, contour, i, Scalar(255,0,0), CV_FILLED, 8, vector<Vec4i>(), 0, Point() );
        }
    }
    return hand;
}

Mat produceBinaries(Mat image)
{
    GaussianBlur(image, image, Size(201,201),3,5);
    threshold(image,image,50,255,CV_THRESH_BINARY | CV_THRESH_OTSU);
    //adaptiveThreshold( image, image, 255,CV_ADAPTIVE_THRESH_GAUSSIAN_C,CV_THRESH_BINARY,901,-17 );
    erode(image, image, Mat(), Point(-1, -1), 1, 1, 1);
    dilate(image, image, Mat(), Point(-1, -1),2,2, 2);
    dilate(image, image, Mat(), Point(-1, -1),1, 1, 1);
    erode(image, image, Mat(), Point(-1, -1), 1, 1, 1);
    return image;
}

void testAllStages(int number)
{
    vector<Rect> hands1;
    ifstream stream1(SSTR( "test_data/"<< number << "/bg.txt").c_str());
    char aa[80];
    if(!stream1)
    {
        cout << "While opening a file an error is encountered" << endl;
    }
    else
    {
        cout << "File is successfully opened" << endl;
    }
    while(!stream1.eof())
    {
        stream1 >> aa;
        char* path="test_data/";
        stringstream ss(stringstream::in | stringstream::out);
        ss << path << number << "/" << aa;
        Mat pom=imread(ss.str(), 0);
        hands1 = detect.haarCascade(pom);
        frame=pom;
        char* path1="test_data/";
        stringstream ss1(stringstream::in | stringstream::out);
        if(hands1.size()>0)
        {
            int maxHand1 = -1;
            int sizeOfHand1 = 0;
            for (int i = 0; i < hands1.size(); i++)
            {
                if(hands1[i].width*hands1[i].height > sizeOfHand1)
                {
                    sizeOfHand1 = hands1[i].width*hands1[i].height ;
                    maxHand1= i;
                }
            }
            Point pt1(hands1[maxHand1].x - hands1[maxHand1].width*0.3,hands1[maxHand1].y);
            Point pt2(hands1[maxHand1].x + hands1[maxHand1].width*1.5,hands1[maxHand1].y + hands1[maxHand1].height*1.1);
            Point center( hands1[maxHand1].x - hands1[maxHand1].width*0.3, hands1[maxHand1].y - hands1[maxHand1].height*0.0);
            small = Mat(pom, cv::Rect(center,Size( hands1[maxHand1].width*2, hands1[maxHand1].height*1.1))).clone();
            binaryImage=produceBinaries(small);
            getFingerNumber(binaryImage);

            //ss1 << path1 << number <<"_test/" <<"avm"<< aa;
            //imwrite(ss1.str(), frame);

            //save wrong classifications
            if(numberOfFingersCH!=number)
            {
                ss1 << path1 << number <<"_test/" <<"hull"<< aa;
                imwrite(ss1.str(), frame);
            }
            if(numberOfFingersSVM!=number)
            {
                ss1 << path1 << number <<"_test/" <<"svm"<< aa;
                imwrite(ss1.str(), frame);
            }
        }
    }
}

int main()
{
    VideoCapture capture("snimke/2015-03-19_120334_1_357#005.mp4"); // open video
    if(!capture.isOpened())  // check if succeeded
        return -1;
    int frame_width = capture.get(CV_CAP_PROP_FRAME_WIDTH);
    int frame_height = capture.get(CV_CAP_PROP_FRAME_HEIGHT);
    int ex=static_cast<int>(capture.get(CV_CAP_PROP_FPS));
    capture >> frame; // get a new frame from video
    //define output video to write
    VideoWriter video("out-video.avi",CV_FOURCC('M','J','P','G'),ex, Size(frame_width,frame_height),true);
    video.open("out-video.avi",CV_FOURCC('M','J','P','G'),ex, Size(frame_width,frame_height),true);
    // Check if the video was opened
    if(!video.isOpened())
    {
        cerr << "Could not create video.";
        return -1;
    }
    int isHand=0;

    //train and test SVM on binary images
    /*svmFingerNumber.setTrainingData();
    svmFingerNumber.train();
    svmFingerNumber.test();*/

    //1 - one finger
    //2 - two fingers
    //3 - three fingers
    //4 - four fingers
    //5 - five fingers
    //6 - negative images (no hand)
    //7 - negative images (gesture outside the classification set)

    //testAllStages(1);

    for(;;)
    {
        capture >> frame; // get a new frame from video
        Mat im = frame;
        Mat im_rgb(frame.size(), CV_8UC3);
        cvtColor(frame, frame, CV_BGR2GRAY);
        cv::cvtColor(frame, im_rgb, CV_GRAY2RGB);
        vector<Rect> hands;
        cvtColor(im, im, CV_BGR2GRAY);
        hands = detect.haarCascade(im);
        if(hands.size() > 0)
        {
            int maxHand = -1;
            int sizeOfHand = 0;
            //find biggest object
            for (int i = 0; i < hands.size(); i++)
            {
                if(hands[i].width*hands[i].height > sizeOfHand)
                {
                    sizeOfHand = hands[i].width*hands[i].height ;
                    maxHand = i;
                }
            }
            //extract hand from image
            Point center(hands[maxHand].x - hands[maxHand].width*0.3, hands[maxHand].y - hands[maxHand].height*0.0);
            small = Mat(im, cv::Rect(center, Size(hands[maxHand].width*2, hands[maxHand].height*1.1))).clone();
            corner_x = hands[maxHand].x - hands[maxHand].width*0.3;
            corner_y = hands[maxHand].y - hands[maxHand].height*0.0;
            Point pt1(hands[maxHand].x - hands[maxHand].width*0.3, hands[maxHand].y - hands[maxHand].height*0.05);
            Point pt2(hands[maxHand].x + hands[maxHand].width*1.5,hands[maxHand].y + hands[maxHand].height*1.1);
            binaryImage = produceBinaries(small);
            //isHand = checkIfHand(binaryImage);
            getFingerNumber(binaryImage);
            cv::cvtColor(frame, im_rgb, CV_GRAY2RGB);
            if(numberOfFingersCH == numberOfFingersSVM)
                rectangle(im_rgb, pt1, pt2, Scalar(0,0,255), 2, 8, 0);
        }
        imshow("hand", im_rgb);
        video.write(im_rgb);
        video<<im_rgb;
        waitKey(0);
    }
    // video.release();
    return 0;
}
