20
votes

I managed to acquire camera's intrinsic and extrinsic parameters using OpenCV, thus I have fx, fy, cx and cy. And I also have the screen / image's width and height.

But how do I create an OpenGL perspective projection matrix from these parameters?

glFrustrum shows how to create projection matrix, given Z near, Z far and the image width and height. But how do I include focal points and camera centers in this matrix?

enter image description here

5

5 Answers

9
votes

Here is the code to obtain the OpenGL projection matrix equivalent to a computer vision camera with camera matrix K=[fx, s, cx; 0, fy, cy; 0, 0, 1] and image size [W, H]:

glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity();            // Reset The Projection Matrix
GLdouble perspMatrix[16]={2*fx/W,0,0,0,2*s/W,2*fy/H,0,0,2*(cx/W)-1,2*(cy/H)-1,(zmax+zmin)/(zmax-zmin),1,0,0,2*zmax*zmin/(zmin-zmax),0};
glMultMatrixd(perspMatrix);

NB: zmin and zmax represent the near and far Z clipping planes. This formulation assumes that the OpenGL world coordinate frame is chosen as follows:

enter image description here

The OpenGL camera is assumed to be located at the origin, looking towards positive Z axis, with a down vector collinear and towards the positive Y axis.

4
votes

In relation to the AldurDisciple answer this is the formulation you need to use if the world coordinate frame is choosen with inverted z axe

inverted z axe

glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity();            // Reset The Projection Matrix
GLdouble perspMatrix[16]={2*fx/w,0,0,0,0,2*fy/h,0,0,2*(cx/w)-1,2*(cy/h)-1,-(far+near)/(far-near),-1,0,0,-2*far*near/(far-near),0};
glMultMatrixd(perspMatrix);
1
votes

Open GL operates with a frustum which is related to perspective projection with some limits in depth referred as near and far values. Imagine a pyramid lying on its side - this is frustum. Another analogy is a projector beam that extends in its width and height with the distance - this is frustum too. So right, left, bottom, and top are your image coordinates while near and far are your depth limits with the near beint your focal plane. OpenGL will put Cx and Cy in the center of the image plane so you can skip them. The alternative and more natural way to specify frustum is based on viewing angle or field of view (50-60 deg is typical); the function you call is glPerspective() where you still have near and far but instead of sizes specify the angle and aspect ratio. Good luck.

-1
votes

You have cx, cy, fx, fy, width, height.
And you need left, right, top, bottom in your equations. You can calculate these value using this way.

left = cx * near / -fx
top = cy * near / fy
right = -(width - cx) * near / -fx
bottom = -(height - cy) * near / fy