Проблемы с OpenCV warpPerspective

Я работаю над проектом вычитания фона Android с движущейся камерой. Я пытаюсь использовать сопоставление функций, findHomography и warpPerspective, чтобы найти перекрывающиеся пиксели между двумя кадрами. Однако вывод, который я получаю, немного неверен. Я новичок в обработке изображений, поэтому не знаком со всей терминологией. У меня есть 2 основные проблемы:

1) Результат warpPerspective чрезмерно искажен - например. изображение перекошено, объекты на изображении перевернуты, сплющены и т. д. Как решить эту проблему?

2) Иногда я получаю сообщение об ошибке «Ошибка OpenCV: ошибка утверждения», которая приводит к сбою моего приложения. Эта ошибка сопоставляется с warpPerspective. Примечания: размеры изображения 1 (предыдущий кадр) и изображения 2 (текущий кадр) одинаковы. Я конвертирую изображения в серый цвет перед обнаружением признаков (в настоящее время из RGB). Иногда я получал аналогичную ошибку «Ошибка утверждения OpenCV» с помощью findHomography, но я узнал, что для этого требуется как минимум 4 балла, поэтому добавление оператора if решило ее, но не уверен, как решить ошибку с помощью warpPerspective.

Ошибка, которую я получаю:

02-24 15:30:49.554: E/cv::error()(4589): OpenCV Error: Assertion failed (type == src2.type() && src1.cols == src2.cols && (type == CV_32F || type == CV_8U)) 
    in void cv::batchDistance(cv::InputArray, cv::InputArray, cv::OutputArray, int, cv::OutputArray, int, int, cv::InputArray, int, bool), 
    file /home/reports/ci/slave_desktop/50-SDK/opencv/modules/core/src/stat.cpp, line 2473

Мой код:

void stitchFrames(){

    //convert frames to grayscale
    image1 = prevFrame.clone();
    image2 = currFrame.clone();

    if(colourSpace==1){ //convert from RGB to gray
        cv::cvtColor(image1, image1Gray,CV_RGB2GRAY);
        cv::cvtColor(image2, image2Gray,CV_RGB2GRAY);
    }
    else if(colourSpace==2){ //convert from HSV to gray
        cv::cvtColor(image1, image1Gray,CV_HSV2RGB);
        cv::cvtColor(image1Gray,image1Gray,CV_RGB2GRAY);
        cv::cvtColor(image2, image1Gray,CV_HSV2RGB);
        cv::cvtColor(image2Gray,image1Gray,CV_RGB2GRAY);
    }

    else if(colourSpace==3){ //no need for conversion
        image1Gray = image1;
        image2Gray = image2;
    }

    //----FEATURE DETECTION----

    //key points
    std::vector<KeyPoint> keypoints1, keypoints2;

    int minHessian;

    cv::FastFeatureDetector detector;

    detector.detect(image1Gray,keypoints1); //prevFrame
    detector.detect(image2Gray,keypoints2); //currFrame

    KeyPoint kp = keypoints2[4];
    Point2f p = kp.pt;
    float i = p.y;

    //---FEATURE EXTRACTION----

    //extracted descriptors
    cv::Mat descriptors1,descriptors2;

    OrbDescriptorExtractor extractor;
    extractor.compute(image1,keypoints1,descriptors1); //prevFrame
    extractor.compute(image2,keypoints2,descriptors2); //currFrame

    //----FEATURE MATCHING----

    //BruteForceMacher

    BFMatcher matcher;

    std::vector< cv::DMatch > matches; //result of matching descriptors
    std::vector< cv::DMatch > goodMatches; //result of sifting matches to get only 'good' matches

    matcher.match(descriptors1,descriptors2,matches);

    //----HOMOGRAPY - WARP-PERSPECTIVE - PERSPECTIVE-TRANSFORM----

    double maxDist = 0.0; //keep track of max distance from the matches
    double minDist = 80.0; //keep track of min distance from the matches

    //calculate max & min distances between keypoints
    for(int i=0; i<descriptors1.rows;i++){
        DMatch match = matches[i];

        float dist = match.distance;
        if (dist<minDist) minDist = dist;
        if(dist>maxDist) maxDist=dist;
    }

    //get only the good matches
    for( int i = 0; i < descriptors1.rows; i++ ){
        DMatch match = matches[i];
        if(match.distance< 500){
            goodMatches.push_back(match);
        }
    }

    std::vector< Point2f > obj;
    std::vector< Point2f > scene;

    //get the keypoints from the good matches
    for( int i = 0; i < goodMatches.size(); i++ ){

        //--keypoints from image1
        DMatch match1 = goodMatches[i];
        int qI1 = match1.trainIdx;
        KeyPoint kp1 = keypoints2[qI1];
        Point2f point1 = kp1.pt;
        obj.push_back(point1);

        //--keypoints from image2
        DMatch match2 = goodMatches[i];
        int qI2 = match2.queryIdx;
        KeyPoint kp2 = keypoints1[qI2];
        Point2f point2 = kp2.pt;
        scene.push_back(point2);

    }

    //calculate the homography matrix
    if(goodMatches.size() >=4){
        Mat H = findHomography(obj,scene, CV_RANSAC);

        warpPerspective(image2,warpResult,H,Size(image1.cols,image1.rows));
    }
}

person user3019612    schedule 24.02.2014    source источник
comment
Вы нашли какое-нибудь решение для этого? У меня похожая проблема.   -  person MMH    schedule 28.03.2014


Ответы (2)


Что касается вашего первого вопроса, я думаю, что искажение, о котором вы говорите, связано с тем, что:

  • вы оцениваете гомографию H, отображающую координаты на изображении 1 в координаты на изображении 2. Когда вы делаете Mat H = findHomography(obj,scene, CV_RANSAC);, obj — это координаты точки на изображении 1, а scene — это координаты точки на изображении 2.

  • затем вы используете H в функции warpPerspective, как если бы она сопоставляла координаты на изображении 2 с координатами на изображении 1, поскольку вы ожидаете, что она преобразует image2 в warpResult, который, как я предполагаю, должен быть сшит с image1.

Следовательно, вы должны оценить гомографию H следующим образом: Mat H = findHomography(scene, obj, CV_RANSAC);.

Что касается вашего второго вопроса, я думаю, что он поднят этой инструкцией:

matcher.match(descriptors1,descriptors2,matches);

Ошибка говорит о том, что выражение

(type == src2.type() && src1.cols == src2.cols && (type == CV_32F || type == CV_8U))

оказалось ложным, тогда как для работы функции оно должно быть истинным. Аналогичная проблема решалась здесь: перед вызовом функции match нужно вручную проверьте, верно ли следующее:

(descriptors1.type()==descriptors2.type() && descriptors1.cols==descriptors2.cols)
person BConic    schedule 24.02.2014
comment
Спасибо за ваш ответ. Ваше предложение по второму вопросу работает - я больше не вижу ошибки. Однако проблема в 1-м вопросе все еще существует после вашего предложения Mat H = findHomography(scene, obj, CV_RANSAC); - person user3019612; 25.02.2014

Что касается (1), я предполагаю, что гомография, которую вы оценили, основана на плохих совпадениях.

Сначала я бы начал с использования детектора ORB вместо FAST, затем изменил findHomography ransacReprojThreshold параметр. Значение по умолчанию — 3, подробности:

Пороговое значение ransacReprojThreshold:

Максимально допустимая ошибка повторного проецирования для обработки пары точек как вкраплений (используется только в методе RANSAC). То есть, если:

| dstPoints_i - convertPointsHomogeneous(H * srcPoints_i) | > ransacReprojThreshold

то точка i считается выбросом. Если srcPoints и dstPoints измеряются в пикселях, обычно имеет смысл установить этот параметр в диапазоне от 1 до 10.

Другими словами, предполагая 3 пикселя по умолчанию, если после применения гомографии к srcPoint расстояние до dstPoint больше 3 пикселов, эта пара считается вставкой (то есть хорошей).

Это только начало, это также поможет вам найти лучший фильтр для хороших совпадений и хорошей гомографии, вы найдете несколько ответов относительно них:

OpenCV Orb не находит совпадений..

Как определить, приемлема матрица гомографии или нет?

person Rui Marques    schedule 24.02.2014
comment
Спасибо за ваш ответ. Я попробовал ваше предложение, но, к сожалению, оно мало что изменило. Действительно, я сначала попробовал 2 изображения, но деформация не была идеальной - поэтому неудивительно, что в прямом эфире результат не такой, как ожидалось. Я пробовал несколько комбинаций алгоритмов, но я не думаю, что это имеет большое значение (кроме, возможно, скорости). Я также ограничен отсутствием доступа к SURF/SIFT на OpenCV Android. Я изучу темы, которые вы связали. - person user3019612; 26.02.2014
comment
Но всегда ли деформация неверна? По крайней мере, некоторые видеокадры должны отображаться нормально. - person Rui Marques; 26.02.2014
comment
На некоторых видеокадрах все нормально. Но чаще всего она перекошена и изображение в целом искажено. Я пытаюсь использовать вывод warpPerspective для обнаружения новинок с помощью вычитания фона, поэтому выводимые новинки обычно искажаются, когда я начинаю слегка перемещать камеру. - person user3019612; 26.02.2014
comment
Это согласуется с ответом, который я вам дал. - person Rui Marques; 26.02.2014