Компенсация движения камеры - PullRequest
5 голосов
/ 25 февраля 2011

Я использую openCV для реализации компенсации движения камеры для приложения.Я знаю, что мне нужно рассчитать оптический поток и затем найти фундаментальную матрицу между двумя кадрами для преобразования изображения.

Вот что я сделал до сих пор:

void VideoStabilization::stabilize(Image *image) {
    if (image->getWidth() != width || image->getHeight() != height) reset(image->getWidth(), image->getHeight());

    IplImage *currImage = toCVImage(image);
    IplImage *currImageGray = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);

    cvCvtColor(currImage, currImageGray, CV_BGRA2GRAY);

    if (baseImage) {
        CvPoint2D32f currFeatures[MAX_CORNERS];
        char featuresFound[MAX_CORNERS];

        opticalFlow(currImageGray, currFeatures, featuresFound);

        IplImage *result = transformImage(currImage, currFeatures, featuresFound);
        if (result) {
            updateImage(image, result);
            cvReleaseImage(&result);
        }
    }

    cvReleaseImage(&currImage);

    if (baseImage) cvReleaseImage(&baseImage);
    baseImage = currImageGray;

    updateGoodFeatures();
}

void VideoStabilization::updateGoodFeatures() {
    const double QUALITY_LEVEL = 0.05;
    const double MIN_DISTANCE = 5.0;

    baseFeaturesCount = MAX_CORNERS;

    cvGoodFeaturesToTrack(baseImage, eigImage,
                          tempImage, baseFeatures, &baseFeaturesCount, QUALITY_LEVEL, MIN_DISTANCE);

    cvFindCornerSubPix(baseImage, baseFeatures, baseFeaturesCount,
                       cvSize(10, 10), cvSize(-1,-1), TERM_CRITERIA);
}

void VideoStabilization::opticalFlow(IplImage *currImage, CvPoint2D32f *currFeatures, char *featuresFound) {
    const unsigned int WIN_SIZE = 15;
    const unsigned int PYR_LEVEL = 5;

    cvCalcOpticalFlowPyrLK(baseImage, currImage,
                           NULL, NULL,
                           baseFeatures,
                           currFeatures,
                           baseFeaturesCount,
                           cvSize(WIN_SIZE, WIN_SIZE),
                           PYR_LEVEL,
                           featuresFound,
                           NULL,
                           TERM_CRITERIA,
                           0);
}

IplImage *VideoStabilization::transformImage(IplImage *image, CvPoint2D32f *features, char *featuresFound) const {
    unsigned int featuresFoundCount = 0;
    for (unsigned int i = 0; i < MAX_CORNERS; ++i) {
        if (featuresFound[i]) ++featuresFoundCount;
    }

    if (featuresFoundCount < 8) {
        std::cout << "Not enough features found." << std::endl;
        return NULL;
    }

    CvMat *points1 = cvCreateMat(2, featuresFoundCount, CV_32F);
    CvMat *points2 = cvCreateMat(2, featuresFoundCount, CV_32F);

    CvMat *fundamentalMatrix = cvCreateMat(3, 3, CV_32F);

    unsigned int pos = 0;
    for (unsigned int i = 0; i < featuresFoundCount; ++i) {
        while (!featuresFound[pos]) ++pos;

        cvSetReal2D(points1, 0, i, baseFeatures[pos].x);
        cvSetReal2D(points1, 1, i, baseFeatures[pos].y);
        cvSetReal2D(points2, 0, i, features[pos].x);
        cvSetReal2D(points2, 1, i, features[pos].y);
        ++pos;
    }

    int fmCount = cvFindFundamentalMat(points1, points2, fundamentalMatrix, CV_FM_RANSAC, 1.0, 0.99);
    if (fmCount < 1) {
        std::cout << "Fundamental matrix not found." << std::endl;
        return NULL;
    }

    std::cout << fundamentalMatrix->data.fl[0] << " " << fundamentalMatrix->data.fl[1] << " " << fundamentalMatrix->data.fl[2] << "\n";
    std::cout << fundamentalMatrix->data.fl[3] << " " << fundamentalMatrix->data.fl[4] << " " << fundamentalMatrix->data.fl[5] << "\n";
    std::cout << fundamentalMatrix->data.fl[6] << " " << fundamentalMatrix->data.fl[7] << " " << fundamentalMatrix->data.fl[8] << "\n";

    cvReleaseMat(&points1);
    cvReleaseMat(&points2);

    IplImage *result = transformImage(image, *fundamentalMatrix);

    cvReleaseMat(&fundamentalMatrix);

    return result;
}

MAX_CORNERS равен 100и обычно он находит около 70-90 функций.

С этим кодом я получаю странную фундаментальную матрицу, такую ​​как:

-0.000190809 -0.00114947 1.2487
0.00127824 6.57727e-05 0.326055
-1.22443 -0.338243 1

Поскольку я просто держу камеру рукой и стараюсь нечтобы потрясти его (и там не было никаких движущихся объектов), я ожидал, что матрица будет близка к идентичности.Что я делаю не так?

Кроме того, я не уверен, что использовать для преобразования изображения.cvWarpAffine нужна матрица 2x3, мне следует отбросить последнюю строку или использовать другую функцию?

1 Ответ

7 голосов
/ 28 февраля 2011

То, что вы ищете, - это не фундаментальная матрица, а скорее аффинное или перспективное преобразование.

Фундаментальная матрица описывает отношение двух камер, имеющих существенно разные точки обзора.Он рассчитывается так, что если у вас есть две точки x (на одном изображении) и x '(на другом), которые являются проекциями одной и той же точки в пространстве, то x F x' (произведение) равно нулю.Если x и x 'почти идентичны ... тогда единственное решение - сделать F почти нулевым (и практически бесполезным).Вот почему у вас есть то, что у вас есть.

Матрица, которая действительно должна быть близка к тождеству, - это преобразование A, которое преобразует точки x в x '= A x (старое изображение в новое).В зависимости от того, какие типы преобразований вы хотите включить (аффинные или перспективные), вы можете (теоретически) использовать функции cvGetAffineTransform или cvGetPerspectiveTransform для вычисления преобразования.Для этого вам понадобятся 3 или 4 точки соответственно.

Однако лучший выбор (я думаю) - cvFindHomograpy .Он оценивает перспективное преобразование на основе всех доступных пар точек, используя алгоритмы фильтрации выбросов (например, RANSAC), давая вам матрицу 3x3.

Затем вы можете использовать cvWarpPerspective для преобразованиясами изображения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...