2013-01-25 17 views
15

Próbuję przeprowadzić kalibrację i znaleźć lokalizację i obrót pojedynczej wirtualnej kamery w Blenderze 3d za pomocą homografii. Używam Blendera, aby móc dwukrotnie sprawdzić wyniki, zanim przejdę do prawdziwego świata, w którym jest to trudniejsze. Wykonałem dziesięć zdjęć szachownicy w różnych miejscach i obrotach w widoku mojej nieruchomej kamery. W pythonie opencv użyłem cv2.calibrateCamera, aby znaleźć wewnętrzną matrycę z wykrytych rogów szachownicy na dziesięciu obrazach, a następnie wykorzystałem to w cv2.solvePnP, aby znaleźć zewnętrzne parametry (translacja i obrót). Mimo że szacowane parametry były zbliżone do rzeczywistych, dzieje się coś podejrzanego. Moje wstępne oszacowanie tłumaczenia wyniosło (-0,11205481, -0,0490256,8.13892491). Rzeczywista lokalizacja była (0,0,8.07105). Całkiem blisko, prawda? Ale kiedy przeniosłem się i lekko obróciłem kamerę, a obrazy zostały ponownie zarchiwizowane, szacowane tłumaczenie stało się dalej. Szacowane: (-0,155933154,0.13367286,9.34058867). Rzeczywiste: (-1.7918, -1,51073,9.76597). Wartość Z jest blisko, ale X i Y nie są. Jestem całkowicie zdezorientowany. Jeśli ktokolwiek może mi pomóc rozwiązać ten problem, byłbym bardzo wdzięczny. Oto kod (jest oparty off python2 kalibracji przykład dostarczany z OpenCV):Python Opencv SolvePnP daje zły wektor translacji

#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 

Dziękuję bardzo

+0

Mam ten sam problem, używam innej metody chociaż. Mam nadzieję, że ktoś zna odpowiedź. http://stackoverflow.com/questions/14444433/calculate-camera-world-position-with-opencv-python –

+0

nie potrzebujesz własnej rot_matrix_to_euler, Rodrigues robi to za Ciebie – Hammer

+0

Cóż, b_m, wygląda na to, że jesteśmy w tej samej łodzi haha. Mam nadzieję, że ktoś będzie w stanie nam pomóc. Jak mogę uzyskać kąty Eulera bezpośrednio od Rodriguesa? Wektor obrotu 3x1 nie jest taki sam, jak kąty Eulera dla mnie. Czy moje dane wejściowe do solvePnP są poprawne? Czy w ten sposób używasz danych wyjściowych z calibratecamera? – amartin7211

Odpowiedz

20

myślę, że może być myślenie o tvecs_new jak położenie kamery. Nieco mylące, że tak nie jest! W rzeczywistości jest to pozycja świata w kamerze. Aby dostać aparat stanowią jednocześnie w Ords obiekt/świat, wierzę, trzeba zrobić:

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

I można uzyskać za pomocą kątów Eulera cv2.decomposeProjectionMatrix(P)[-1] gdzie P jest macierzą zewnętrzna [r|t] 3 przez 4.

znalazłem this się być całkiem dobry artykuł o intrinsics i extrinsics ...

+1

Wow! Działa jak marzenie! Dziękuję bardzo. Nie dotarłem jeszcze do tego artykułu (planuję), ale to z pewnością ustaliło wyniki. Jestem nieco zdezorientowany, co masz na myśli mówiąc "to jest pozycja pochodzenia świata w kamerze". Czy masz szansę na krótką analizę? Co to są kamery? Ponadto, kąty Eulera uzyskane z rozkładem odpowiadają moim obliczonym kątom Eulera (im będzie trzymać się kodu opencvs) – amartin7211

+1

@ user1713402 - Cool :)."Układ współrzędnych kamery" jest kartezjańskim układem współrzędnych, porusza się wraz z kamerą, a kamera zawsze jest na początku, oś Z jest kierunkiem widoku kamery, y jest obrazem w górę, a x jest do dobrze. Natomiast system współrzędnych świata jest statyczny, a kamera porusza się w nim. [Here] (http://stackoverflow.com/questions/695043/how-does-one-convert-world-coordinates-to-camera-coordinates) kolejne pytanie, które wyjaśnia to nieco więcej. – fraxel

+0

Świetnie! To ma sens! Jeszcze raz dziękuję – amartin7211