-
Notifications
You must be signed in to change notification settings - Fork 3
/
exocentric_render_photogrammetry.py
130 lines (123 loc) · 5.77 KB
/
exocentric_render_photogrammetry.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import os
import argparse
import sys
import subprocess
import multiprocessing
import pyexcel
import itertools
import nvgpu
DEFAULT_M3D_PATH = r'PATH_TO_MATTERPORT3D'
DEFAULT_DRONE_TRAJECTORIES = r'PATH_TO_TRAJECTORY_FOLDERS'
DEFAULT_BLENDER_PATH = r'PATH_TO_BLENDER_EXE'
DEFAULT_OUTPUT_PATH = r'PATH_TO_DUMP_RESULTS'
DEFAULT_RENDER_SCRIPT_PATH = ".\\render\\PilotRender.py"
DEFAULT_RENDERED_TRAJECTORIES_PATH = ".\\pilot.xlsx"
DEFAULT_DRONE_MODEL_PATH = r'PATH_TO_DRONE_3D_FBX_MODEL'
def parse_arguments(args):
usage_text = (
"This script renders exocentric viewpoint pairs from Matterport3D using sampled play-generated trajectories."
"Usage: exocentric_render.py --m3d PATH_TO_MATTERPORT3D --generated trajectories PATH_TO_TRAJECTORY_FOLDERS"
" --blender PATH_TO_BLENDER_EXE --rendered_path PATH_TO_DUMP_RESULTS --render_script PATH_TO_RENDER_SCRIPT"
" --rendered_trajectories PATH_TO_DUMP_COMPLETED_JOBS --drone_model PATH_TO_DRONE_3D_FBX_MODEL"
)
parser = argparse.ArgumentParser(description=usage_text)
parser.add_argument('--m3d', type=str, help='Matterport3D root path.',\
default=DEFAULT_M3D_PATH)
parser.add_argument('--generated_trajectories', type=str, help='Root path for the generated trajectories.',\
default=DEFAULT_DRONE_TRAJECTORIES) #TODO: add code
parser.add_argument("--blender", type=str, help="Blender executable path.",\
default=DEFAULT_BLENDER_PATH)
parser.add_argument("--rendered_path", type=str, help="Output folder.",\
default=DEFAULT_OUTPUT_PATH)
parser.add_argument('--render_script', type=str, help='The render script path.',\
default=DEFAULT_RENDER_SCRIPT_PATH)
parser.add_argument('--rendered_trajectories', type=str,
help='The .xlsx file with the already rendered Matterport3D buildings that will be appended to during rendering.',\
default=DEFAULT_RENDERED_TRAJECTORIES_PATH)
parser.add_argument('--drone_model', type=str, help='The .fbx file of the drone model to be used.',\
default=DEFAULT_DRONE_MODEL_PATH) #TODO: add model
return parser.parse_known_args(args)
COMMAND = (
"{0} --background --python {1} -- " # use blender's exe and render script's path
"--samples {2} --scene_model {3} --output_path {4} " #
"--camera_path {5} --device_type {6} --dataset matterport3d " # use \pose path and input flag
"--width 320 --height 240 --drone_model {7} --drone photogrammetry " # currently fixed to DJI and M3D
"--log_sheet {8} " # use primary render group flag
)
def render_trajectory(t):
command, queue = t
gpu_id = queue.get()
try:
command += "--device_id " + str(gpu_id)
print(command)
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, shell=True)
output = process.communicate()
print(output[0])
finally:
queue.put(gpu_id)
def process(t):
command, queue = t
gpu_id = queue.get()
try:
command += "--device_id " + str(gpu_id)
finally:
queue.put(gpu_id)
if __name__ == "__main__":
if 'PROGRAMFILES' in os.environ.keys():
nvidia_smi_path = os.path.join(
os.environ['PROGRAMFILES'],
'NVIDIA Corporation',
'NVSMI'
)
if nvidia_smi_path not in os.environ['PATH']:
os.environ['PATH'] = os.environ['PATH'] + ";" + nvidia_smi_path
gpus = len(nvgpu.available_gpus(max_used_percent=30.0))
args, unknown = parse_arguments(sys.argv)
buildings_root = os.path.join(args.m3d, "v1", "scans")
print("Working on M3D buildings @ %s" % buildings_root)
rendered_trajectories = []
if args.rendered_trajectories is not None and os.path.exists(args.rendered_trajectories):
data = pyexcel.get_sheet(file_name=args.rendered_trajectories)
rendered_trajectories.extend(data.column_at(0))
commands = []
building_hashes = {}
for building_folder in os.listdir(buildings_root):
building_hash = os.path.join(buildings_root, building_folder, building_folder, "matterport_mesh")
for root, dirs, files in os.walk(building_hash, topdown = False):
obj = next((s for s in files if 'obj' in s), None)
mesh = os.path.join(root, obj)
building_hashes.update({building_folder: mesh})
if obj is not None:
break
for traj in os.listdir(args.generated_trajectories):
mesh = building_hashes[traj]
trajectory_folder = os.path.join(args.generated_trajectories, traj)
for trajectory_date in os.listdir(trajectory_folder):
if trajectory_date in rendered_trajectories:
print("Skipping already rendered building (%s)" % building_hash)
continue
for root, dirs, files in os.walk(os.path.join(trajectory_folder, trajectory_date), topdown = False):
txt = next((s for s in files if 'airsim_rec_blender' in s), None)
trajectory_file = os.path.join(root, txt)
if txt is None:
break #TODO: check this
cmd = COMMAND.format(
args.blender, #1
args.render_script, #2
512, #3
mesh, #4
args.rendered_path, #5
trajectory_file, #6
'GPU', #7
args.drone_model, #8
args.rendered_trajectories, #9,
) + " -d --normal_map -f -r -m --silhouette --combined "
commands.extend([cmd])
pool = multiprocessing.Pool(processes=gpus)
m = multiprocessing.Manager()
q = m.Queue()
for gpu_ids in range(gpus):
q.put(gpu_ids)
pool.map(render_trajectory, zip(commands, itertools.repeat(q, len(commands))))
pool.close()
pool.join()