Last active
August 12, 2024 10:57
-
-
Save autosquid/8e1cddbc0336a49c6f84591d35371c4d to your computer and use it in GitHub Desktop.
blender-camera-from-3x4-matrix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# from: http://blender.stackexchange.com/questions/40650/blender-camera-from-3x4-matrix?rq=1 | |
# And: http://blender.stackexchange.com/questions/38009/3x4-camera-matrix-from-blender-camera | |
# Input: P 3x4 numpy matrix | |
# Output: K, R, T such that P = K*[R | T], det(R) positive and K has positive diagonal | |
# | |
# Reference implementations: | |
# - Oxford's visual geometry group matlab toolbox | |
# - Scilab Image Processing toolbox | |
def KRT_from_P(P): | |
N = 3 | |
H = P[:,0:N] # if not numpy, H = P.to_3x3() | |
[K,R] = rf_rq(H) | |
K /= K[-1,-1] | |
# from http://ksimek.github.io/2012/08/14/decompose/ | |
# make the diagonal of K positive | |
sg = numpy.diag(numpy.sign(numpy.diag(K))) | |
K = K * sg | |
R = sg * R | |
# det(R) negative, just invert; the proj equation remains same: | |
if (numpy.linalg.det(R) < 0): | |
R = -R | |
# C = -H\P[:,-1] | |
C = numpy.linalg.lstsq(-H, P[:,-1])[0] | |
T = -R*C | |
return K, R, T | |
# RQ decomposition of a numpy matrix, using only libs that already come with | |
# blender by default | |
# | |
# Author: Ricardo Fabbri | |
# Reference implementations: | |
# Oxford's visual geometry group matlab toolbox | |
# Scilab Image Processing toolbox | |
# | |
# Input: 3x4 numpy matrix P | |
# Returns: numpy matrices r,q | |
def rf_rq(P): | |
P = P.T | |
# numpy only provides qr. Scipy has rq but doesn't ship with blender | |
q, r = numpy.linalg.qr(P[ ::-1, ::-1], 'complete') | |
q = q.T | |
q = q[ ::-1, ::-1] | |
r = r.T | |
r = r[ ::-1, ::-1] | |
if (numpy.linalg.det(q) < 0): | |
r[:,0] *= -1 | |
q[0,:] *= -1 | |
return r, q | |
# Creates a blender camera consistent with a given 3x4 computer vision P matrix | |
# Run this in Object Mode | |
# scale: resolution scale percentage as in GUI, known a priori | |
# P: numpy 3x4 | |
def get_blender_camera_from_3x4_P(P, scale): | |
# get krt | |
K, R_world2cv, T_world2cv = KRT_from_P(numpy.matrix(P)) | |
scene = bpy.context.scene | |
sensor_width_in_mm = K[1,1]*K[0,2] / (K[0,0]*K[1,2]) | |
sensor_height_in_mm = 1 # doesn't matter | |
resolution_x_in_px = K[0,2]*2 # principal point assumed at the center | |
resolution_y_in_px = K[1,2]*2 # principal point assumed at the center | |
s_u = resolution_x_in_px / sensor_width_in_mm | |
s_v = resolution_y_in_px / sensor_height_in_mm | |
# TODO include aspect ratio | |
f_in_mm = K[0,0] / s_u | |
# recover original resolution | |
scene.render.resolution_x = resolution_x_in_px / scale | |
scene.render.resolution_y = resolution_y_in_px / scale | |
scene.render.resolution_percentage = scale * 100 | |
# Use this if the projection matrix follows the convention listed in my answer to | |
# http://blender.stackexchange.com/questions/38009/3x4-camera-matrix-from-blender-camera | |
R_bcam2cv = Matrix( | |
((1, 0, 0), | |
(0, -1, 0), | |
(0, 0, -1))) | |
# Use this if the projection matrix follows the convention from e.g. the matlab calibration toolbox: | |
# R_bcam2cv = Matrix( | |
# ((-1, 0, 0), | |
# (0, 1, 0), | |
# (0, 0, 1))) | |
R_cv2world = R_world2cv.T | |
rotation = Matrix(R_cv2world.tolist()) * R_bcam2cv | |
location = -R_cv2world * T_world2cv | |
# create a new camera | |
bpy.ops.object.add( | |
type='CAMERA', | |
location=location) | |
ob = bpy.context.object | |
ob.name = 'CamFrom3x4PObj' | |
cam = ob.data | |
cam.name = 'CamFrom3x4P' | |
# Lens | |
cam.type = 'PERSP' | |
cam.lens = f_in_mm | |
cam.lens_unit = 'MILLIMETERS' | |
cam.sensor_width = sensor_width_in_mm | |
ob.matrix_world = Matrix.Translation(location)*rotation.to_4x4() | |
# cam.shift_x = -0.05 | |
# cam.shift_y = 0.1 | |
# cam.clip_start = 10.0 | |
# cam.clip_end = 250.0 | |
# empty = bpy.data.objects.new('DofEmpty', None) | |
# empty.location = origin+Vector((0,10,0)) | |
# cam.dof_object = empty | |
# Display | |
cam.show_name = True | |
# Make this the current camera | |
scene.camera = ob | |
bpy.context.scene.update() | |
def test2(): | |
P = Matrix([ | |
[2. , 0. , - 10. , 282. ], | |
[0. ,- 3. , - 14. , 417. ], | |
[0. , 0. , - 1. , - 18. ] | |
]) | |
# This test P was constructed as k*[r | t] where | |
# k = [2 0 10; 0 3 14; 0 0 1] | |
# r = [1 0 0; 0 -1 0; 0 0 -1] | |
# t = [231 223 -18] | |
# k, r, t = KRT_from_P(numpy.matrix(P)) | |
get_blender_camera_from_3x4_P(P, 1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment