Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
get_camera_pose_teabox.py
1import bpy
2import os
3from mathutils import Matrix
4import sys
5
6def save_depth_M_color_file(prefix_data, scene, camera_name_color, camera_name_depth):
7 """! Save depth_M_color.txt file.
8 @param[in] prefix_data String corresponding to the folder where depth_M_color.txt file has to be saved.
9 @param[in] scene Scene handler.
10 @param[in] camera_name_color String corresponding to the name of the color camera to consider.
11 @param[in] camera_name_depth String corresponding to the name of the depth camera to consider.
12 """
13
14 w_M_c = get_object_pose_in_world(camera_name_color)
15 w_M_d = get_object_pose_in_world(camera_name_depth)
16 d_M_c = w_M_d.inverted() @ w_M_c
17 #print("d_M_c: \n", d_M_c)
18
19 filename = prefix_data + "depth_M_color.txt"
20 save_pose(filename, d_M_c)
21 print(f"Saved: {filename}")
22
23def get_object_pose_in_world(object_name):
24 """! Return the object pose in the world frame w_M_o.
25 @param[in] object_name String corresponding to the name of the object to consider.
26 @return The 4-by-4 homogeneous matrix corresponding to w_M_object.
27 """
28 w_M_object = bpy.data.objects[object_name].matrix_world
29 w_M_object_normalized = w_M_object.copy()
30 w_R_object_normalized = w_M_object_normalized.to_3x3().normalized()
31 for i in range(3):
32 for j in range(3):
33 w_M_object_normalized[i][j] = w_R_object_normalized[i][j]
34 return w_M_object_normalized
35
36def get_camera_pose(camera_name, object_name):
37 """! Return the object pose in the camera frame as an homogenous matrices.
38 @param[in] camera_name String corresponding to the name of the camera to consider.
39 @param[in] object_name String corresponding to the name of the object to consider.
40 @return The 4-by-4 homogeneous matrix corresponding to c_M_o.
41 """
42
43 # OpenGL to Computer vision camera frame convention
44 M = Matrix().to_4x4()
45 M[1][1] = -1
46 M[2][2] = -1
47
48 #print("M: \n", M)
49
50 w_M_c = get_object_pose_in_world(camera_name)
51 w_M_o = get_object_pose_in_world(object_name)
52
53 #print("w_M_c: \n", w_M_c)
54 #print("w_M_o: \n", w_M_o)
55
56 c_M_o = M @ w_M_c.inverted() @ w_M_o
57
58 #print("c_M_o:\n", c_M_o)
59 return c_M_o
60
61def save_pose(filename, pose):
62 """! Save pose in a .txt file.
63 @param[in] filename String corresponding to the file name that will contain the saved pose.
64 @param[in] pose Object pose to save as a 4-by-4 homogeneous matrix.
65 """
66
67 print(f"Save: {filename}")
68 with open(filename, 'w') as f:
69 f.write(str(pose[0][0]) + " ")
70 f.write(str(pose[0][1]) + " ")
71 f.write(str(pose[0][2]) + " ")
72 f.write(str(pose[0][3]) + " ")
73 f.write("\n")
74
75 f.write(str(pose[1][0]) + " ")
76 f.write(str(pose[1][1]) + " ")
77 f.write(str(pose[1][2]) + " ")
78 f.write(str(pose[1][3]) + " ")
79 f.write("\n")
80
81 f.write(str(pose[2][0]) + " ")
82 f.write(str(pose[2][1]) + " ")
83 f.write(str(pose[2][2]) + " ")
84 f.write(str(pose[2][3]) + " ")
85 f.write("\n")
86
87 f.write(str(pose[3][0]) + " ")
88 f.write(str(pose[3][1]) + " ")
89 f.write(str(pose[3][2]) + " ")
90 f.write(str(pose[3][3]) + " ")
91 f.write("\n")
92
93 return
94
95def save_color_camera_pose(prefix, scene, camera_name, object_name):
96 """! Save homogeneous transformation from camera to object frames (cMo).
97 @param[in] prefix String corresponding to the folder name that will contain the saved poses.
98 @param[in] scene Scene handler.
99 @param[in] camera_name String corresponding to the name of the camera to consider.
100 @param[in] object_name String corresponding to the name of the object to track.
101 """
102 frame_number = scene.frame_current
103 print("\n\nCurrent Frame", scene.frame_current)
104 camera_pose = get_camera_pose(camera_name, object_name)
105
106 filename = prefix + camera_name_color + "_%04d" % frame_number + ".txt"
107 save_pose(filename, camera_pose)
108
109def get_intrinsics(camera_name):
110 """! Save camera intrinsics in xml.
111 @param[in] camera_name String corresponding to the name of the camera to consider.
112 """
113 cam_data = bpy.data.objects[camera_name].data
114 f = cam_data.lens
115 scene = bpy.context.scene
116 resolution_x_in_px = scene.render.resolution_x
117 resolution_y_in_px = scene.render.resolution_y
118 scale = scene.render.resolution_percentage / 100
119 sensor_width = cam_data.sensor_width
120 sensor_height = cam_data.sensor_height
121 pixel_aspect_ratio = scene.render.pixel_aspect_x / scene.render.pixel_aspect_y
122 if (cam_data.sensor_fit == 'VERTICAL'):
123 # the sensor height is fixed (sensor fit is horizontal),
124 # the sensor width is effectively changed with the pixel aspect ratio
125 s_u = resolution_x_in_px * scale / sensor_width / pixel_aspect_ratio
126 s_v = resolution_y_in_px * scale / sensor_height
127 else: # 'HORIZONTAL' and 'AUTO'
128 # the sensor width is fixed (sensor fit is horizontal),
129 # the sensor height is effectively changed with the pixel aspect ratio
130 pixel_aspect_ratio = scene.render.pixel_aspect_x / scene.render.pixel_aspect_y
131 s_u = resolution_x_in_px * scale / sensor_width
132 s_v = resolution_y_in_px * scale * pixel_aspect_ratio / sensor_height
133
134 # Parameters of intrinsic calibration matrix K
135 w = resolution_x_in_px
136 h = resolution_y_in_px
137 p_x = f * s_u
138 p_y = f * s_v
139 u_0 = resolution_x_in_px*scale / 2
140 v_0 = resolution_y_in_px*scale / 2
141
142 return w, h, p_x, p_y, u_0, v_0
143
144def save_intrinsics(filename, camera_name, w, h, p_x, p_y, u_0, v_0):
145 """! Save camera intrinsics in xml.
146 @param[in] filename Name of the file that will contain the intrinsics in xml format.
147 @param[in] camera_name Camera name.
148 @param[in] w, h Image size.
149 @param[in] p_x, p_y Ratio between the focal length and the size of the pixel.
150 @param[in] u_0, v_0 Coordinates of the principal point.
151 """
152 print(f"Save: {filename}")
153 with open(filename, 'w') as f:
154 f.write("<?xml version=\"1.0\"?>\n")
155 f.write("<root>\n")
156 f.write(" <camera>\n")
157 f.write(f" <name>{camera_name}</name>\n")
158 f.write(f" <image_width>{w}</image_width>\n")
159 f.write(f" <image_height>{h}</image_height>\n")
160 f.write(" <model>\n")
161 f.write(" <type>perspectiveProjWithoutDistortion</type>\n")
162 f.write(f" <px>{p_x}</px>\n")
163 f.write(f" <py>{p_y}</py>\n")
164 f.write(f" <u0>{u_0}</u0>\n")
165 f.write(f" <v0>{v_0}</v0>\n")
166 f.write(" </model>\n")
167 f.write(" </camera>\n")
168 f.write("</root>\n")
169 f.write("\n")
170
171if __name__ == '__main__':
172 """! Python script that save camera poses, color and depth images, but also depth to color transform.
173 """
174 camera_name_color = "Camera_L"
175 camera_name_depth = "Camera_R"
176 object_name = "teabox"
177 prefix_data = "/tmp/teabox/"
178 prefix_pose = prefix_data + "ground-truth/"
179 prefix_color_images = prefix_data + "color/"
180 prefix_depth_images = prefix_data + "depth/"
181 images_suffix = "JPEG"
182
183 if not os.path.exists(prefix_data):
184 print(f"Create {prefix_data}")
185 os.makedirs(prefix_data)
186
187 if not os.path.exists(prefix_pose):
188 print(f"Create {prefix_pose}")
189 os.makedirs(prefix_pose)
190
191 scene = bpy.context.scene
192
193 save_depth_M_color_file(prefix_data, scene, camera_name_color, camera_name_depth)
194
195 color_w, color_h, color_p_x, color_p_y, color_u_0, color_v_0 = get_intrinsics(camera_name_color)
196 filename_color_intrinsics = prefix_data + camera_name_color + ".xml"
197 save_intrinsics(filename_color_intrinsics, camera_name_color, color_w, color_h, color_p_x, color_p_y, color_u_0, color_v_0)
198
199 depth_w, depth_h, depth_p_x, depth_p_y, depth_u_0, depth_v_0 = get_intrinsics(camera_name_depth)
200 filename_depth_intrinsics = prefix_data + camera_name_depth + ".xml"
201 save_intrinsics(filename_depth_intrinsics, camera_name_depth, depth_w, depth_h, depth_p_x, depth_p_y, depth_u_0, depth_v_0)
202
203 for step in range(scene.frame_start, scene.frame_end):
204 # Set render frame
205 scene.frame_set(step)
206
207 # Set filename and render
208 if not os.path.exists(prefix_color_images):
209 os.makedirs(prefix_color_images)
210 scene.render.filepath = (prefix_color_images + '%04d') % step
211 scene.render.image_settings.file_format = images_suffix
212 bpy.ops.render.render( write_still=True )
213
214 save_color_camera_pose(prefix_pose, scene, camera_name_color, object_name)
215
216 # Remove useless rendered images to keep only
217 # - color images from Camera_L
218 # - depth images from Camera_R
219 filename_color_R = (prefix_color_images + '%04d' + "_R" + scene.render.file_extension) % step
220 if not os.path.exists(filename_color_R):
221 raise Exception(f"Color image {filename_color_R} doesn't exists. Should not occur.")
222
223 print(f"Remove file: {filename_color_R}")
224 os.remove(filename_color_R)
225
226 filename_depth_L = (prefix_depth_images + 'Image%04d' + "_L" + ".exr") % step
227 if not os.path.exists(filename_depth_L):
228 raise Exception(f"Depth image {filename_depth_L} doesn't exists. Check if you set the extension to OpenEXR in the compositor.")
229
230 print(f"Remove file: {filename_depth_L}")
231 os.remove(filename_depth_L)
save_color_camera_pose(prefix, scene, camera_name, object_name)
Save homogeneous transformation from camera to object frames (cMo).
get_intrinsics(camera_name)
Save camera intrinsics in xml.
save_intrinsics(filename, camera_name, w, h, p_x, p_y, u_0, v_0)
Save camera intrinsics in xml.
save_depth_M_color_file(prefix_data, scene, camera_name_color, camera_name_depth)
Save depth_M_color.txt file.
get_camera_pose(camera_name, object_name)
Return the object pose in the camera frame as an homogenous matrices.
save_pose(filename, pose)
Save pose in a .txt file.
get_object_pose_in_world(object_name)
Return the object pose in the world frame w_M_o.