Jump to content
Compvision.ru
Smorodov

Программка калибрующая камеру

Recommended Posts

Кстати. В gimp'е есть фильтр "убрать искажение оптики". Там несколько движков, передвигая которые можно убирать дисторсию.

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

Ещё есть убирание дисторсии в проекте с открытыми исходниками IVT. Пример называется UndistortionRectificationDemo. В этом же примере есть "выпрямление" изображения, если оно снималось под наклоном.

Share this post


Link to post
Share on other sites

Ещё есть убирание дисторсии в проекте с открытыми исходниками IVT. Пример называется UndistortionRectificationDemo. В этом же примере есть "выпрямление" изображения, если оно снималось под наклоном.

Можна вопрос???

Не могу понять что-это за ресурс IVT. Это еще ожни библиотеки, че-то наподобе ОпенСв... Или я ошибаюсь...

Share this post


Link to post
Share on other sites

Не ошибаешься.

А какой из этих вариантов тогда выходит лучше!!!! OpenCV или IVT???? или это дело выбора???

Share this post


Link to post
Share on other sites

Что тебе на текущий момент больше подходит, то и выбирай. OpenCV хорошая, но неидеальная библиотека. Ну и никто не запрещает использовать и то, и другое одновременно.

Share this post


Link to post
Share on other sites

Что тебе на текущий момент больше подходит, то и выбирай. OpenCV хорошая, но неидеальная библиотека. Ну и никто не запрещает использовать и то, и другое одновременно.

Спасибо за инфу!!!!!!

Share this post


Link to post
Share on other sites

Всем, привет! =)

Ну как, в итоге что-нибудь получилось?

Share this post


Link to post
Share on other sites

Я как-то писал:

С эпиполярными линиями все понятно, все работает почти при любых позициях камер.

Так вот... При любых позициях все работает, но проблема в самих точках. Они должны быть на одной плоскости. Чем больше отклонение от плоскости, тем хуже находит эпиполярные линии.

До того как я это узнал, прошло много времени. Потом я попытался всё сделать по-другому, составил громадную систему уравнений, там остаются неизвестные.

Недавно нашел одну хорошую книгу на Английском, пробежался по картинкам, но еще не читал.

На этом пока остановился. Не хватает времени и идей.

Share this post


Link to post
Share on other sites

А книжка не Multiple View Geometry ?

Share this post


Link to post
Share on other sites

Чуть-чуть не в тему, на калибровку я забил пока, калибрую по доске, оттуда же беру матрицы трансформации. Не получается из соответствующих точек на двух изображениях получить 3D координату.

Нашел вот такую презентацию еще, там кусок из Multiple View Geometry как раз то, что надо, все разложено по полочкам:

http://users.cecs.anu.edu.au/~luke/cvcourse_files/online_notes/lectures_3D_5_calibrated_recon.pdf

Написал функцию, вроде все правильно, а в итоге вообще не понимаю, в каких координатах она мне что возвращает и как это привязать к камере. Даже расстроился, столько времени потратил, вроде вот оно, а до конца разобраться не получается. Может там всего-то надо домножить на внутренние параметры камеры где-то?


//CvMat* x1 = cvCreateMat(3,1,CV_32FC1); // Точка на первом изображении в виде матрицы [x y 1] (координаты в пикселях)

//CvMat* x2 = cvCreateMat(3,1,CV_32FC1); // Соответствующая точка на втором изображении

//CvMat* P = cvCreateMat(3,4,CV_32FC1); // Относительное перемещение камеры между кадрами

//CvMat* Х = cvCreateMat(3,1,CV_32FC1); // output - Получаю точку [X Y Z] по идее в координатах первой камеры 


void TwoViewTriangulation(CvMat *x1, CvMat *x2, CvMat *P, CvMat *X) {

  CvMat* P1cam = cvCreateMat(3,4,CV_32FC1);

  CvMat* P2cam = cvCreateMat(3,4,CV_32FC1);

  CvMat* A = cvCreateMat(4,4,CV_32FC1);

  CvMat* Anorm = cvCreateMat(4,4,CV_32FC1);

  CvMat* U = cvCreateMat(4,4,CV_32FC1);

  CvMat* D = cvCreateMat(4,4,CV_32FC1);

  CvMat* Vt = cvCreateMat(4,4,CV_32FC1);


  // P1cam = [ I | 0 ]

  cvmSet(P1cam,0,0, 1); cvmSet(P1cam,0,1, 0); cvmSet(P1cam,0,2, 0); cvmSet(P1cam,0,3, 0);

  cvmSet(P1cam,1,0, 0); cvmSet(P1cam,1,1, 1); cvmSet(P1cam,1,2, 0); cvmSet(P1cam,1,3, 0);

  cvmSet(P1cam,2,0, 0); cvmSet(P1cam,2,1, 0); cvmSet(P1cam,2,2, 1); cvmSet(P1cam,2,3, 0);

  cvCopy(P, P2cam, 0);


  for (int i = 0; i < 4; ++i) {

    cvmSet(A,0,i, cvmGet(x1,0,0) * cvmGet(P1cam,2,i) - cvmGet(P1cam,0,i));

    cvmSet(A,1,i, cvmGet(x1,1,0) * cvmGet(P1cam,2,i) - cvmGet(P1cam,1,i));

    cvmSet(A,2,i, cvmGet(x2,0,0) * cvmGet(P2cam,2,i) - cvmGet(P2cam,0,i));

    cvmSet(A,3,i, cvmGet(x2,1,0) * cvmGet(P2cam,2,i) - cvmGet(P2cam,1,i));

  }

  cvNormalize(A, Anorm, 1, 0, CV_L2, NULL);

  cvSVD(Anorm, D, U, Vt, CV_SVD_MODIFY_A || CV_SVD_V_T); // A = U D V^T

  double W = cvmGet(Vt,3,3);

  cvmSet(X,0,0, cvmGet(Vt,0,3)/W);

  cvmSet(X,1,0, cvmGet(Vt,1,3)/W);

  cvmSet(X,2,0, cvmGet(Vt,2,3)/W);

}

В OpenCV 2.2 есть функция cvTriangulatePoints для той же цели, но у меня под билдер тока 1.1 и вообще с ней тоже сходу не разберешься...

Буду благодарен любой помощи!

Share this post


Link to post
Share on other sites

А книжка не Multiple View Geometry ?

Да) Second Edition. Только теперь полная версия)

Share this post


Link to post
Share on other sites

Dr.Hell В демках OpenCV должен быть пример работы с шахматной доской, вот только с одной камерой.

Используйте справочник OpenCV

Share this post


Link to post
Share on other sites

Ура, получилось! =) Разобрался с матрицами проекций и все встало на свои места. Сейчас попробую все расписать подробно.

Дано: вебкамера 1 шт, доска шахматная калибровочная 1 шт.

Надо: определить положение соответствующих ключевых точек в 3Д пространстве сцены.

Еще раз уточню, что задачу я упростил, мне не нужно получать внешние параметры камеры из ключевых точек, у меня есть доска. =)

Получается следующий алгоритм:

1) Калибруем камеру при помощи доски (этот пример как раз есть в книжке по OpenCV: стандартная связка cvFindChessboardCorners->cvFindCornerSubPix->cvCalibrateCamera2 в гугле по этим функциям находится куча страничек всяких индусов и китайцев, которые перепечатали и успешно откомпилили код из книжки и очень по этому поводу радуются <_< ) - получаем матрицу внутренних параметров камеры (intrinsic) и коэффициенты искажения (distCoeffs). Сохраняем их в xml. Калибровку делаем один раз для одной камеры (если не использовали зум).

2) Используем cvUndistort2 для устранения искажений изображения с камеры.

3) Делаем два снимка, перемещая камеру, из них мы и будем получать наши трехмерные координаты.

4) В функцию cvFindExtrinsicCameraParams2 передаем новые координаты точек доски для первого и второго изображения и внутренние параметры камеры (камера у нас одна, так что параметры одинаковые, будем называть их матрицей K). Получаем rvecs и tvecs - векторы вращения и перемещения для каждого нового положения камеры.

5) Используем cvRodrigues2(rvecs,rmat,NULL); получаем матрицу вращения камеры размерностью 3х3.

До этого пункта мне все было понятно и вчера, проблемы появились дальше.

6) Необходимо получить матрицу проекции P для каждого из двух изображений. По определению m = P*M, где m = [x,y,1]^T - координаты точки на изображении в пикселях, а M = [X,Y,Z]^T - координаты точки в трехмерном пространстве сцены. Так вот, матрица P в том виде, что нам нужна, получается так: P = K*Pcam, где К - матрица внутренних параметров камеры, а Pcam = [rmat | tvecs] размерностью 3х4.

7) Если передать полученные значения в функцию cvTriangulatePoints из OpenCV 2.2, то она вернет вполне корректные координаты точки в трехмерном пространстве сцены.

Я чуть-чуть переписал свою функцию, так что она теперь получает и возвращает такие же параметры, как и cvTriangulatePoints.


//CvMat* projPoints1 = cvCreateMat(2,N,CV_32FC1); // Массив координат точек на первом изображении в пикселях виде матрицы: 

// | x1 x2 ... xN |

// | y1 y2 ... yN |, N - количество точек

//CvMat* projPoints2 = cvCreateMat(2,N,CV_32FC1); // Соответствующие точки:: на втором изображении

//CvMat* projMatr1 = cvCreateMat(3,4,CV_32FC1); //Матрица проекции для первого изображения

//CvMat* projMatr2 = cvCreateMat(3,4,CV_32FC1); //Матрица проекции для второго изображения

//CvMat* points4D = cvCreateMat(4,N,CV_32FC1); // output - получаем массив координат точек в трехмерном пространстве сцены в виде матрицы:

// | X1 X2 ... XN |

// | Y1 Y2 ... YN |

// | Z1 Z2 ... ZN |

// | W1 W2 ... WN |, N - количество точек, W - масштабный множитель или как-то так он называется

void TwoViewTriangulation(CvMat *projMatr1, CvMat *projMatr2, CvMat *projPoints1, CvMat *projPoints2, CvMat *points4D) {

  CvMat* A = cvCreateMat(4,4,CV_64F);

  CvMat* Anorm = cvCreateMat(4,4,CV_64F);

  CvMat* U = cvCreateMat(4,4,CV_64F);

  CvMat* D = cvCreateMat(4,4,CV_64F);

  CvMat* Vt = cvCreateMat(4,4,CV_64F);


  for (int n = 0; n < projPoints1->cols; n++)

  {

      for (int i = 0; i < 4; i++) {

        cvmSet(A,0,i, cvmGet(projPoints1,0,n) * cvmGet(projMatr1,2,i) - cvmGet(projMatr1,0,i));

        cvmSet(A,1,i, cvmGet(projPoints1,1,n) * cvmGet(projMatr1,2,i) - cvmGet(projMatr1,1,i));

        cvmSet(A,2,i, cvmGet(projPoints2,0,n) * cvmGet(projMatr2,2,i) - cvmGet(projMatr2,0,i));

        cvmSet(A,3,i, cvmGet(projPoints2,1,n) * cvmGet(projMatr2,2,i) - cvmGet(projMatr2,1,i));

      }

      cvNormalize(A, Anorm, 1, 0, CV_L2, NULL);

      cvSVD(Anorm, D, U, Vt, CV_SVD_MODIFY_A || CV_SVD_V_T); // A = U D V^T


      cvmSet(points4D,0,n, cvmGet(Vt,0,3));

      cvmSet(points4D,1,n, cvmGet(Vt,1,3));

      cvmSet(points4D,2,n, cvmGet(Vt,2,3));

      cvmSet(points4D,3,n, cvmGet(Vt,3,3));

  }

}

8) Чтобы получить реальные координаты в масштабе сцены, нужно все координаты X, Y, Z разделить на W.

Пока проверил на координатах точек доски, расчетные довольно точно совпадают с реальными (ну, примерно совпадают - уже хорошо :)). Пойду другие ключевые точки доставать и испытывать.

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

post-665-0-41163800-1304697068_thumb.jpg

  • Like 2

Share this post


Link to post
Share on other sites

Здравствуйте! Т.е. если у меня есть два изначально откалиброванных изображения, известна ориентация камер, эпиполярные прямые построены, то я могу узнать фокусное расстояние камер и координаты центра камер? Или хотя бы базу стереоскпической системы, т.е. на сколько смещен центр правой камеры относительно центра левой.

Share this post


Link to post
Share on other sites

Вот тут попробуйте посмотреть.

Share this post


Link to post
Share on other sites

Здравствуйте! Т.е. если у меня есть два изначально откалиброванных изображения, известна ориентация камер, эпиполярные прямые построены, то я могу узнать фокусное расстояние камер и координаты центра камер? Или хотя бы базу стереоскпической системы, т.е. на сколько смещен центр правой камеры относительно центра левой.

Здравствуйте! Уточните, пожалуйста, какие параметры точно известны.

Share this post


Link to post
Share on other sites

есть стереоскопическая система, где камеры расположены так, что оси Х коллинеарны, а Y и Z параллельны. из параметров камеры известен только угол камер. ну и что координаты y1=y2 и z1=z2. известны 2D-координаты сопряженных точек

Share this post


Link to post
Share on other sites

Из этих параметров мы можем узнать только диспаритет. Нет ни одного параметра, который мог бы хоть как-то зафиксировать размеры системы.

Вот тут для стереопары все очень понятно расписано: http://blog.vidikon.com/?p=176

Edited by Dr.Hell

Share this post


Link to post
Share on other sites

В недавно вышедшей версии OpenCV 2.3 появилась возможность калибровки не по шахматной доске, а по кругам. Вроде, точнее получается.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

×