В матрице A у вас есть два уравнения, которые может дать 3D-точка (умноженные на число точек):
Поскольку у нас есть uZ -uoZ -px =0 и vZ -v0Z - py=0
Тогда у нас есть A*X=0 где X представляет собой неизвестно, а A представляет наблюдаемые.
Чтобы решить X, в идеальном сценарии мы должны выполнить разложение по сингулярным значениям (SVD) A. X связан с наименьшим значением в D.
Однако есть проблема: X = 0 — допустимое решение! Поэтому я думаю, что СВД дает именно такое решение, а не то, которое мы ищем. Я не уверен, есть ли проблема в моем коде или это просто «нормально».
objpoints находится в опорном кадре шахматной доски, а imgpoints — в опорном кадре камеры. (они рассчитаны ниже)
Код: Выделить всё
A = []
for i in range(len(objpoints)):
X, Y, Z = objpoints[i]
u, v = imgpoints[i][0]
row1 = [u*X, u*Y, u*Z, -X, -Y, -Z, 0, 0, 0, -1, 0, u]
row2 = [v*X, v*Y, v*Z, 0, 0, 0, -X, -Y, -Z, 0, -1, v]
A.append(row1)
A.append(row2)
A = np.array(A)
# Solve the homogeneous system using SVD
_, _, V = np.linalg.svd(A)
X = V[:, -1]
print("Estimated Camera Parameters:", X)
print("uo:",X[0]*X[3]+X[1]*X[4]+X[2]*X[6])
На этот раз мы не решаем AX, потому что 0 может быть решением.
Вместо этого мы пытаемся минимизировать следующую функцию стоимости C=||A
Код: Выделить всё
X1 + B*X2||Код: Выделить всё
2 + (1-X1)При таком подходе проблема была декомпозирована.
Код: Выделить всё
A= [[uКод: Выделить всё
X, uКод: Выделить всё
Y, uКод: Выделить всё
Z]**,[vКод: Выделить всё
X, vКод: Выделить всё
Y, vКод: Выделить всё
Z]]Код: Выделить всё
X1Код: Выделить всё
=[X1,X2,X3]Код: Выделить всё
B=[[-X, -Y, -Z, 0, 0, 0, -1, 0, u],[ 0, 0, 0, -X, -Y, -Z, 0, -1, v]]Код: Выделить всё
X2Код: Выделить всё
=[X4,..,X12]Дифференцируя C, мы можем получить **решение ** проблемы.
Производная
и затем :
Решение
Как видите, нам нужно вычислить обратную величину B.T @ B, чтобы получить некоторые параметры ( не все!).
Однако я есть БОЛЬШАЯ проблема: BT @ B должен быть обратимым. Когда я смотрю на этот метод, мне кажется, что нет причин, по которым этого не должно быть! Между строками и столбцами нет явной зависимости!
Однако в написанном мною коде (который вы можете найти ниже) я получаю** ошибку о том, что матрица сингулярна** . Я всмотрелся, и действительно, матрица 9х9 не полного ранга (8-го ранга, если быть точным). Это делает невозможным вычисление X1 и X2. Я не уверен, допустил ли я ошибку в своих расчетах, обработке матрицы или этот метод просто предназначен для использования в определенном контексте. Сейчас я пытаюсь заставить его работать на изображении шахматной доски из руководства по калибровке OpenCV.
Вот код, о котором идет речь. Должно отображаться:
Код: Выделить всё
Cx= X[0]*X[3]+X[1]*X[4]+X[2]*X[6]Код: Выделить всё
import numpy as np
import cv2
import glob
CHECKERBOARD = (6, 9)
square_size = 3
def calibration(CHECKERBOARD,square_size):
objp = np.zeros((CHECKERBOARD[0] * CHECKERBOARD[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2) * square_size
objpoints = []
imgpoints = []
images = glob.glob('Folder/*.jpg')
#Only for one image. I have to remove the loop
for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, corners = cv2.findChessboardCorners(gray, CHECKERBOARD, cv2.CALIB_CB_ADAPTIVE_THRESH + cv2.CALIB_CB_FAST_CHECK + cv2.CALIB_CB_NORMALIZE_IMAGE)
if ret:
objpoints=objp
imgpoints=corners
cv2.drawChessboardCorners(img, CHECKERBOARD, corners, ret)
cv2.imshow('Image', img)
cv2.waitKey()
else:
print(ret)
cv2.destroyAllWindows()
A = np.zeros((CHECKERBOARD[0] * CHECKERBOARD[1] * 2, 3), np.float32)
B = np.zeros((CHECKERBOARD[0] * CHECKERBOARD[1] * 2, 9), np.float32)
#Algo 1: using Toscani Faugeras approach
for i in range (CHECKERBOARD[0] * CHECKERBOARD[1]):
X,Y,Z= objpoints[i]
u,v=imgpoints[i][0]
A[2*i][0]=u*X
A[2*i][1]=u*Y
A[2*i][2]=u*Z
A[2*i+1][0]=v*X
A[2*i+1][1]=v*Y
A[2*i+1][2]=v*Z
B[2*i][0]=-X
B[2*i][1]=-Y
B[2*i][2]=-Z
#B[2*i][3]=0
#B[2*i][4]=0
#B[2*i][5]=0
B[2*i][6]=-1
B[2*i][7]=0
B[2*i][8]=u
#B[2*i+1][0]=0
#B[2*i+1][1]=0
#B[2*i+1][2]=0
B[2*i+1][3]=-X
B[2*i+1][4]=-Y
B[2*i+1][5]=-Z
B[2*i+1][6]=0
B[2*i+1][7]=-1
B[2*i+1][8]=v
print(B) #Is there a problem?
E = A.T @ A - A.T @ B @ np.linalg.inv(B.T @ B) @ B.T @ A
eigenvalues, eigenvectors = np.linalg.eig(E)
X1 = eigenvectors[:, np.argmin(eigenvalues)]
X2 = -np.linalg.pinv(B.T @ B) @ B.T @ A @ X1
print("X1",X1,"X2",X2)
#print([i for i in range (9) if ((B.T @ B)[i,i]==0)] ) #2 erreurs
#print(np.linalg.matrix_rank((B.T @ B)))
print(X[0]*X[3]+X[1]*X[4]+X[2]*X[6])
calibration(CHECKERBOARD,square_size)
Если кто-то увидит проблему в коде или подходе, спасибо! Я знаю, что это не лучший метод, но я хотел попробовать его и сравнить результаты с функциями OpenCV.
Подробнее здесь: https://stackoverflow.com/questions/792 ... geras-work
Мобильная версия