-
-
Save wangg12/ed7293dd7e7da1a09fb46e2840450d3b to your computer and use it in GitHub Desktop.
blender-camera-from-3x4-matrix
This file contains hidden or 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