Python Opencv SolvePnP fournit un mauvais vecteur de traduction

j'essaie de calibrer et de trouver l'emplacement et la rotation d'une seule caméra virtuelle dans Blender 3d en utilisant l'homographie. J'utilise Blender pour pouvoir revérifier mes résultats avant de passer au monde réel où c'est plus difficile. J'ai fait dix photos d'un échiquier dans différents endroits et rotations dans la vue de mon appareil fixe. Avec le python d'opencv, j'ai utilisé cv2.calibrateCamera pour trouver la matrice intrinsèque à partir des coins détectés de l'échiquier les dix images et ensuite utilisé que dans cv2.solvePnP pour trouver les paramètres extrinsèques (translation et rotation). Toutefois, même si les paramètres estimés étaient proches des paramètres réels, il se passe quelque chose de louche. Mon estimation initiale de la traduction était (- 0.11205481, - 0.0490256, 8.13892491). L'emplacement réel était de (0,0,8.07105). Assez proche de la droite? Mais quand j'ai bougé et fait tourner légèrement la caméra et que j'ai relancé les images, la traduction estimée est devenue plus éloignée. Estimer: (-0.15933154,0.13367286,9.34058867). Effectif: (-1.7918,-1.51073,9.76597). La valeur Z est proche, mais le X et le Y ne le sont pas. Je suis complètement confus. Si quelqu'un peut m'aider à faire le tri dans cet, je serais très reconnaissant. Voici le code (il est basé sur l'exemple de calibrage python2 fourni avec 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

Merci beaucoup

16
demandé sur amartin7211 2013-01-25 08:11:00

1 réponses

je pense que vous pourriez penser à tvecs_new comme la position de la caméra. Légèrement de prêter à confusion, ce n'est pas le cas! En fait, sa position de l'origine mondiale dans la caméra co-ords. Pour obtenir la pose de la caméra dans les co-ords objet/monde, je crois que vous devez faire:

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

et vous pouvez obtenir les angles D'Euler en utilisant cv2.decomposeProjectionMatrix(P)[-1]P est le [r|t] 3 par 4 matrice extrinsèque.

j'ai trouvé this un bon article sur le intrinsèques et extrinsics...

20
répondu fraxel 2016-12-01 19:24:34