2013-01-25 2 views
15

Sto tentando di calibrare e trovare la posizione e la rotazione di una singola telecamera virtuale in Blender 3d usando l'omografia. Sto usando Blender in modo da poter ricontrollare i miei risultati prima di passare al mondo reale, dove è più difficile. Ho reso dieci immagini di una scacchiera in varie posizioni e rotazioni nella vista della mia macchina fotografica stazionaria. Con python di opencv, ho usato cv2.calibrateCamera per trovare la matrice intrinseca dagli angoli rilevati della scacchiera nelle dieci immagini e poi ho usato quello in cv2.solvePnP per trovare i parametri estrinseci (traslazione e rotazione). Tuttavia, sebbene i parametri stimati fossero vicini a quelli reali, c'è qualcosa di strano in corso. La mia stima iniziale della traduzione era (-0.11205481, -0.0490256,8.13892491). La posizione effettiva era (0,0,8.07105). Piuttosto vicino, vero? Ma quando ho spostato e ruotato leggermente la fotocamera e ho ridisegnato le immagini, la traduzione stimata è diventata più lontana. Stimato: (-0.15933154,0.13367286,9.34058867). Effettivo: (-1.7918, -1.51073,9.76597). Il valore Z è vicino, ma X e Y non lo sono. Sono completamente confuso. Se qualcuno mi può aiutare a risolvere questo, sarei molto grato. Ecco il codice (si basa off del python2 calibrare esempio fornito con OpenCV):Python Opencv SolvePnP produce un vettore di traduzione errato

#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 

Grazie mille

+0

Ho lo stesso problema, sto usando un metodo diverso però. Spero che qualcuno qui conosca la risposta. http://stackoverflow.com/questions/14444433/calculate-camera-world-position-with-opencv-python –

+0

non hai bisogno del tuo rot_matrix_to_euler, Rodrigues lo fa per te – Hammer

+0

Beh, b_m, poi sembra che siamo nella stessa barca haha. Speriamo che qualcuno possa aiutarci. Come ottengo direttamente gli angoli di Eulero da Rodrigues? Il vettore di rotazione 3x1 non è lo stesso degli angoli di Eulero per me. Inoltre, i miei input in solvePnP sono corretti? È così che usi l'output di calibratecamera? – amartin7211

risposta

20

Penso che si può pensare di tvecs_new come la posizione della telecamera. Un po 'confusionario non è il caso! In effetti è la posizione dell'origine mondiale nei co-ord della fotocamera. Per ottenere la fotocamera posa in co-ords oggetto/mondo, credo che devi fare:

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

e si può ottenere angoli di Eulero usando cv2.decomposeProjectionMatrix(P)[-1] dove P è la matrice estrinseca [r|t] 3 da 4.

ho trovato this di essere un buon articolo sui intrinseci ed estrinseci ...

+1

Wow! Funziona come un fascino! Grazie mille. Non ho ancora ricevuto l'articolo (ho intenzione di farlo), ma questo ha sicuramente risolto i risultati. Sono un po 'confuso cosa intendi per "è la posizione dell'origine del mondo nei co-ord". Qualche possibilità che potresti elaborare brevemente su questo? Cosa sono i coorti della fotocamera? Inoltre, gli angoli di Eulero ottenuti con la decomposizione corrispondono ai miei angoli euler calcolati (sto andando ad attaccare con il codice di opencvs però) – amartin7211

+1

@ user1713402 - Cool :).Il "sistema di coordinate della telecamera" è il sistema di coordinate cartesiane delle telecamere, si muove con la telecamera e la telecamera è sempre all'origine, l'asse z è la direzione della vista della telecamera, y è sopra l'immagine e x è verso la destra. Mentre il sistema di co-ord mondiale è statico e la telecamera si muove al suo interno. [Heres] (http://stackoverflow.com/questions/695043/how-does-one-convert-world-coordinates-to-camera-coordinates) un'altra domanda che lo spiega un po 'di più. – fraxel

+0

Ottimo! Ciò ha senso! Grazie ancora una volta – amartin7211