Camera calibration and pose estimation (OpenGL + OpenCV)

asked 2017-03-01 07:33:45 -0600

updated 2017-03-01 07:35:53 -0600

Hello i'm fairly new to OpenCV. I'm trying to estimate the 3D pose of the camera in order to draw a 3D teapot using OpenGL. I have been testing for about a week and I partially understand the theory, I tried to replicate an example but I do not get it to appear correctly. I get the keypoints using SIFT and looks right.

I use this function in order to obtain the intrinsics and extrinsics parameters:

ret, K, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, im_size,None,None)

When I have these parameters I create the loop to draw the teapot:

def setup():
    pygame.init()
    pygame.display.set_mode((im_size[0], im_size[1]), pygame.OPENGL | pygame.DOUBLEBUF)
    pygame.display.set_caption('OpenGL AR demo')

setup()
S = 1 # Selected Image
while True:
    event = pygame.event.poll()
    if event.type in (pygame.QUIT, pygame.KEYDOWN):
        break

    draw_background(I[S - 1])
    set_projection_from_camera(K)
    set_modelview_from_camera(rvecs[S-1], tvecs[S-1])
    draw_teapot(100)

    pygame.display.flip()
    pygame.time.wait(50)

I estimate the projection using this function:

def set_projection_from_camera(K):
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    fx = K[0,0]
    fy = K[1,1]
    fovy = 2*arctan(0.5*im_size[1]/fy)*180/pi
    aspect = (im_size[0]*fy)/(im_size[1]*fx)
    # define the near and far clipping planes
    near = 0.1
    far = 500000.0
    # set perspective
    gluPerspective(fovy, aspect, near, far)
    glViewport(0, 0, im_size[0], im_size[1])

I estimate the modelview using this function:

def set_modelview_from_camera(rvec, tvec):
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()

    Rx = array([[1, 0, 0], [0, 0, -1], [0, 1, 0]]) # rotate the teapot
    M = eye(4)
    M[:3, :3] = dot(Rx, cv2.Rodrigues(rvec)[0])
    M[:3, 3] = tvec.T
    cv2GlMat = array([[1,0,0,0],[0,-1,0,0],[0,0,-1,0],[0,0,0,1]]) #OpenCV -> OpenGL matrix
    M = dot(cv2GlMat, M)
    m = M.T.flatten()
    glLoadMatrixf(m)

The function to draw the background (the real image)

def draw_background(I):
    bg_image = Image.fromarray(I)
    bg_data = bg_image.tobytes('raw', 'RGBX', 0, -1)

    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    # bind the texture
    glEnable(GL_TEXTURE_2D)
    glBindTexture(GL_TEXTURE_2D, glGenTextures(1))
    glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,bg_image.size[0],bg_image.size[1],0,GL_RGBA,GL_UNSIGNED_BYTE,bg_data)
    glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST)
    glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST)
    # create quad to fill the whole window
    glBegin(GL_QUADS)
    glTexCoord2f(0.0,0.0); glVertex3f(-1,-1,-1.0)
    glTexCoord2f(1.0,0.0); glVertex3f( 1,-1,-1.0)
    glTexCoord2f(1.0,1.0); glVertex3f( 1, 1,-1.0)
    glTexCoord2f(0.0,1.0); glVertex3f(-1, 1,-1.0)
    glEnd()
    # clear the texture
    glDeleteTextures(1)

I understand the concepts of Opencv Calibration, but I cannot put together into OpenGL and show the object correctly on the screen.

edit retag flag offensive close merge delete

Comments

1

Related (to check the conversion between OpenCV intrinsic + extrinsic matrices with OpenGL convention) as I guess the problem should be the convention used between OpenCV / OpenGL:

Eduardo gravatar imageEduardo ( 2017-03-01 11:01:24 -0600 )edit