working render script ?
This commit is contained in:
parent
c4d9fcf3f7
commit
36fd4947a1
14
poetry.lock
generated
14
poetry.lock
generated
|
@ -125,6 +125,18 @@ files = [
|
||||||
{file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"},
|
{file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fake-bpy-module-latest"
|
||||||
|
version = "20230118"
|
||||||
|
description = "Collection of the fake Blender Python API module for the code completion."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "fake-bpy-module-latest-20230118.tar.gz", hash = "sha256:a3f45879347ef37b6fa5cd66ccc49634a14b420fa1b0fd196dfbf177d8602053"},
|
||||||
|
{file = "fake_bpy_module_latest-20230118-py3-none-any.whl", hash = "sha256:66d0b76ba65e01a91f74e77114705d744f3c2ad1078d060abf4a42c7fff9e79b"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "filelock"
|
name = "filelock"
|
||||||
version = "3.9.0"
|
version = "3.9.0"
|
||||||
|
@ -692,4 +704,4 @@ testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = ">=3.8.1,<4.0"
|
python-versions = ">=3.8.1,<4.0"
|
||||||
content-hash = "78e5e2403aaceb237ee187dd395971a4ee3a07af884a3d2be70e201a8285b2f4"
|
content-hash = "70277d35aa55c1022524e37b75fcd711637ee16fb1737bc157244cf83d57efff"
|
||||||
|
|
|
@ -10,6 +10,7 @@ numpy = "^1.23.5"
|
||||||
python = ">=3.8.1,<4.0"
|
python = ">=3.8.1,<4.0"
|
||||||
rich = "^12.6.0"
|
rich = "^12.6.0"
|
||||||
opencv-python = "^4.6.0.66"
|
opencv-python = "^4.6.0.66"
|
||||||
|
fake-bpy-module-latest = "^20230118"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
Flake8-pyproject = "^1.1.0"
|
Flake8-pyproject = "^1.1.0"
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
# https://blender.stackexchange.com/questions/38009/3x4-camera-matrix-from-blender-camera
|
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from mathutils import Matrix
|
from mathutils import Matrix
|
||||||
import pickle
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
# 3x4 P matrix from Blender camera
|
# 3x4 P matrix from Blender camera
|
||||||
|
@ -27,7 +22,7 @@ def get_sensor_fit(sensor_fit, size_x, size_y):
|
||||||
|
|
||||||
# Build intrinsic camera parameters from Blender camera data
|
# Build intrinsic camera parameters from Blender camera data
|
||||||
#
|
#
|
||||||
# See notes on this in
|
# See notes on this in
|
||||||
# blender.stackexchange.com/questions/15102/what-is-blenders-camera-projection-matrix-model
|
# blender.stackexchange.com/questions/15102/what-is-blenders-camera-projection-matrix-model
|
||||||
# as well as
|
# as well as
|
||||||
# https://blender.stackexchange.com/a/120063/3581
|
# https://blender.stackexchange.com/a/120063/3581
|
||||||
|
@ -66,7 +61,7 @@ def get_calibration_matrix_K_from_blender(camd):
|
||||||
return K
|
return K
|
||||||
|
|
||||||
# Returns camera rotation and translation matrices from Blender.
|
# Returns camera rotation and translation matrices from Blender.
|
||||||
#
|
#
|
||||||
# There are 3 coordinate systems involved:
|
# There are 3 coordinate systems involved:
|
||||||
# 1. The World coordinates: "world"
|
# 1. The World coordinates: "world"
|
||||||
# - right-handed
|
# - right-handed
|
||||||
|
@ -76,7 +71,7 @@ def get_calibration_matrix_K_from_blender(camd):
|
||||||
# - right-handed: negative z look-at direction
|
# - right-handed: negative z look-at direction
|
||||||
# 3. The desired computer vision camera coordinates: "cv"
|
# 3. The desired computer vision camera coordinates: "cv"
|
||||||
# - x is horizontal
|
# - x is horizontal
|
||||||
# - y is down (to align to the actual pixel coordinates
|
# - y is down (to align to the actual pixel coordinates
|
||||||
# used in digital images)
|
# used in digital images)
|
||||||
# - right-handed: positive z look-at direction
|
# - right-handed: positive z look-at direction
|
||||||
def get_3x4_RT_matrix_from_blender(cam):
|
def get_3x4_RT_matrix_from_blender(cam):
|
||||||
|
@ -86,7 +81,7 @@ def get_3x4_RT_matrix_from_blender(cam):
|
||||||
(0, -1, 0),
|
(0, -1, 0),
|
||||||
(0, 0, -1)))
|
(0, 0, -1)))
|
||||||
|
|
||||||
# Transpose since the rotation is object rotation,
|
# Transpose since the rotation is object rotation,
|
||||||
# and we want coordinate rotation
|
# and we want coordinate rotation
|
||||||
# R_world2bcam = cam.rotation_euler.to_matrix().transposed()
|
# R_world2bcam = cam.rotation_euler.to_matrix().transposed()
|
||||||
# T_world2bcam = -1*R_world2bcam @ location
|
# T_world2bcam = -1*R_world2bcam @ location
|
||||||
|
@ -97,7 +92,7 @@ def get_3x4_RT_matrix_from_blender(cam):
|
||||||
|
|
||||||
# Convert camera location to translation vector used in coordinate changes
|
# Convert camera location to translation vector used in coordinate changes
|
||||||
# T_world2bcam = -1*R_world2bcam @ cam.location
|
# T_world2bcam = -1*R_world2bcam @ cam.location
|
||||||
# Use location from matrix_world to account for constraints:
|
# Use location from matrix_world to account for constraints:
|
||||||
T_world2bcam = -1*R_world2bcam @ location
|
T_world2bcam = -1*R_world2bcam @ location
|
||||||
|
|
||||||
# Build the coordinate transform matrix from world to computer vision camera
|
# Build the coordinate transform matrix from world to computer vision camera
|
||||||
|
@ -117,28 +112,25 @@ def get_3x4_P_matrix_from_blender(cam):
|
||||||
RT = get_3x4_RT_matrix_from_blender(cam)
|
RT = get_3x4_RT_matrix_from_blender(cam)
|
||||||
return K@RT, K, RT
|
return K@RT, K, RT
|
||||||
|
|
||||||
def run_script(scene):
|
# ----------------------------------------------------------
|
||||||
with open(PICKLE_PATH, 'rb') as file:
|
if __name__ == "__main__":
|
||||||
matrices = pickle.load(file)
|
# Insert your camera name here
|
||||||
|
cam = bpy.data.objects['Camera']
|
||||||
|
P, K, RT = get_3x4_P_matrix_from_blender(cam)
|
||||||
|
print("K")
|
||||||
|
print(K)
|
||||||
|
print("RT")
|
||||||
|
print(RT)
|
||||||
|
print("P")
|
||||||
|
print(P)
|
||||||
|
|
||||||
projection_matrix, _, _ = get_3x4_P_matrix_from_blender(scene.camera)
|
print("==== 3D Cursor projection ====")
|
||||||
matrices.append(np.array(projection_matrix))
|
pc = P @ bpy.context.scene.cursor.location
|
||||||
|
pc /= pc[2]
|
||||||
with open(PICKLE_PATH, 'wb') as file:
|
print("Projected cursor location")
|
||||||
pickle.dump(matrices, file)
|
print(pc)
|
||||||
|
|
||||||
def setup_script(scene):
|
# Bonus code: save the 3x4 P matrix into a plain text file
|
||||||
matrices = []
|
# Don't forget to import numpy for this
|
||||||
with open(PICKLE_PATH, 'wb') as file:
|
#nP = numpy.matrix(P)
|
||||||
pickle.dump(matrices, file)
|
#numpy.savetxt("/tmp/P3x4.txt", nP) # to select precision, use e.g. fmt='%.2f'
|
||||||
|
|
||||||
PICKLE_PATH = "/tmp/pickle.truc"
|
|
||||||
|
|
||||||
# clear handlers
|
|
||||||
bpy.app.handlers.render_init.clear()
|
|
||||||
bpy.app.handlers.frame_change_pre.clear()
|
|
||||||
bpy.app.handlers.frame_change_post.clear()
|
|
||||||
|
|
||||||
# add handler
|
|
||||||
bpy.app.handlers.render_init.append(setup_script)
|
|
||||||
bpy.app.handlers.frame_change_post.append(run_script)
|
|
67
src/blender/render.py
Normal file
67
src/blender/render.py
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import bpy
|
||||||
|
import math
|
||||||
|
import itertools
|
||||||
|
import pathlib
|
||||||
|
import pickle
|
||||||
|
import sys
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
# dirty hack to import proj.py
|
||||||
|
dir = pathlib.Path(bpy.data.filepath).parent
|
||||||
|
dir = dir / "src" / "blender"
|
||||||
|
sys.path.append(str(dir))
|
||||||
|
|
||||||
|
from proj import get_3x4_P_matrix_from_blender
|
||||||
|
|
||||||
|
# setup output path
|
||||||
|
EXPORT_PATH = pathlib.Path("/tmp/")
|
||||||
|
|
||||||
|
# setup camera poses
|
||||||
|
phis = [-45, 0, 45]
|
||||||
|
thetas = [0, 45, 90, 135, 180, 225, 270, 315]
|
||||||
|
|
||||||
|
# convert to radians
|
||||||
|
phis = [math.radians(phi) for phi in phis]
|
||||||
|
thetas = [math.radians(theta) for theta in thetas]
|
||||||
|
|
||||||
|
# create all possible combinations
|
||||||
|
poses = list(itertools.product(phis, thetas))
|
||||||
|
|
||||||
|
# create export folders
|
||||||
|
pathlib.Path(EXPORT_PATH / "images").mkdir(parents=True, exist_ok=True)
|
||||||
|
pathlib.Path(EXPORT_PATH / "masks").mkdir(parents=True, exist_ok=True)
|
||||||
|
pathlib.Path(EXPORT_PATH / "cameras").mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# set "File Output" nodes' "Base Path" property
|
||||||
|
bpy.data.scenes["Scene"].node_tree.nodes["Image Output"].base_path = str(EXPORT_PATH / "images")
|
||||||
|
bpy.data.scenes["Scene"].node_tree.nodes["Mask Output"].base_path = str(EXPORT_PATH / "masks")
|
||||||
|
|
||||||
|
# get camera
|
||||||
|
cam = bpy.data.objects["Camera"]
|
||||||
|
|
||||||
|
for i, (phi, theta) in enumerate(poses):
|
||||||
|
print(f"Rendering pose {i}...")
|
||||||
|
|
||||||
|
# set camera pose
|
||||||
|
bpy.context.scene.objects["Empty"].rotation_euler[0] = phi
|
||||||
|
bpy.context.scene.objects["Empty"].rotation_euler[2] = theta
|
||||||
|
|
||||||
|
# get camera matrices
|
||||||
|
P, K, RT = get_3x4_P_matrix_from_blender(cam)
|
||||||
|
|
||||||
|
# save camera matrices
|
||||||
|
with open(EXPORT_PATH / "cameras" / f"{i:04d}.pickle", "wb") as f:
|
||||||
|
pickle.dump({
|
||||||
|
"P": np.array(P),
|
||||||
|
"K": np.array(K),
|
||||||
|
"RT": np.array(RT),
|
||||||
|
}, f)
|
||||||
|
print(f"Saved camera matrices: {i:04d}.pickle")
|
||||||
|
|
||||||
|
|
||||||
|
# set frame number
|
||||||
|
bpy.context.scene.frame_current = i
|
||||||
|
|
||||||
|
# render the frame
|
||||||
|
bpy.ops.render.render(write_still=False)
|
||||||
|
|
BIN
torus.blend
BIN
torus.blend
Binary file not shown.
Loading…
Reference in a new issue