python opencv camera-calibration

Python Opencv SolvePnP produce un vector de traducción incorrecto



camera-calibration (1)

Estoy intentando calibrar y encontrar la ubicación y la rotación de una sola cámara virtual en Blender 3d utilizando homografía. Estoy usando Blender para poder verificar dos veces mis resultados antes de pasar al mundo real donde es más difícil. Presté diez imágenes de un tablero de ajedrez en varias ubicaciones y rotaciones en la vista de mi cámara estacionaria. Con python de opencv, usé cv2.calibrateCamera para encontrar la matriz intrínseca de las esquinas detectadas del tablero de ajedrez en las diez imágenes y luego usé eso en cv2.solvePnP para encontrar los parámetros extrínsecos (traslación y rotación). Sin embargo, aunque los parámetros estimados estaban cerca de los reales, hay algo raro. Mi estimación inicial de la traducción fue (-0.11205481, -0.0490256,8.13892491). La ubicación real fue (0,08.07105). Bastante cerca ¿verdad? Pero cuando moví y giré la cámara ligeramente y volví a enviar las imágenes, la traducción estimada se fue alejando. Estimado: (-0.15933154,0.13367286,9.34058867). Real: (-1.7918, -1.51073,9.76597). El valor de Z está cerca, pero la X y la Y no lo están. Estoy completamente confundido. Si alguien me puede ayudar a resolver esto, estaría muy agradecido. Aquí está el código (se basa en el ejemplo de calibración de python2 suministrado con opencv):

#imports left out USAGE = '''''' USAGE: calib.py [--save <filename>] [--debug <output path>] [--square_size] [<image mask>] '''''' args, img_mask = getopt.getopt(sys.argv[1:], '''', [''save='', ''debug='', ''square_size='']) args = dict(args) try: img_mask = img_mask[0] except: img_mask = ''../cpp/0*.png'' img_names = glob(img_mask) debug_dir = args.get(''--debug'') square_size = float(args.get(''--square_size'', 1.0)) pattern_size = (5, 8) pattern_points = np.zeros( (np.prod(pattern_size), 3), np.float32 ) pattern_points[:,:2] = np.indices(pattern_size).T.reshape(-1, 2) pattern_points *= square_size obj_points = [] img_points = [] h, w = 0, 0 count = 0 for fn in img_names: print ''processing %s...'' % fn, img = cv2.imread(fn, 0) h, w = img.shape[:2] found, corners = cv2.findChessboardCorners(img, pattern_size) if found: if count == 0: #corners first is a list of the image points for just the first image. #This is the image I know the object points for and use in solvePnP corners_first = [] for val in corners: corners_first.append(val[0]) np_corners_first = np.asarray(corners_first,np.float64) count+=1 term = ( cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 30, 0.1 ) cv2.cornerSubPix(img, corners, (5, 5), (-1, -1), term) if debug_dir: vis = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) cv2.drawChessboardCorners(vis, pattern_size, corners, found) path, name, ext = splitfn(fn) cv2.imwrite(''%s/%s_chess.bmp'' % (debug_dir, name), vis) if not found: print ''chessboard not found'' continue img_points.append(corners.reshape(-1, 2)) obj_points.append(pattern_points) print ''ok'' rms, camera_matrix, dist_coefs, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, (w, h)) print "RMS:", rms print "camera matrix:/n", camera_matrix print "distortion coefficients: ", dist_coefs.ravel() cv2.destroyAllWindows() np_xyz = np.array(xyz,np.float64).T #xyz list is from file. Not shown here for brevity camera_matrix2 = np.asarray(camera_matrix,np.float64) np_dist_coefs = np.asarray(dist_coefs[:,:],np.float64) found,rvecs_new,tvecs_new = cv2.solvePnP(np_xyz, np_corners_first,camera_matrix2,np_dist_coefs) np_rodrigues = np.asarray(rvecs_new[:,:],np.float64) print np_rodrigues.shape rot_matrix = cv2.Rodrigues(np_rodrigues)[0] def rot_matrix_to_euler(R): y_rot = asin(R[2][0]) x_rot = acos(R[2][2]/cos(y_rot)) z_rot = acos(R[0][0]/cos(y_rot)) y_rot_angle = y_rot *(180/pi) x_rot_angle = x_rot *(180/pi) z_rot_angle = z_rot *(180/pi) return x_rot_angle,y_rot_angle,z_rot_angle print "Euler_rotation = ",rot_matrix_to_euler(rot_matrix) print "Translation_Matrix = ", tvecs_new

Muchas gracias


Creo que puedes estar pensando en tvecs_new como la posición de la cámara. ¡Ligeramente confuso ese no es el caso! De hecho, es la posición del origen mundial en cámaras de co-ords. Para obtener la posición de la cámara en las co-ords objeto / mundo, creo que necesitas hacer:

-np.matrix(rotation_matrix).T * np.matrix(tvecs_new)

Y puede obtener los ángulos de Euler utilizando cv2.decomposeProjectionMatrix(P)[-1] donde P es la matriz extrínseca [r|t] 3 por 4.

Descubrí que this es un muy buen artículo sobre los intrínsecos y los extrínsecos ...