Welcome to mirror list, hosted at ThFree Co, Russian Federation.

meshroom_batch « bin - github.com/alicevision/meshroom.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 5aa752769c0f4fd1650fe5f9b7f643ebfe16bc06 (plain)
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#!/usr/bin/env python
import argparse
import os
import sys
import distutils.util

import meshroom
meshroom.setupEnvironment()

import meshroom.core.graph
from meshroom import multiview
from meshroom.core.desc import InitNode
import logging


parser = argparse.ArgumentParser(description='Launch the full photogrammetry or Panorama HDR pipeline.')
parser.add_argument('-i', '--input', metavar='SFM/FOLDERS/IMAGES', type=str, nargs='*',
                    default=[],
                    help='Input folder containing images or folders of images or file (.sfm or .json) '
                         'with images paths and optionally predefined camera intrinsics.')
parser.add_argument('-I', '--inputRecursive', metavar='FOLDERS/IMAGES', type=str, nargs='*',
                    default=[],
                    help='Input folders containing all images recursively.')

parser.add_argument('-p', '--pipeline', metavar='FILE.mg/' + '/'.join(meshroom.core.pipelineTemplates), type=str, default='photogrammetry',
                    help='Template pipeline among those listed or a Meshroom file containing a custom pipeline to run on input images. '
                         'Requirements: the graph must contain one CameraInit node, '
                         'and one Publish node if --output is set.')

parser.add_argument('--overrides', metavar='SETTINGS', type=str, default=None,
                    help='A JSON file containing the graph parameters override.')

parser.add_argument('--paramOverrides', metavar='NODETYPE:param=value NODEINSTANCE.param=value', type=str, default=None, nargs='*',
                    help='Override specific parameters directly from the command line (by node type or by node names).')

parser.add_argument('-o', '--output', metavar='FOLDER', type=str, required=False,
                    help='Output folder where results should be copied to. '
                         'If not set, results will have to be retrieved directly from the cache folder.')

parser.add_argument('--cache', metavar='FOLDER', type=str,
                    default=None,
                    help='Custom cache folder to write computation results. '
                         'If not set, the default cache folder will be used: ' + meshroom.core.defaultCacheFolder)

parser.add_argument('--save', metavar='FILE', type=str, required=False,
                    help='Save the configured Meshroom graph to a project file. It will setup the cache folder accordingly if not explicitly changed by --cache.')

parser.add_argument('--compute', metavar='<yes/no>', type=lambda x: bool(distutils.util.strtobool(x)), default=True, required=False,
                    help='You can set it to <no/false/0> to disable the computation.')

parser.add_argument('--scale', type=int, default=-1,
                    choices=[-1, 1, 2, 4, 8, 16],
                    help='Downscale factor override for DepthMap estimation. '
                         'By default (-1): use pipeline default value.')

parser.add_argument('--toNode', metavar='NODE', type=str, nargs='*',
                    default=None,
                    help='Process the node(s) with its dependencies.')

parser.add_argument('--forceStatus', help='Force computation if status is RUNNING or SUBMITTED.',
                    action='store_true')
parser.add_argument('--forceCompute', help='Compute in all cases even if already computed.',
                    action='store_true')

parser.add_argument('--submit', help='Submit on renderfarm instead of local computation.',
                    action='store_true')
parser.add_argument('--submitter',
                    type=str,
                    default='SimpleFarm',
                    help='Execute job with a specific submitter.')

parser.add_argument('-v', '--verbose', help="Verbosity level", default='',
                    choices=['', 'fatal', 'error', 'warning', 'info', 'debug', 'trace'],)

args = parser.parse_args()


logStringToPython = {
    'fatal': logging.FATAL,
    'error': logging.ERROR,
    'warning': logging.WARNING,
    'info': logging.INFO,
    'debug': logging.DEBUG,
    'trace': logging.DEBUG,
}
if args.verbose:
    logging.getLogger().setLevel(logStringToPython[args.verbose])


def getOnlyNodeOfType(g, nodeType):
    """ Helper function to get a node of 'nodeType' in the graph 'g' and raise if no or multiple candidates. """
    nodes = g.nodesOfType(nodeType)
    if len(nodes) != 1:
        raise RuntimeError("meshroom_batch requires a pipeline graph with exactly one '{}' node, {} found."
                           .format(nodeType, len(nodes)))
    return nodes[0]


def getInitNode(g):
    """
    Helper function to get the Init node in the graph 'g' and raise an exception if there is no or
    multiple candidates.
    """
    nodes = g.findInitNodes()
    if len(nodes) == 0:
        raise RuntimeError("meshroom_batch requires an Init node in the pipeline.")
    elif len(nodes) > 1:
        raise RuntimeError("meshroom_batch requires exactly one Init node in the pipeline, {} found: {}"
                           .format(len(nodes), str(nodes)))
    return nodes[0]


if not args.input and not args.inputRecursive:
    print('Nothing to compute. You need to set --input or --inputRecursive.')
    sys.exit(1)

graph = multiview.Graph(name=args.pipeline)

with multiview.GraphModification(graph):
    # initialize template pipeline
    loweredPipelineTemplates = dict((k.lower(), v) for k, v in meshroom.core.pipelineTemplates.items())
    if args.pipeline.lower() in loweredPipelineTemplates:
        graph.load(loweredPipelineTemplates[args.pipeline.lower()], setupProjectFile=False)
    else:
        # custom pipeline
        graph.load(args.pipeline, setupProjectFile=False)

    # get init node and initialize it
    initNode = getInitNode(graph)
    initNode.nodeDesc.initialize(initNode, args.input, args.inputRecursive)

    if not graph.canComputeLeaves:
        raise RuntimeError("Graph cannot be computed. Check for compatibility issues.")

    if args.verbose:
        graph.setVerbose(args.verbose)

    if args.output:
        publish = getOnlyNodeOfType(graph, 'Publish')
        publish.output.value = args.output

    if args.overrides:
        import io
        import json
        with io.open(args.overrides, 'r', encoding='utf-8', errors='ignore') as f:
            data = json.load(f)
            for nodeName, overrides in data.items():
                for attrName, value in overrides.items():
                    graph.findNode(nodeName).attribute(attrName).value = value

    if args.paramOverrides:
        print("\n")
        import re
        reExtract = re.compile('(\w+)([:.])(\w[\w.]*)=(.*)')
        for p in args.paramOverrides:
            result = reExtract.match(p)
            if not result:
                raise ValueError('Invalid param override: ' + str(p))
            node, t, param, value = result.groups()
            multiValues = value.split(',')
            if len(multiValues) > 1:
                value = multiValues
            if t == ':':
                nodesOfType = graph.nodesOfType(node)
                if not nodesOfType:
                    raise ValueError('No node with the type "{}" in the scene.'.format(node))
                for n in nodesOfType:
                    print('Overrides {node}.{param}={value}'.format(node=node, param=param, value=value))
                    n.attribute(param).value = value
            elif t == '.':
                print('Overrides {node}.{param}={value}'.format(node=node, param=param, value=value))
                graph.findNode(node).attribute(param).value = value
            else:
                raise ValueError('Invalid param override: ' + str(p))
        print("\n")

    # setup DepthMap downscaling
    if args.scale > 0:
        for node in graph.nodesOfType('DepthMap'):
            node.downscale.value = args.scale

    # setup cache directory
    graph.cacheDir = args.cache if args.cache else meshroom.core.defaultCacheFolder

    if args.save:
        graph.save(args.save, setupProjectFile=not bool(args.cache))
        print('File successfully saved: "{}"'.format(args.save))

if not args.output:
    print('No output set, results will be available in the cache folder: "{}"'.format(graph.cacheDir))

# find end nodes (None will compute all graph)
toNodes = graph.findNodes(args.toNode) if args.toNode else None

if args.submit:
    if not args.save:
        raise ValueError('Need to save the project to file to submit on renderfarm.')
    # submit on renderfarm
    meshroom.core.graph.submit(args.save, args.submitter, toNode=args.toNode)
elif args.compute:
    # find end nodes (None will compute all graph)
    toNodes = graph.findNodes(args.toNode) if args.toNode else None
    # start computation
    meshroom.core.graph.executeGraph(graph, toNodes=toNodes, forceCompute=args.forceCompute, forceStatus=args.forceStatus)