├── README.md └── instant-ngp-blender-export.py /README.md: -------------------------------------------------------------------------------- 1 | # BlenderInstant-NGPScript 2 | 3 | Initial script by Martijn Courteaux (https://github.com/mcourteaux) 4 | 5 | 1. Align your image set in Reality Capture with all images in the same Calibration and Lens Distortion group 6 | 2. Create a preview mesh from your alignment 7 | 3. Export a FBX from Reality Capture, ensure Export Cameras and Undistort Images are set to Yes 8 | 4. Open Blender, and delete the default cube, camera and light 9 | 5. Import your previously created FBX 10 | 6. Copy and paste the script into a new Text item in the Scripting view 11 | 7. Save your Blender project (script won't run without this step) 12 | 8. Run the script 13 | 9. Add scale, aabb_scale, and offset to the generated transform.json (example values below but dataset dependent) 14 | 15 | ``` 16 | "scale": 0.15, 17 | "aabb_scale": 16, 18 | "offset": [0.5, 0.5, 0.5], 19 | ``` 20 | 10. Copy your undistorted images to an images subfolder in your dataset folder and transforms.json to the root of the dataset folder 21 | 11. Run the instant-ngp testbed with your dataset 22 | -------------------------------------------------------------------------------- /instant-ngp-blender-export.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import numpy as np 3 | import json 4 | from os.path import dirname, join 5 | from mathutils import Vector 6 | 7 | fp = bpy.path.abspath(f"//images") 8 | 9 | def listify_matrix(matrix): 10 | matrix_list = [] 11 | for row in matrix: 12 | print(list(row)) 13 | matrix_list.append(list(row)) 14 | return matrix_list 15 | 16 | def generate_transform_matrix(pos, rot, average_position): 17 | def Rx(theta): 18 | return np.matrix([[ 1, 0 , 0 ], 19 | [ 0, np.cos(theta),-np.sin(theta)], 20 | [ 0, np.sin(theta), np.cos(theta)]]) 21 | def Ry(theta): 22 | return np.matrix([[ np.cos(theta), 0, np.sin(theta)], 23 | [ 0 , 1, 0 ], 24 | [-np.sin(theta), 0, np.cos(theta)]]) 25 | def Rz(theta): 26 | return np.matrix([[ np.cos(theta), -np.sin(theta), 0 ], 27 | [ np.sin(theta), np.cos(theta) , 0 ], 28 | [ 0 , 0 , 1 ]]) 29 | 30 | R = Rz(rot[2]) * Ry(rot[1]) * Rx(rot[0]) 31 | xf_rot = np.eye(4) 32 | xf_rot[:3,:3] = R 33 | 34 | xf_pos = np.eye(4) 35 | 36 | #xf_pos[:3,3] = pos - average_position 37 | xf_pos[:3,3] = pos 38 | # barbershop_mirros_hd_dense: 39 | # - camera plane is y+z plane, meaning: constant x-values 40 | # - cameras look to +x 41 | 42 | # Don't ask me... 43 | extra_xf = np.matrix([ 44 | [-1, 0, 0, 0], 45 | [ 0, 0, 1, 0], 46 | [ 0, 1, 0, 0], 47 | [ 0, 0, 0, 1]]) 48 | # NerF will cycle forward, so lets cycle backward. 49 | shift_coords = np.matrix([ 50 | [0, 0, 1, 0], 51 | [1, 0, 0, 0], 52 | [0, 1, 0, 0], 53 | [0, 0, 0, 1]]) 54 | xf = shift_coords @ extra_xf @ xf_pos 55 | assert np.abs(np.linalg.det(xf) - 1.0) < 1e-4 56 | xf = xf @ xf_rot 57 | return xf 58 | 59 | avg_x = 0.0 60 | avg_y = 0.0 61 | avg_z = 0.0 62 | 63 | num_objects = 0; 64 | 65 | scene = bpy.context.scene 66 | for ob in scene.objects: 67 | if ob.type == 'CAMERA': 68 | avg_x += ob.location[0] 69 | avg_y += ob.location[1] 70 | avg_z += ob.location[2] 71 | num_objects = num_objects + 1 72 | print(num_objects) 73 | 74 | avg_pos = Vector((avg_x / num_objects, avg_y / num_objects, avg_z / num_objects)) 75 | 76 | out_data = { 77 | 'camera_angle_x': bpy.data.objects['00000.jpeg'].data.angle_x, 78 | 'camera_angle_y': bpy.data.objects['00000.jpeg'].data.angle_y 79 | } 80 | 81 | out_data['frames'] = [] 82 | 83 | scene = bpy.context.scene 84 | 85 | for ob in scene.objects: 86 | if ob.type == 'CAMERA': 87 | print(ob.name) 88 | xf = generate_transform_matrix(ob.location, ob.rotation_euler, avg_pos) 89 | frame_data = { 90 | 'file_path': "./images/" + ob.name, 91 | #'transform_matrix': listify_matrix(xf) 92 | 'rotation' : 0.0, 93 | 'transform_matrix': xf.tolist() 94 | } 95 | out_data['frames'].append(frame_data) 96 | 97 | with open(fp + '/../' + 'transforms.json', 'w') as out_file: 98 | json.dump(out_data, out_file, indent=4) 99 | 100 | print("DONE") --------------------------------------------------------------------------------