Тестирование фундаментальной матрицы

Мои вопросы:

  • Как мне понять, верна ли моя фундаментальная матрица?
  • Является ли код, который я разместил ниже, хорошим усилием в этом направлении?

Моя конечная цель — сделать своего рода 3D-реконструкцию. Сейчас я пытаюсь рассчитать фундаментальную матрицу, чтобы оценить разницу между двумя камерами. Я делаю это в openFrameworks, используя аддон ofxCv, но по большей части это просто чистый OpenCV. Трудно опубликовать код, который изолирует проблему, так как ofxCv также находится в разработке.

Мой код в основном читается в двух кадрах 640x480, снятых моей веб-камерой с немного разных позиций (в основном, просто немного сдвигая ноутбук по горизонтали). У меня уже есть для него калибровочная матрица, полученная из кода калибровки ofxCv, в котором используется findChessboardCorners. Пример кода неискажения, по-видимому, указывает на то, что калибровочная матрица точна. Он вычисляет оптический поток между изображениями (либо calcOpticalFlowPyrLK, либо calcOpticalFlowFarneback) и передает эти пары точек на findFundamentalMatrix.

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

Вот основная матрица и матрица вращения моего последнего кода, если это поможет:

fund: [-8.413948689969405e-07, -0.0001918870646474247, 0.06783422344973795;
    0.0001877654679452431, 8.522397812179886e-06, 0.311671691674232;
    -0.06780237856576941, -0.3177275967586101, 1]
R: [0.8081771697692786, -0.1096128431920695, -0.5786490187247098;
    -0.1062963539438068, -0.9935398408215166, 0.03974506055610323;
    -0.5792674230456705, 0.02938723035105822, -0.8146076621848839]
t: [0, 0.3019063882496216, -0.05799044915951077;
    -0.3019063882496216, 0, -0.9515721940769112;
    0.05799044915951077, 0.9515721940769112, 0]

Вот моя часть кода, которая появляется после того, как сделан второй снимок:

const ofImage& image1 = images[images.size() - 2];
const ofImage& image2 = images[images.size() - 1];

std::vector<cv::Point2f> points1 = flow->getPointsPrev();
std::vector<cv::Point2f> points2 = flow->getPointsNext();

std::vector<cv::KeyPoint> keyPoints1 = convertFrom(points1);
std::vector<cv::KeyPoint> keyPoints2 = convertFrom(points2);

std::cout << "points1: " << points1.size() << std::endl;
std::cout << "points2: " << points2.size() << std::endl;


fundamentalMatrix = (cv::Mat)cv::findFundamentalMat(points1, points2);
cv::Mat cameraMatrix = (cv::Mat)calibration.getDistortedIntrinsics().getCameraMatrix();
cv::Mat cameraMatrixInv = cameraMatrix.inv();
std::cout << "fund: " << fundamentalMatrix << std::endl;

essentialMatrix = cameraMatrix.t() * fundamentalMatrix * cameraMatrix;

cv::SVD svd(essentialMatrix);
Matx33d W(0,-1,0,   //HZ 9.13
          1,0,0,
          0,0,1);

cv::Mat_<double> R = svd.u * Mat(W).inv() * svd.vt; //HZ 9.19

std::cout << "R: " << (cv::Mat)R << std::endl;
Matx33d Z(0, -1, 0,
          1, 0, 0,
          0, 0, 0);
cv::Mat_<double> t = svd.vt.t() * Mat(Z) * svd.vt;
std::cout << "t: " << (cv::Mat)t << std::endl;

Vec3d tVec = Vec3d(t(1,2), t(2,0), t(0,1));

Matx34d P1 = Matx34d(R(0,0),    R(0,1), R(0,2), tVec(0),
                     R(1,0),    R(1,1), R(1,2), tVec(1),
                     R(2,0),    R(2,1), R(2,2), tVec(2));
ofMatrix4x4 ofR(R(0,0),    R(0,1), R(0,2), 0,
                R(1,0),    R(1,1), R(1,2), 0,
                R(2,0),    R(2,1), R(2,2), 0,
                0, 0, 0, 1);
ofRs.push_back(ofR);

cv::Matx34d P(1,0,0,0,
              0,1,0,0,
              0,0,1,0);

for (int y = 0; y < image1.height; y += 10) {
    for (int x = 0; x < image1.width; x += 10) {
        Vec3d vec(x, y, 0);

        Point3d point1(vec.val[0], vec.val[1], vec.val[2]);
        Vec3d result = (cv::Mat)((cv::Mat)R * (cv::Mat)vec);
        Point3d point2 = result;


        mesh.addColor(image1.getColor(x, y));
        mesh.addVertex(ofVec3f(point1.x, point1.y, point1.z));

        mesh.addColor(image2.getColor(x, y));
        mesh.addVertex(ofVec3f(point2.x, point2.y, point2.z));
    }
}

Любые идеи? Правильно ли выглядит моя фундаментальная матрица, или у меня неправильная идея при ее тестировании?


person noisecapella    schedule 23.08.2012    source источник
comment
Может быть, кто-то может найти это полезным: Фундаментальная матричная оценка: исследование критериев ошибки   -  person Georgy    schedule 11.05.2018


Ответы (3)


Если вы хотите узнать, верна ли ваша фундаментальная матрица, вам следует вычислить ошибку. Используя эпиполярное уравнение ограничения, вы можете проверить, насколько близко обнаруженные особенности на одном изображении лежат на эпиполярных линиях другого изображения. В идеале сумма этих скалярных произведений должна равняться 0, и, таким образом, ошибка калибровки вычисляется как сумма абсолютных расстояний (SAD). Среднее значение SAD указывается как ошибка стереокалибровки. По сути, вы вычисляете SAD вычисленных функций в image_left (могут быть углы шахматной доски) из соответствующих эпиполярных линий. Эта ошибка измеряется в пикселях ^ 2, допустимо все, что меньше 1.

В OpenCV есть примеры кода, посмотрите cpp-файл Stereo Calibrate, он показывает, как вычислить эту ошибку. https://code.ros.org/trac/opencv/browser/trunk/opencv/samples/c/stereo_calib.cpp?rev=2614 Посмотрите строки 260–269 «avgErr».

Анкур

person Ankur    schedule 24.08.2012
comment
Спасибо за Ваш ответ! Кроме того, знаете ли вы примерное количество баллов, которое я должен предоставить findFundamentalMatrix? Сейчас у меня 200 баллов, но я не уверен, что это слишком много. Я использую CV_RANSAC - person noisecapella; 24.08.2012
comment
Для вычисления фундаментальной матрицы с помощью RANSAC требуется как минимум 8 баллов (я действительно считаю, что в этом случае RANSAC используется для получения хороших совпадений, а затем применяется 8-точечный алгоритм (из-за заданного минимума в 8 баллов)): docs.opencv.org/modules/calib3d/doc/ - person rbaleksandar; 28.11.2014
comment
Ссылка не работает. И я просмотрел всю историю stereo_calib.cpp на GitHub, но не смог найти этот загадочный avgErr. - person Georgy; 11.05.2018
comment
github.com/opencv/opencv/blob/ master/samples/cpp/ avgErr находится в коде (строки 183+). Специальной функции для него нет. - person Phann; 04.12.2018

я думаю, что вы не удалили неверные совпадения, прежде чем использовать их для вычисления F. Также у меня есть идея о том, как проверить F, начиная с x'Fx=0, вы можете заменить несколько x' и x в формуле.

КайлФан

person KyleFan    schedule 04.07.2016
comment
Это должен быть комментарий, а не ответ - person shapiro yaacov; 04.07.2016

Я написал функцию Python для этого:

def Ferror(F,pts1,pts2):  # pts are Nx3 array of homogenous coordinates.  
    # how well F satisfies the equation pt1 * F * pt2 == 0
    vals = pts1.dot(F).dot(pts2.T)
    err = np.abs(vals)
    print("avg Ferror:",np.mean(err))
    return np.mean(err)
person john ktejik    schedule 26.11.2019