Перейти к содержимому
Compvision.ru
VVVVV

OpenCV проеция объекта на маркер, solvePnp, углы.

Recommended Posts

Пытаюсь спроецировать чайник на маркер (шахматную доску) при помощи OpenCV и OpenGL.

Как делаю:

* получаю изображение с камеры;

* нахожу шаблон при помощиc vFindChessboardCorners;

* вызываю solvePnp, передав туда матрицу камеры, коэффициенты дисторсии (получил их, используя пример calibration из OpenGL), координаты объекта в 3D, и полученные точки.

* зная, что матрицы OpenCV и OpenGL не совпадают, конвертирую матрицу и передаю её в GL_MODELVIEW.

Проблема: неправильно определяются углы и перенос (см. картинку).

Также: что я должен передать в качестве objectPoints в solvePnp? Я не до конца понимаю суть этих координат.

Что я получаю:

image.png

Код:

void process()

{

    frame = cvQueryFrame(capture);

    cvFlip(frame, frame, 1);

    IplImage * gray = cvCreateImage(cvGetSize(frame), frame->depth, 1);

    cvCvtColor(frame, gray, CV_BGR2GRAY);


    int cornerCount = 0;

    int found = cvFindChessboardCorners(frame, patternSize, patternCorners, &cornerCount, 

            CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);

    cvFindCornerSubPix(gray, patternCorners, PATTERN_SQUARES_COUNT,  patternSize,cvSize(-1,-1),     

                                    cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1 ));

    if( cornerCount == PATTERN_SQUARES_COUNT)

    {   

        CvPoint2D32f patternPlane[4];

        CvPoint2D32f imagePlane[4];

        imagePlane[0].x = 0;

        imagePlane[0].y = 0;

        imagePlane[1].x = 640;

        imagePlane[1].y = 0;

        imagePlane[2].x = 640.0f;

        imagePlane[2].y = 480.0f;

        imagePlane[3].x = 0;

        imagePlane[3].y = 480.0f;


        patternPlane[0].x = patternCorners[0].x;

        patternPlane[0].y = patternCorners[0].y;

        patternPlane[1].x = patternCorners[4].x;

        patternPlane[1].y = patternCorners[4].y;

        patternPlane[2].x = patternCorners[19].x;

        patternPlane[2].y = patternCorners[19].y;

        patternPlane[3].x = patternCorners[15].x;

        patternPlane[3].y = patternCorners[15].y;


        cvGetPerspectiveTransform(imagePlane, patternPlane, warpMatrix);


        cvLine(frame, cvPoint(patternPlane[0].x,patternPlane[0].y) , 

        cvPoint(patternPlane[1].x, patternPlane[1].y), CV_RGB(255, 0, 0));

        cvLine(frame, cvPoint(patternPlane[1].x,patternPlane[1].y) , 

        cvPoint(patternPlane[2].x, patternPlane[2].y), CV_RGB(255, 0, 0));

        cvLine(frame, cvPoint(patternPlane[2].x,patternPlane[2].y) , 

        cvPoint(patternPlane[3].x, patternPlane[3].y), CV_RGB(255, 0, 0));

        cvLine(frame, cvPoint(patternPlane[3].x,patternPlane[3].y) , 

        cvPoint(patternPlane[0].x, patternPlane[0].y), CV_RGB(255, 0, 0));


        cv::Mat rvec(3,1,cv::DataType<double>::type);

        cv::Mat tvec(3,1,cv::DataType<double>::type);

        std::vector<cv::Point3d> objectPoints(4);

        std::vector<cv::Point2d> imagePoints(4);


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

        {

            imagePoints[i].x = patternPlane[i].x;

            imagePoints[i].y = patternPlane[i].y;

        }


        objectPoints[0] = cv::Point3d(-0.5, -0.5, 0);

        objectPoints[1] = cv::Point3d(-0.5, 0.5, 0);

        objectPoints[2] = cv::Point3d(0.5, 0.5, 0);

        objectPoints[3] = cv::Point3d(0.5, -0.5, 0);



        cv::Mat distCoeffs = cv::Mat(5, 1, cv::DataType<double>::type);

        distCoeffs.at<double>(0) = -1.8436299045609152e+000;

        distCoeffs.at<double>(1) = 9.4006548737354095e+001;

        distCoeffs.at<double>(2) = 5.3534809112582196e-002;

        distCoeffs.at<double>(3) = 3.6660383502917997e-002;

        distCoeffs.at<double>(4) = -1.4544803056488936e+003;


        cv::Mat camMat = cv::Mat(3, 3, cv::DataType<double>::type);

        cv::setIdentity(camMat);


        camMat.at<double>(0, 0) = 1.4940995863136072e+003;

        camMat.at<double>(0, 1) = 0;

        camMat.at<double>(0, 2) = 3.2909815768239292e+002;


        camMat.at<double>(1, 0) = 0;

        camMat.at<double>(1, 1) = 1.5489456829024023e+003;

        camMat.at<double>(1, 2) = 1.9730921217312456e+002;


        camMat.at<double>(2, 0) = 0;

        camMat.at<double>(2, 1) = 0;

        camMat.at<double>(2, 2) = 1;




        cv::solvePnP(objectPoints, imagePoints, camMat, distCoeffs, rvec, tvec);

        DebugPrint("Rotation: %f %f %f\n", (float)rvec.at<double>(0), 

            (float)rvec.at<double>(1), 

            (float)rvec.at<double>(2));

        DebugPrint("Translation: %f %f %f\n", tvec.at<double>(0), tvec.at<double>(1), tvec.at<double>(2));



        std::vector<cv::Point3f> axisPoints(8);

        std::vector<cv::Point2f> cubePoints(8);


        axisPoints[0].x = 0;

        axisPoints[0].y = 0;

        axisPoints[0].z = 0;

        axisPoints[1].x = 0;

        axisPoints[1].y = 0;

        axisPoints[1].z = 1;

        axisPoints[2].x = 1;

        axisPoints[2].y = 0;

        axisPoints[2].z = 1;

        axisPoints[3].x = 1;

        axisPoints[3].y = 0;

        axisPoints[3].z = 0;

        axisPoints[4].x = 0;

        axisPoints[4].y = -1;

        axisPoints[4].z = 0;

        axisPoints[5].x = 0;

        axisPoints[5].y = -1;

        axisPoints[5].z = 1;

        axisPoints[6].x = 1;

        axisPoints[6].y = -1;

        axisPoints[6].z = 1;

        axisPoints[7].x = 1;

        axisPoints[7].y = -1;

        axisPoints[7].z = 0;

        cv::projectPoints(axisPoints, rvec, tvec, camMat, distCoeffs, cubePoints);



        cvLine(frame, cubePoints[0], cubePoints[1], CV_RGB(0, 255, 0), 2);

        cvLine(frame, cubePoints[1], cubePoints[2], CV_RGB(0, 255, 0), 2);

        cvLine(frame, cubePoints[2], cubePoints[3], CV_RGB(0, 255, 0), 2);

        cvLine(frame, cubePoints[3], cubePoints[0], CV_RGB(0, 255, 0), 2);


        cvLine(frame, cubePoints[4], cubePoints[5], CV_RGB(255, 0, 0), 2);

        cvLine(frame, cubePoints[5], cubePoints[6], CV_RGB(255, 0, 0), 2);

        cvLine(frame, cubePoints[6], cubePoints[7], CV_RGB(255, 0, 0), 2);

        cvLine(frame, cubePoints[7], cubePoints[4], CV_RGB(255, 0, 0), 2);


        cvLine(frame, cubePoints[4], cubePoints[0], CV_RGB(0, 0, 255), 2);

        cvLine(frame, cubePoints[6], cubePoints[2], CV_RGB(0, 0, 255), 2);

        cvLine(frame, cubePoints[7], cubePoints[3], CV_RGB(0, 0, 255), 2);

        cvLine(frame, cubePoints[5], cubePoints[1], CV_RGB(0, 0, 255), 2);


        tvec.at<double>(0, 0) *= -1;

        cv::Mat R(3, 3, CV_64FC1);

        cv::Rodrigues(rvec, R);


        glMatrixMode(GL_PROJECTION);

        glLoadIdentity();

        gluPerspective(50, 1.3, 1.0, 1000);

        gluLookAt(0, 0, -10, 0, 0, 0, 1, 0, 0);

        glMatrixMode(GL_MODELVIEW);

        glLoadIdentity();

        float mat44[16] =  {(float)R.at<double>(0, 0), (float)R.at<double>(0, 1), (float)R.at<double>(0, 2), 0, 

                            (float)R.at<double>(1, 0), (float)R.at<double>(1, 1), (float)R.at<double>(1, 2), 0, 

                            (float)R.at<double>(2, 0), (float)R.at<double>(2, 1), (float)R.at<double>(2, 2), 0, 

                            tvec.at<double>(0), tvec.at<double>(1), tvec.at<double>(2), 1};


        glLoadMatrixf(mat44);

    }

    cvShowImage(WINDOW_CAPTURE_NAME, frame);

    cvReleaseImage(&gray);

    gray = NULL;

    glutPostRedisplay();

} 

Я уже гуглил, нашел темы, вроде http://stackoverflow.com/questions/19612704/opencv-opengl-proper-camera-pose-using-solvepnp или http://stackoverflow.com/questions/18637494/camera-position-in-world-coordinate-from-cvsolvepnp или http://stackoverflow.com/questions/10313040/opencv-rotation-translation-vector-to-opengl-modelview-matrix?rq=1 , но ни одна из этих ссылок мне не помогла.

Что же я делаю не так?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Сделал просто

glRotatef((rvec.at<double>(0) * 180) / 3.141592, 1, 0, 0);

glRotatef((rvec.at<double>(1) * 180) / 3.141592, 0, 1, 0);

glRotatef((rvec.at<double>(2) * 180) / 3.141592, 0, 0, 1);

Много лучше не стало - углы нестабильно определяются правильно, перенос совсем неправильно работает.

Посмотрел, пытаюсь обпилить исходник под своб задачу. Но это все же не то, ведь мне интересно, где ошибка в моем коде и как её устранить. Прозреваю, что что-то не так именно с конверсией матрицы или неправильно заданными физическими координатам объекта (почему я так думаю: cv::projectPoints работает же).

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

А матрица проекции у вас из каких соображений при помощи LookAt формируется?

И попробуйте умножать на не раздраконенную Родригисом матрицу, а на полную (поворот и перенос вместе).

Помню что-то пробовал с углами делать, тоже вроде бы все скакало.

По поводу переноса, попробуйте поменять порядок операций переноса и поворота.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Поменял код - много лучше не стало.

void process()

{

	frame = cvQueryFrame(capture);

	IplImage * gray = cvCreateImage(cvGetSize(frame), frame->depth, 1);

	cvCvtColor(frame, gray, CV_BGR2GRAY);


	int cornerCount = 0;

	int found = cvFindChessboardCorners(frame, patternSize, patternCorners, &cornerCount, 

			CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);

	cvFindCornerSubPix(gray, patternCorners, PATTERN_SQUARES_COUNT,  patternSize,cvSize(-1,-1),     

                                    cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1 ));

	if( cornerCount == PATTERN_SQUARES_COUNT)

	{	

		CvPoint2D32f patternPlane[4];


		patternPlane[0].x = patternCorners[0].x;

		patternPlane[0].y = patternCorners[0].y;

		patternPlane[1].x = patternCorners[15].x;

		patternPlane[1].y = patternCorners[15].y;

		patternPlane[2].x = patternCorners[19].x;

		patternPlane[2].y = patternCorners[19].y;

		patternPlane[3].x = patternCorners[4].x; 

		patternPlane[3].y = patternCorners[4].y;


		cv::Mat tvec(3,1,cv::DataType<double>::type);

		cv::Mat rvec(3,1,cv::DataType<double>::type);

		std::vector<cv::Point3d> objectPoints(4);

		std::vector<cv::Point2d> imagePoints(4);


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

		{

			imagePoints[i].x = patternPlane[i].x;

			imagePoints[i].y = patternPlane[i].y;

		}


		objectPoints[0] = cv::Point3d(-1, 1, 0);

		objectPoints[1] = cv::Point3d(-1, -1, 0);

		objectPoints[2] = cv::Point3d(1, -1, 0);

		objectPoints[3] = cv::Point3d(1, 1, 0);


		cv::Mat distCoeffs = cv::Mat(5, 1, cv::DataType<double>::type);

		distCoeffs.at<double>(0) = -1.8436299045609152e+000;

		distCoeffs.at<double>(1) = 9.4006548737354095e+001;

		distCoeffs.at<double>(2) = 5.3534809112582196e-002;

		distCoeffs.at<double>(3) = 3.6660383502917997e-002;

		distCoeffs.at<double>(4) = -1.4544803056488936e+003;


		cv::Mat camMat = cv::Mat(3, 3, cv::DataType<double>::type);

		cv::setIdentity(camMat);


		camMat.at<double>(0, 0) = 1.4940995863136072e+003;

		camMat.at<double>(0, 1) = 0;

		camMat.at<double>(0, 2) = 3.2909815768239292e+002;


		camMat.at<double>(1, 0) = 0;

		camMat.at<double>(1, 1) = 1.5489456829024023e+003;

		camMat.at<double>(1, 2) = 1.9730921217312456e+002;


		camMat.at<double>(2, 0) = 0;

		camMat.at<double>(2, 1) = 0;

		camMat.at<double>(2, 2) = 1;


		cv::solvePnP(objectPoints, imagePoints, camMat, distCoeffs, rvec, tvec);


		DebugPrint("Rotation: %f %f %f\n", (float)rvec.at<double>(0), (float)rvec.at<double>(1), (float)rvec.at<double>(2));

		DebugPrint("Translation: %f %f %f\n", tvec.at<double>(0), tvec.at<double>(1), tvec.at<double>(2));


		std::vector<cv::Point3f> axisPoints(4);

		std::vector<cv::Point2f> cubePoints(4);


		axisPoints[0].x = 0;

		axisPoints[0].y = 0;

		axisPoints[0].z = 0;


		axisPoints[1].x = 1;

		axisPoints[1].y = 0;

		axisPoints[1].z = 0;


		axisPoints[2].x = 0;

		axisPoints[2].y = -1;

		axisPoints[2].z = 0;


		axisPoints[3].x = 0;

		axisPoints[3].y = 0;

		axisPoints[3].z = 1;


		cv::projectPoints(axisPoints, rvec, tvec, camMat, distCoeffs, cubePoints);


		cvLine(frame, cubePoints[0], cubePoints[1], CV_RGB(255, 0, 0), 2);

		cvLine(frame, cubePoints[0], cubePoints[2], CV_RGB(0, 255, 0), 2);

		cvLine(frame, cubePoints[0], cubePoints[3], CV_RGB(0, 0, 255), 2);


		glMatrixMode(GL_PROJECTION);

		glLoadIdentity();

		gluPerspective(50, 640/480, 1.0, 1000);


		float proj[16] = {

			2*1.4940995863136072e+003/640, 0, (640 - 2 * 3.2909815768239292e+002) / 640, 0,

			0, 2 * 1.5489456829024023e+003 / 480, (480 - 2 * 1.9730921217312456e+002) / 480, 0,

			0, 0, (-1000 - 1)/(1000 - 1), -2*1000*1/(1000 - 1), 

			0, 0, -1, 0

		};

		glLoadMatrixf(proj);

		glMatrixMode(GL_MODELVIEW);

		glLoadIdentity();


		rvec.at<double>(1) = -1.0 * rvec.at<double>(1);

		rvec.at<double>(2) = -1.0 * rvec.at<double>(2);

		cv::Mat rotMat(3, 3, CV_64FC1);

		cv::Rodrigues(rvec, rotMat);

		float mat44[16] =  {(float)rotMat.at<double>(0, 0), (float)rotMat.at<double>(0, 1), (float)rotMat.at<double>(0, 2), 0, 

							(float)rotMat.at<double>(1, 0), (float)rotMat.at<double>(1, 1), (float)rotMat.at<double>(1, 2), 0, 

							(float)rotMat.at<double>(2, 0), (float)rotMat.at<double>(2, 1), (float)rotMat.at<double>(2, 2), 0, 

							tvec.at<double>(0), -tvec.at<double>(1), -tvec.at<double>(2), 1};


		glLoadMatrixf(mat44);

	}


	cvShowImage(WINDOW_CAPTURE_NAME, frame);

	cvFlip(frame, frame, 0);

	glBindTexture( GL_TEXTURE_2D, backgroundId );

	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);

	glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

	glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

	glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);

	glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);

	gluBuild2DMipmaps(GL_TEXTURE_2D,3,frame->width, frame->height,

                    GL_BGR_EXT,GL_UNSIGNED_BYTE, frame->imageData);


	cvReleaseImage(&gray);

	gray = NULL;

	glutPostRedisplay();

} 

Получаю:

image.png

И попробуйте умножать на не раздраконенную Родригисом матрицу, а на полную (поворот и перенос вместе).

Не совсем понял вас, пожалуйста, поясните.

Помню что-то пробовал с углами делать, тоже вроде бы все скакало.

Уж лучше бы оно скакало, "дрыгания"-то можно подавить, а тут трансформируется неправильно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Интересный мануал по матрицам поворота: http://www.cs.rpi.edu/~trink/Courses/RobotManipulation/lectures/lecture6.pdf

Я имел ввиду использовать не матрицу вида

0 -wz wy
wz 0 -wx
-wy wx 0[/code] (вы из нее углы получаете, затем извращенным способом (glRotate) формируете матрицу преобразования). Можно взять непосредственно матрицу 4х4, полученную из POSIT, и использовать ее для преобразования координат (взять установить единичную, затем умножить на пролученную от POSIT). У меня был такой кусок кода
[code]
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(&posit.projectionMatrix[0]);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Делаем отражение в зеркале
glScalef(-1.0f, -1.0f, -1.0f);
posit.posePOSIT[12] *= -1; // X
posit.posePOSIT[13] *= -1; // Y
glMultMatrixf(posit.posePOSIT);
//*************************************
Draw3DObject(textureFrontID,textureLeftID);

Мой класс POSIT: posit.rar

Писал все это 3 года назад, многое уже забыл.

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Советую почитать книгу Mastering OpenCV. Там целая глава посвящена работе с маркерами при помощи OpenCV&OpenGL

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Сделал таки.

void process()

{

	frame = cvQueryFrame(capture);

	IplImage * gray = cvCreateImage(cvGetSize(frame), frame->depth, 1);

	cvCvtColor(frame, gray, CV_BGR2GRAY);


	int cornerCount = 0;

	int found = cvFindChessboardCorners(frame, patternSize, patternCorners, &cornerCount, 

			CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);

	cvFindCornerSubPix(gray, patternCorners, PATTERN_SQUARES_COUNT,  patternSize,cvSize(-1,-1),     

                                    cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1 ));

	if( cornerCount == PATTERN_SQUARES_COUNT)

	{	

		CvPoint2D32f patternPlane[4];


		patternPlane[0].x = patternCorners[0].x;

		patternPlane[0].y = patternCorners[0].y;

		patternPlane[1].x = patternCorners[15].x;

		patternPlane[1].y = patternCorners[15].y;

		patternPlane[2].x = patternCorners[19].x;

		patternPlane[2].y = patternCorners[19].y;

		patternPlane[3].x = patternCorners[4].x;

		patternPlane[3].y = patternCorners[4].y;


		cv::Mat tvec(3,1,cv::DataType<double>::type);

		cv::Mat rvec(3,1,cv::DataType<double>::type);

		std::vector<cv::Point3d> objectPoints(4);

		std::vector<cv::Point2d> imagePoints(4);


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

		{

			imagePoints[i].x = patternPlane[i].x;

			imagePoints[i].y = patternPlane[i].y;

		}


		objectPoints[0] = cv::Point3d(-1, 0, 1);

		objectPoints[1] = cv::Point3d(-1, 0, -1);

		objectPoints[2] = cv::Point3d(1, 0, -1);

		objectPoints[3] = cv::Point3d(1, 0, 1);


		cv::Mat distCoeffs = cv::Mat(5, 1, cv::DataType<double>::type);

		distCoeffs.at<double>(0) = -1.8436299045609152e+000;

		distCoeffs.at<double>(1) = 9.4006548737354095e+001;

		distCoeffs.at<double>(2) = 5.3534809112582196e-002;

		distCoeffs.at<double>(3) = 3.6660383502917997e-002;

		distCoeffs.at<double>(4) = -1.4544803056488936e+003;


		cv::Mat camMat = cv::Mat(3, 3, cv::DataType<double>::type);

		cv::setIdentity(camMat);


		camMat.at<double>(0, 0) = 1.4940995863136072e+003;

		camMat.at<double>(0, 1) = 0;

		camMat.at<double>(0, 2) = 3.2909815768239292e+002;


		camMat.at<double>(1, 0) = 0;

		camMat.at<double>(1, 1) = 1.5489456829024023e+003;

		camMat.at<double>(1, 2) = 1.9730921217312456e+002;


		camMat.at<double>(2, 0) = 0;

		camMat.at<double>(2, 1) = 0;

		camMat.at<double>(2, 2) = -1;


		cv::solvePnP(objectPoints, imagePoints, camMat, distCoeffs, rvec, tvec);


		std::vector<cv::Point3f> axisPoints(4);

		std::vector<cv::Point2f> cubePoints(4);


		axisPoints[0].x = 0;

		axisPoints[0].y = 0;

		axisPoints[0].z = 0;


		axisPoints[1].x = 1;

		axisPoints[1].y = 0;

		axisPoints[1].z = 0;


		axisPoints[2].x = 0;

		axisPoints[2].y = -1;

		axisPoints[2].z = 0;


		axisPoints[3].x = 0;

		axisPoints[3].y = 0;

		axisPoints[3].z = 1;


		cv::projectPoints(axisPoints, rvec, tvec, camMat, distCoeffs, cubePoints);


		cvLine(frame, cubePoints[0], cubePoints[1], CV_RGB(255, 0, 0), 2);

		cvLine(frame, cubePoints[0], cubePoints[2], CV_RGB(0, 255, 0), 2);

		cvLine(frame, cubePoints[0], cubePoints[3], CV_RGB(0, 0, 255), 2);


		glMatrixMode(GL_PROJECTION);

		gluPerspective(50, 640/480, 1.0, 1000);


		float f_x = 1.4940995863136072e+003;

		float f_y = 1.5489456829024023e+003;

		float c_x = 3.2909815768239292e+002;

		float c_y = 1.9730921217312456e+002;


		float fx = -2.0 * f_x / 640;

		float fy = 2.0 * f_y / 480;

		float cx = 2.0 * c_x / 640 - 1;

		float cy = 2.0 * c_y / 480 - 1;

		float fn = -(100 + 1) / (100 - 1);

		float fcn = -2.0 * 100 * 1 / (100 - 1);


		float proj[16] = {

			fx, 0, cx, 0,

			0, fy, cy, 0,

			0, 0, fn, fcn, 

			0, 0, -1, 0

		};


		glLoadMatrixf(proj);

		glMatrixMode(GL_MODELVIEW);

		glLoadIdentity();


		cv::Mat rotMat(3, 3, CV_64FC1);

		cv::Rodrigues(rvec, rotMat);


		float mat44[16] =  {(float)rotMat.at<double>(0, 0), (float)rotMat.at<double>(0, 1), (float)rotMat.at<double>(0, 2), 0, 

							(float)rotMat.at<double>(1, 0), (float)rotMat.at<double>(1, 1), (float)rotMat.at<double>(1, 2), 0, 

							(float)rotMat.at<double>(2, 0), (float)rotMat.at<double>(2, 1), (float)rotMat.at<double>(2, 2), 0, 

							tvec.at<double>(0), tvec.at<double>(1), -tvec.at<double>(2), 1};



		glLoadMatrixf(mat44);


		glRotatef(180, 0, 1, 0);

	}


	cvShowImage(WINDOW_CAPTURE_NAME, frame);

	cvReleaseImage(&gray);

	gray = NULL;

	glutPostRedisplay();

} 

Mastering OpenCV

Полистал. Интересная книга, эдакий сбрник рецептов, "смотрите, при помощи OpenCV можно сделать такие-то прикалюхи".

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

А в каких попугаях возвращяется вектор переноса? Получаю что-то вроде x: 0.14 y: -0,91 z: -30, из которых доверие вызывает только z, а по остальным двум осям положение объекта не соответствует маркеру.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Вероятно в координатах OpenGL-евской проекции, определяемой матрицей проекции.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Это я почему спрашиваю: объект "гуляет" по маркеру. Отсюда я делаю вывод, что его система координат установлена неправильно. И чего-то совсем я не понимаю, что пошло не так. Интернет имеет мне заявить, будто все нормально, но это не так.

Иллюстрация.

image.png

Код.


void CameraCalibration::getOpenGlProjectionMatrix(float farPlane, float nearPlane, float width, float height, float *matrix[16])

{

	(*matrix)[0] = -2.0 * cameraMatrix.at<double>(0, 0) / width; // fx

	(*matrix)[1] = 0;

	(*matrix)[2] = 2.0 * cameraMatrix.at<double>(0, 2) / (width - 1); // cx

	(*matrix)[3] = 0;


	(*matrix)[4] = 0;

	(*matrix)[5] = 2.0 * cameraMatrix.at<double>(1, 1) / height; // fy

	(*matrix)[6] = 2.0 * cameraMatrix.at<double>(1, 2) / (height - 1); // cy

	(*matrix)[7] = 0;


	(*matrix)[8] = 0;

	(*matrix)[9] = 0;

	(*matrix)[10] = -(farPlane + nearPlane) / (farPlane - nearPlane); // fn

	(*matrix)[11] = -2.0 * farPlane * nearPlane / (farPlane - nearPlane); // fcn


	(*matrix)[12] = 0;

	(*matrix)[13] = 0;

	(*matrix)[14] = -1;

	(*matrix)[15] = 0;

}


void PoseEstimator::convertToOpenGlMatrix(cv::Mat& rvec, cv::Mat& tvec, float * openglMatrix[16])

{

	cv::Mat rotMat(3, 3, CV_64FC1);

	cv::Rodrigues(rvec, rotMat);


	rotMat = rotMat.t();

	(*openglMatrix)[0] = rotMat.at<double>(0, 0);

	(*openglMatrix)[1] = rotMat.at<double>(0, 1);

	(*openglMatrix)[2] = rotMat.at<double>(0, 2);

	(*openglMatrix)[3] = 0;

	(*openglMatrix)[4] = rotMat.at<double>(1, 0);

	(*openglMatrix)[5] = rotMat.at<double>(1, 1);

	(*openglMatrix)[6] = rotMat.at<double>(1, 2);

	(*openglMatrix)[7] = 0;

	(*openglMatrix)[8] = rotMat.at<double>(2, 0);

	(*openglMatrix)[9] = rotMat.at<double>(2, 1);

	(*openglMatrix)[10] = rotMat.at<double>(2, 2);

	(*openglMatrix)[11] = 0;

	//tvec = -rotMat.t() * tvec;



	double x = -tvec.at<double>(0);

	double y = -tvec.at<double>(1);

	double z = -tvec.at<double>(2);



	(*openglMatrix)[12] = x;

	(*openglMatrix)[13] = y;

	(*openglMatrix)[14] = z;

	(*openglMatrix)[15] = 1;

	printf("x: %f y: %f z: %f\n", x, y, z);

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Голова моя слепая, матрица проекции задана неправильно! Первая же ссылка в гугле: http://www.songho.ca/opengl/gl_projectionmatrix.html

Вот этот код работает:


void CameraCalibration::getOpenGlProjectionMatrix(float farPlane, float nearPlane, float width, float height, float *matrix[16])

{

	(*matrix)[0] = 2.0 * cameraMatrix.at<double>(0, 0) / width;

	(*matrix)[1] = 0;

	(*matrix)[2] = 0;

	(*matrix)[3] = 0;


	(*matrix)[4] = 0;

	(*matrix)[5] = 2.0 * cameraMatrix.at<double>(1, 1) / height;

	(*matrix)[6] = 0;

	(*matrix)[7] = 0;


	(*matrix)[8] = 2.0 * (cameraMatrix.at<double>(0, 2) / width) - 1;

	(*matrix)[9] = 2.0 * (cameraMatrix.at<double>(1, 2) / height) - 1;

	(*matrix)[10] = -(farPlane + nearPlane) / (farPlane - nearPlane);

	(*matrix)[11] = -1;


	(*matrix)[12] = 0;

	(*matrix)[13] = 0;

	(*matrix)[14] = -2.0 * farPlane * nearPlane / (farPlane - nearPlane);;

	(*matrix)[15] = 0;

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Однако, при попытке расположить маркер точно напротив камеры, объект проецируется неправильно.

post-6676-0-87683600-1391026485_thumb.pn

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Другая вещь, которую я не могу понять, это почему не удается создать иллюзию присутствия объекта на маркере. Если выводить линии через cvProjectPoints, все нормально, нарисованное как бы "прилипает" к центру маркера, что ожидаемо и понятно. А вот с выводом модельки такого не получается, несмотря на то, что углы и трансляция вычисляется верно. Я подозреваю, что дело в fov, но ведь я использую матрицу проекции камеры! Сейчас я пытаюсь подобрать нужный fov и понять, что не так.

Что же я пропустил?

На поясняющей картнике видно, что моделька трансформируется верно, но к маркеру не прилипает и иллюзия разрушается.

post-6676-0-00930100-1397670504_thumb.pn

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

А может просто камера фокус подстраивает, вот fov и плавает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

что значит не прилипает? стул вроде как стоит на плоскости. кстати вы это делаете на чистом opencv? вроде был еще ARToolKit.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Камера без автофокуса.

что значит не прилипает? стул вроде как стоит на плоскости.

Попробую пояснить.

Что я ожидаю:

крусло жестко привязано к центру маркера и остается в центре его при любых поворотах.

Что я получаю:

На картинке "А" видно кресло на маркере, оно не в центре, ну да ладно, может координаты модельки такие. Теперь, когда я повернул маркер (рисунок "Б"), кресло повернется на тот же угол, но как бы "сдвинется" с маркера.

кстати вы это делаете на чистом opencv? вроде был еще ARToolKit.

Есть обязательно, но я не преследую какой-либо практической цели, просто интересное развлечение.

Напишу сюда решение, если пойму как создать эту иллюзию.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

А все оказалось очень просто:

1. Центр объектов был в (0; 0; 0).

2. Координаты модели (первый параметр solvePnP) надо было задавать так, чтобы центр модели был в (0; 0; 0)

Что происходило:

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

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

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

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×