如何提高OpenCV模板跟踪准确度?使用什么参数?

时间:2015-02-13 18:20:40

标签: c++ opencv computer-vision

我正在尝试使用OpenCV跟踪一个房间里的人。

我理解通常的程序是: 1)做面部检测 2)查找内部功能 3)创建一个模板(在我的情况下是眼睛对) 4)然后,对以前的位置进行模板匹配,并使用minMaxloc()评估值 5)如果匹配不正确,请重新检测并存储新模板

但是,我正在努力从minMaxLoc()中获取有意义的价值。差异太小,跟踪会产生太多的误报。

我尝试了使用不同阈值的最小值和最大值的各种方法,但我无处可去。

也许我需要预处理数据?我尝试了标准化,但它只是使大多数值非常小(大约10e-10)。另外,我应该尝试缩放模板以提高准确性吗? 使用不同的模板匹配方法怎么样?

代码:

使用命名空间std; 使用namespace cv;

cv::CascadeClassifier face_cascade;
cv::CascadeClassifier eye_cascade;

cv::Mat other, other2;
int count_val = 0;
double checkVal = -10;
int second_count = 20;


int detectEye(cv::Mat& im, cv::Mat& tpl, cv::Rect& rect)
{
    std::vector<cv::Rect> faces, eyes;
    face_cascade.detectMultiScale(im, faces, 1.1, 2,
        CV_HAAR_SCALE_IMAGE, cv::Size(30, 30));

    for (int i = 0; i < faces.size(); i++)
    {
        cv::Mat face = im(faces[i]);
        eye_cascade.detectMultiScale(face, eyes, 1.1, 2,
            CV_HAAR_SCALE_IMAGE, cv::Size(20, 20));
        if (eyes.size())
        {
            rect = eyes[0] + cv::Point(faces[i].x, faces[i].y);
            if (count_val == 0){
                tpl = im(rect);
                count_val = 5;
            }
            else{
                count_val--;
            }

        }
    }

    return eyes.size();
}


Rect trackEye(cv::Mat& im, cv::Mat& tpl, cv::Rect& rect)
{
    cv::Size size(rect.width * 0.5, rect.height * 2);
    cv::Rect window(rect + size - cv::Point(size.width / 2, size.height / 2));

    window &= cv::Rect(0, 0, im.cols, im.rows);

    cv::Mat dst(window.height - tpl.rows + 1, window.width - tpl.cols + 1, CV_32FC1);
    cv::matchTemplate(im(window), tpl, dst, CV_TM_SQDIFF_NORMED);

    other = dst;
    other2 = tpl;

    //mormalising makes it really difficult to find a match, the range it too small
    //normalize(dst, dst, 0, 1, NORM_MINMAX, -1, Mat());

    double minval, maxval;
    cv::Point minloc, maxloc;
    cv::minMaxLoc(dst, &minval, &maxval, &minloc, &maxloc);

    cv::Point target = minloc;

    cout << minval << " " << maxval<<" "<< checkVal << endl;

    //if (minval <= checkVal || minval == 0|| checkVal == -10)
    if (maxval >0.25) //normally you would use the minval, but the range it too small... 
    //if (minval >0.01)
    {
        rect.x = window.x + target.x;
        rect.y = window.y + target.y;
        if (checkVal == -10)
            checkVal = minval;
    }
    else{
        rect.x = rect.y = rect.width = rect.height = 0;
        cout << "\n\n\n LOST TRACK \n\n";
    }
    return window;
}


int main(int argc, const char** argv) {



    // Load the cascade classifiers
    // Make sure you point the XML files to the right path, or
    // just copy the files from [OPENCV_DIR]/data/haarcascades directory

    String m_eyePair_cascade_file = "haarcascades/haarcascade_mcs_eyepair_big.xml";
    if (!face_cascade.load("haarcascades/haarcascade_frontalface_alt2.xml")) { printf("--(!)Error loading face\n"); };
//  if (!eye_cascade.load("haarcascades/haarcascade_eye.xml")) { printf("--(!)Error loading eyepair\n"); };
    if (!eye_cascade.load(m_eyePair_cascade_file)) { printf("--(!)Error loading eyepair\n"); };


    // Open webcam
    //cv::VideoCapture cap(0);
    // Check if everything is ok
    VideoCapture cap;
    if (!cap.open(0)) {
        cerr << "Cannot open camera" << endl;
        exit(-1);
    }

    if (face_cascade.empty() || eye_cascade.empty() || !cap.isOpened())
        return 1;
    // Set video to 320x240
    cap.set(CV_CAP_PROP_FRAME_WIDTH, 640);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
    cv::Mat frame, eye_tpl;
    cv::Rect eye_bb;
    while (cv::waitKey(15) != 'q')
    {
        second_count--;
        cap >> frame;
        if (frame.empty())
            break;
        // Flip the frame horizontally, Windows users might need this
        cv::flip(frame, frame, 1);
        // Convert to grayscale and
        // adjust the image contrast using histogram equalization
        cv::Mat gray;
        cv::cvtColor(frame, gray, CV_BGR2GRAY);

        if (second_count == 0){
            eye_bb.width == 0;
            count_val = 0;
            second_count = 20;
        }

        //cout << eye_bb << endl;
        if (eye_bb.width == 0)
        {
            // Detection stage
            // Try to detect the face and the eye of the user
            detectEye(gray, eye_tpl, eye_bb);
        }
        else
        {
            // Tracking stage with template matching
            Rect r = trackEye(gray, eye_tpl, eye_bb);
            // Draw bounding rectangle for the eye
            cv::rectangle(frame, eye_bb, CV_RGB(0, 255, 0));
            cv::rectangle(frame, r, CV_RGB(255, 255, 0));
        }
        // Display video

        cv::imshow("video2", frame);
        if (other.data != nullptr){
            cv::imshow("video", other);
            cv::imshow("video3", other2);

        }


        Sleep(400);

    }
}

1 个答案:

答案 0 :(得分:0)

您是否尝试过使用CV_TM_CCORR_NORMED而不是CV_TM_SQDIFF_NORMED?