Go to the blender.org and download the latest version. Open the API reference for your version (as of 2015-01: 2.73).
Start blender from terminal and press Alt+F11
for
fullscreen. Press t
/n
for toggling the toolbar
left and the object properties bar right. Press Ctrl+RightArrow
until you arrive in the "Scripting" perspective.
In the Text view, open a new text block and type:
import time; ts = time.time()
import bpy
print("----\nHello world : %s" % (bpy.data.objects,))
print("This took %.4f seconds" % (time.time() - ts,))
Then press "Run Script" and look at the terminal you started
blender from. Next, back to blender and the Python console [docs]
(or for fun, press Shift+F4
over any window). Type bpy.
and press Ctrl+Space
for completion. Explore a bit, e.g.
to bpy.data.cameras[0].name
[api].
Also it seems somewhat intricate to show a popup dialog instead of
terminal messages (you would need to define an Operator
[docs],
the existing operators do not offer anything as far as I can see [api]).
There are two types of camera objects: One in the data camera list, and one in the scene object list.
camcount = len(bpy.data.cameras)
camdat = bpy.data.cameras[0]; assert camdat.type == 'PERSP'
camobj = bpy.context.scene.objects['Camera']; assert
camobj.type == 'CAMERA'
assert camobj.data == camdat
The scene object camera has an association to the data camera,
but not vice versa. The two cameras might not have the same name,
i.e. camdat.name != camobj.name
is well possible -- see
Object and Camera tab in the Properties view. So we can choose the
more convoluted way to get all cameras (in their two respective
incarnations dat
and obj
):
scene_camobj_list = [ob for ob in
list(bpy.context.scene.objects) if ob.type == 'CAMERA']
camdat_list = sorted(list(bpy.data.cameras), key=lambda
camdat: camdat.name)
camobj_list = [[ob for ob in scene_camobj_list if ob.data
== camdat][0] for camdat in camdat_list]
camidx = 0; camobj, camdat = camobj_list[camidx],
camdat_list[camidx]
We get the data cameras first, then the object cameras by
checking whether their data
entry is the data camera.
Next, we are interested in the project matrixes. The matrix_world
matrix is camera-to-world, not the other way round. So, in the VisualSFM/bundler sense, we need the
following:
RT = camobj.matrix_world.inverted()
RT = RT * Matrix(np.diag([1., 1., -1., 1.]))
sr = bpy.context.scene.render
img_wid_px = sr.resolution_x * sr.resolution_percentage/100.
img_hei_px = sr.resolution_y *
sr.resolution_percentage/100.
sensor_width_in_mm = camdat.sensor_width
focal_length_in_px = camdat.lens.real / sensor_width_in_mm *
img_wid_px
Extrinsic matrix (i.e. inverted position of the camera) comes from inverting the camera-to-world matrix. Since blender works with a RHS (right-hand side) coordinate system [wiki], we flip the z-axis to arrive at a LHS [coords]. Intrinsic matrix (i.e. focal length, same for x and y) requires knowledge about the rendered image pixel size as well as the virtual camera sensor.
As a side note for ground truth (GT) export: When you export
depth/motion, RenderLayer.Z
will contain the depth in
camera space, RenderLayer.Vector.Z
/W
the motion
to the next frame in camera space, and RenderLayer.Vector.X
/Y
the motion to the previous frame in camera space.
So if you want a (forward) scene flow in world coordinates, you need to project the camera space points at t=0 and t=1 into world space and the subtract them from each other.
u = Vector.Z * -1.
v = Vector.W * -1.
p_t0 = [xgrid, ygrid, Z0]
p_t1 = [xgrid+u, ygrid+v, Z1[xgrid+u, ygrid+v]]
Do a perspective multiplication and (K
*Rt
)-1p
[coords] and subtract them from
each other to get dU
, dV
, dW
in
world space. Note that the motion is given in reverse sign.
Before we write a script, we assume that you might have gotten one from someone and want to install it.
Press Ctrl+Alt+U
to open the user preferences. Choose
the "Add-Ons" tab and at the bottom, "Install from File". But
wait, you still need to allow it! If it not visible,
search for its name (fun game: find the minimal search string that
shows only your plugin) and enable the checkbox to the right. Then
at the bottom, press "Save User Settings". You are good to go.
When reloading, choose again "Install from File" and then disable and enable the checkbox. No need to press "Save User Settings", and you can as well leave the window open. Look at the terminal to see whether the reload happened.
That is slightly convoluted [docs], but the gist is: In your blender-plugin Python file, you first have to provide some metadata:
bl_info = {
"name": "RenderAllCameras",
"category": "Render",
}
Then you need to create a new operator class with more metadata:
class OBJECT_OT_RenderAllCamerasButton(
bl_idname =
"renderallcams.renderallcamerasbutton"
bl_label = "Render all Cameras"
Our new class needs at least an execute
method (the
context is mostly the same as bpy.context
, but can be
different for some special cases), which has to return either CANCELLED
or FINISHED
.
def execute(self, context):
print("Huhu, I was called")
return {'FINISHED'}
And finally, the script (not the class) needs methods ro register and unregister itself.
def register():
bpy.utils.register_class(
def unregister():
bpy.utils.unregister_class(
But really, the blender API/tutorials [docs] do a much better job than I could here. So go there, read some more blender/Python documentation, and have fun!
EOF (Jan:2015)