OpenCV: получить перспективную матрицу от перевода и вращения
Я пытаюсь проверить калибровку камеры, поэтому я хотел бы исправить калибровочные изображения. Я ожидаю, что это будет связано с использованием вызова warpPerspective
, но я не вижу очевидной функции, которая принимает матрицу камеры, а векторы вращения и перевода для генерации матрицы перспективы для этого вызова.
По сути, я хочу сделать описанный процесс здесь (см., в частности, изображения к концу), но начиная с известной модели камеры и позиционирования.
Есть ли прямой вызов функции, который принимает внутренние и внешние параметры камеры и вычисляет перспективную матрицу для использования в warpPerspective
?
Я вызываю warpPerspective
после вызова undistort
на изображении.
В принципе, я мог бы найти решение, решая систему уравнений, определенную в верхней части документации по калибровке камеры opencv после указания ограничения Z=0
, но Я полагаю, что должна быть законченная программа, которая позволит мне ортотрансформировать мои тестовые изображения.
В моих поисках мне сложно пройти через все результаты стереокалибровки - у меня есть только одна камера, но вы хотите исправить изображение под ограничением, что я только смотрю план плана.
Ответы
Ответ 1
На самом деле нет необходимости привлекать орфографическую камеру. Вот как вы можете получить соответствующее преобразование перспективы.
Если вы откалибровали камеру с помощью cv::calibrateCamera
, вы получили матрицу камеры K
вектор коэффициентов искажения объектива D
для вашей камеры и для каждого используемого изображения вектор вращения rvec
(который вы можете преобразовать в матрицу 3x3 R
с помощью cv::rodrigues
, doc) и вектора перевода T
. Рассмотрим одно из этих изображений и связанные с ним R
и T
. После того, как вы вызвали cv::undistort
с использованием коэффициентов искажения, изображение будет похоже на то, что оно было получено камерой матрицы проецирования K * [ R | T ]
.
В принципе (как @DavidNilosek интуитивно) вы хотите отменить поворот и получить изображение, как если бы оно было получено матрицей проекции формы K * [ I | -C ]
, где C=-R.inv()*T
- позиция камеры. Для этого вам необходимо применить следующее преобразование:
Hr = K * R.inv() * K.inv()
Единственная потенциальная проблема заключается в том, что искаженное изображение может выйти за пределы видимой части плоскости изображения. Следовательно, вы можете использовать дополнительный перевод для решения этой проблемы следующим образом:
[ 1 0 | ]
Ht = [ 0 1 | -K*C/Cz ]
[ 0 0 | ]
где Cz - компонента C вдоль оси Oz.
Наконец, с приведенными выше определениями, H = Ht * Hr
является выпрямляющим преобразованием перспективы для рассматриваемого изображения.
Ответ 2
Это набросок того, что я подразумеваю под "решением системы уравнений" (на Python):
import cv2
import scipy # I use scipy by habit; numpy would be fine too
#rvec= the rotation vector
#tvec = the translation *emphasized text*matrix
#A = the camera intrinsic
def unit_vector(v):
return v/scipy.sqrt(scipy.sum(v*v))
(fx,fy)=(A[0,0], A[1,1])
Ainv=scipy.array( [ [1.0/fx, 0.0, -A[0,2]/fx],
[ 0.0, 1.0/fy, -A[1,2]/fy],
[ 0.0, 0.0, 1.0] ], dtype=scipy.float32 )
R=cv2.Rodrigues( rvec )
Rinv=scipy.transpose( R )
u=scipy.dot( Rinv, tvec ) # displacement between camera and world coordinate origin, in world coordinates
# corners of the image, for here hard coded
pixel_corners=[ scipy.array( c, dtype=scipy.float32 ) for c in [ (0+0.5,0+0.5,1), (0+0.5,640-0.5,1), (480-0.5,640-0.5,1), (480-0.5,0+0.5,1)] ]
scene_corners=[]
for c in pixel_corners:
lhat=scipy.dot( Rinv, scipy.dot( Ainv, c) ) #direction of the ray that the corner images, in world coordinates
s=u[2]/lhat[2]
# now we have the case that (s*lhat-u)[2]==0,
# i.e. s is how far along the line of sight that we need
# to move to get to the Z==0 plane.
g=s*lhat-u
scene_corners.append( (g[0], g[1]) )
# now we have: 4 pixel_corners (image coordinates), and 4 corresponding scene_coordinates
# can call cv2.getPerspectiveTransform on them and so on..