Merge branch 'develop' into dev_ml

This commit is contained in:
Laureηt 2022-09-01 16:34:44 +02:00
commit 4e4fce03eb
No known key found for this signature in database
GPG key ID: D88C6B294FD40994
36 changed files with 236 additions and 78 deletions

View file

@ -62,7 +62,7 @@ If you use this project for a publication, please cite the [paper](https://hal.a
``` ```
@inproceedings{alicevision2021, @inproceedings{alicevision2021,
title={{A}liceVision {M}eshroom: An open-source {3D} reconstruction pipeline}, title={{A}liceVision {M}eshroom: An open-source {3D} reconstruction pipeline},
authors={Carsten Griwodz and Simone Gasparini and Lilian Calvet and Pierre Gurdjos and Fabien Castan and Benoit Maujean and Gregoire De Lillo and Yann Lanthony}, author={Carsten Griwodz and Simone Gasparini and Lilian Calvet and Pierre Gurdjos and Fabien Castan and Benoit Maujean and Gregoire De Lillo and Yann Lanthony},
booktitle={Proceedings of the 12th ACM Multimedia Systems Conference - {MMSys '21}}, booktitle={Proceedings of the 12th ACM Multimedia Systems Conference - {MMSys '21}},
doi = {10.1145/3458305.3478443}, doi = {10.1145/3458305.3478443},
publisher = {ACM Press}, publisher = {ACM Press},

View file

@ -177,7 +177,7 @@ with multiview.GraphModification(graph):
if args.paramOverrides: if args.paramOverrides:
print("\n") print("\n")
import re import re
reExtract = re.compile('(\w+)([:.])(\w+)=(.*)') reExtract = re.compile('(\w+)([:.])(\w[\w.]*)=(.*)')
for p in args.paramOverrides: for p in args.paramOverrides:
result = reExtract.match(p) result = reExtract.match(p)
if not result: if not result:

View file

@ -5,6 +5,7 @@ import argparse
import os import os
import re import re
import sys import sys
import shlex
from pprint import pprint from pprint import pprint
def trim(s): def trim(s):
@ -60,7 +61,7 @@ parser.add_argument('node', metavar='NODE_NAME', type=str,
help='New node name') help='New node name')
parser.add_argument('bin', metavar='CMDLINE', type=str, parser.add_argument('bin', metavar='CMDLINE', type=str,
default=None, default=None,
help='Output plugin folder') help='Input executable')
parser.add_argument('--output', metavar='DIR', type=str, parser.add_argument('--output', metavar='DIR', type=str,
default=os.path.dirname(__file__), default=os.path.dirname(__file__),
help='Output plugin folder') help='Output plugin folder')
@ -77,7 +78,7 @@ soft = "{nodeType}"
if args.bin: if args.bin:
soft = args.bin soft = args.bin
import subprocess import subprocess
proc = subprocess.Popen(args=[args.bin, '--help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc = subprocess.Popen(args=shlex.split(args.bin) + ['--help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate() stdout, stderr = proc.communicate()
inputCmdLineDoc = stdout if stdout else stderr inputCmdLineDoc = stdout if stdout else stderr
elif sys.stdin.isatty(): elif sys.stdin.isatty():
@ -137,7 +138,7 @@ choiceValues1_re = re.compile('\* (?P<value>\w+):')
choiceValues2_re = re.compile('\((?P<value>.+?)\)') choiceValues2_re = re.compile('\((?P<value>.+?)\)')
choiceValues3_re = re.compile('\{(?P<value>.+?)\}') choiceValues3_re = re.compile('\{(?P<value>.+?)\}')
cmdLineArgs = args_re.findall(inputCmdLineDoc) cmdLineArgs = args_re.findall(inputCmdLineDoc.decode('utf-8'))
print('='*80) print('='*80)
pprint(cmdLineArgs) pprint(cmdLineArgs)

View file

@ -272,9 +272,17 @@ def loadSubmitters(folder, packageName):
meshroomFolder = os.path.dirname(os.path.dirname(__file__)) meshroomFolder = os.path.dirname(os.path.dirname(__file__))
additionalNodesPath = os.environ.get("MESHROOM_NODES_PATH", "").split(os.pathsep)
# filter empty strings
additionalNodesPath = [i for i in additionalNodesPath if i]
# Load plugins: # Load plugins:
# - Nodes # - Nodes
loadAllNodes(folder=os.path.join(meshroomFolder, 'nodes')) nodesFolders = [os.path.join(meshroomFolder, 'nodes')] + additionalNodesPath
for f in nodesFolders:
loadAllNodes(folder=f)
# - Submitters # - Submitters
subs = loadSubmitters(os.environ.get("MESHROOM_SUBMITTERS_PATH", meshroomFolder), 'submitters') subs = loadSubmitters(os.environ.get("MESHROOM_SUBMITTERS_PATH", meshroomFolder), 'submitters')

7
meshroom/core/desc.py Normal file → Executable file
View file

@ -5,6 +5,8 @@ import math
import os import os
import psutil import psutil
import ast import ast
import distutils.util
class Attribute(BaseObject): class Attribute(BaseObject):
""" """
@ -191,7 +193,10 @@ class BoolParam(Param):
def validateValue(self, value): def validateValue(self, value):
try: try:
return bool(int(value)) # int cast is useful to handle string values ('0', '1') if isinstance(value, pyCompatibility.basestring):
# use distutils.util.strtobool to handle (1/0, true/false, on/off, y/n)
return bool(distutils.util.strtobool(value))
return bool(value)
except: except:
raise ValueError('BoolParam only supports bool value (param:{}, value:{}, type:{})'.format(self.name, value, type(value))) raise ValueError('BoolParam only supports bool value (param:{}, value:{}, type:{})'.format(self.name, value, type(value)))

View file

@ -95,23 +95,34 @@ class ComputerStatistics:
return return
try: try:
p = subprocess.Popen([self.nvidia_smi, "-q", "-x"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) p = subprocess.Popen([self.nvidia_smi, "-q", "-x"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
xmlGpu, stdError = p.communicate(timeout=10) # 10 seconds if sys.version_info[0] == 2:
# no timeout in python-2
xmlGpu, stdError = p.communicate()
else:
xmlGpu, stdError = p.communicate(timeout=10) # 10 seconds
smiTree = ET.fromstring(xmlGpu) smiTree = ET.fromstring(xmlGpu)
gpuTree = smiTree.find('gpu') gpuTree = smiTree.find('gpu')
try: try:
self._addKV('gpuMemoryUsed', gpuTree.find('fb_memory_usage').find('used').text.split(" ")[0]) gpuMemoryUsed = gpuTree.find('fb_memory_usage').find('used').text.split(" ")[0]
self._addKV('gpuMemoryUsed', gpuMemoryUsed)
except Exception as e: except Exception as e:
logging.debug('Failed to get gpuMemoryUsed: "{}".'.format(str(e))) logging.debug('Failed to get gpuMemoryUsed: "{}".'.format(str(e)))
pass pass
try: try:
self._addKV('gpuUsed', gpuTree.find('utilization').find('gpu_util').text.split(" ")[0]) self.gpuMemoryTotal = gpuTree.find('fb_memory_usage').find('total').text.split(" ")[0]
except Exception as e:
pass
try:
gpuUsed = gpuTree.find('utilization').find('gpu_util').text.split(" ")[0]
self._addKV('gpuUsed', gpuUsed)
except Exception as e: except Exception as e:
logging.debug('Failed to get gpuUsed: "{}".'.format(str(e))) logging.debug('Failed to get gpuUsed: "{}".'.format(str(e)))
pass pass
try: try:
self._addKV('gpuTemperature', gpuTree.find('temperature').find('gpu_temp').text.split(" ")[0]) gpuTemperature = gpuTree.find('temperature').find('gpu_temp').text.split(" ")[0]
self._addKV('gpuTemperature', gpuTemperature)
except Exception as e: except Exception as e:
logging.debug('Failed to get gpuTemperature: "{}".'.format(str(e))) logging.debug('Failed to get gpuTemperature: "{}".'.format(str(e)))
pass pass

View file

@ -136,7 +136,7 @@ def findFilesByTypeInFolder(folder, recursive=False):
else: else:
output.addFiles([os.path.join(currentFolder, filename) for filename in os.listdir(currentFolder)]) output.addFiles([os.path.join(currentFolder, filename) for filename in os.listdir(currentFolder)])
else: else:
# if not a diretory or a file, it may be an expression # if not a directory or a file, it may be an expression
import glob import glob
paths = glob.glob(currentFolder) paths = glob.glob(currentFolder)
filesByType = findFilesByTypeInFolder(paths, recursive=recursive) filesByType = findFilesByTypeInFolder(paths, recursive=recursive)
@ -186,7 +186,7 @@ def panoramaFisheyeHdr(inputImages=None, inputViewpoints=None, inputIntrinsics=N
# when using fisheye images, 'sift' performs better than 'dspsift' # when using fisheye images, 'sift' performs better than 'dspsift'
featureExtraction.attribute("describerTypes").value = ['sift'] featureExtraction.attribute("describerTypes").value = ['sift']
# when using fisheye images, the overlap between images can be small # when using fisheye images, the overlap between images can be small
# and thus requires many features to get enough correspondances for cameras estimation # and thus requires many features to get enough correspondences for cameras estimation
featureExtraction.attribute("describerPreset").value = 'high' featureExtraction.attribute("describerPreset").value = 'high'
return graph return graph

View file

@ -1,4 +1,4 @@
__version__ = "6.0" __version__ = "7.0"
import os import os
import json import json
@ -28,16 +28,17 @@ Viewpoint = [
Intrinsic = [ Intrinsic = [
desc.IntParam(name="intrinsicId", label="Id", description="Intrinsic UID", value=-1, uid=[0], range=None), desc.IntParam(name="intrinsicId", label="Id", description="Intrinsic UID", value=-1, uid=[0], range=None),
desc.FloatParam(name="pxInitialFocalLength", label="Initial Focal Length", desc.FloatParam(name="initialFocalLength", label="Initial Focal Length",
description="Initial Guess on the Focal Length (in pixels). \n" description="Initial Guess on the Focal Length (in pixels). \n"
"When we have an initial value from EXIF, this value is not accurate but cannot be wrong. \n" "When we have an initial value from EXIF, this value is not accurate but cannot be wrong. \n"
"So this value is used to limit the range of possible values in the optimization. \n" "So this value is used to limit the range of possible values in the optimization. \n"
"If you put -1, this value will not be used and the focal length will not be bounded.", "If you put -1, this value will not be used and the focal length will not be bounded.",
value=-1.0, uid=[0], range=None), value=-1.0, uid=[0], range=None),
desc.GroupAttribute(name="pxFocalLength", label="Focal Length", description="Known/Calibrated Focal Length (in pixels)", groupDesc=[ desc.FloatParam(name="focalLength", label="Focal Length", description="Known/Calibrated Focal Length (in mm)", value=1000, uid=[], range=(0, 10000, 1)),
desc.FloatParam(name="x", label="x", description="", value=-1, uid=[], range=(0, 10000, 1)), desc.FloatParam(name="pixelRatio", label="pixel Ratio", description="ratio between pixel width and pixel height", value=1, uid=[], range=(0, 10, 0.1)),
desc.FloatParam(name="y", label="y", description="", value=-1, uid=[], range=(0, 10000, 1)), desc.BoolParam(name='pixelRatioLocked', label='Pixel ratio Locked',
]), description='the pixelRatio value is locked for estimation',
value=True, uid=[0]),
desc.ChoiceParam(name="type", label="Camera Type", desc.ChoiceParam(name="type", label="Camera Type",
description="Mathematical Model used to represent a camera:\n" description="Mathematical Model used to represent a camera:\n"
" * pinhole: Simplest projective camera model without optical distortion (focal and optical center).\n" " * pinhole: Simplest projective camera model without optical distortion (focal and optical center).\n"
@ -107,11 +108,6 @@ def readSfMData(sfmFile):
intrinsic['principalPoint']['x'] = pp[0] intrinsic['principalPoint']['x'] = pp[0]
intrinsic['principalPoint']['y'] = pp[1] intrinsic['principalPoint']['y'] = pp[1]
f = intrinsic['pxFocalLength']
intrinsic['pxFocalLength'] = {}
intrinsic['pxFocalLength']['x'] = f[0]
intrinsic['pxFocalLength']['y'] = f[1]
# convert empty string distortionParams (i.e: Pinhole model) to empty list # convert empty string distortionParams (i.e: Pinhole model) to empty list
if intrinsic['distortionParams'] == '': if intrinsic['distortionParams'] == '':
intrinsic['distortionParams'] = list() intrinsic['distortionParams'] = list()
@ -255,12 +251,6 @@ The metadata needed are:
] ]
def upgradeAttributeValues(self, attrValues, fromVersion): def upgradeAttributeValues(self, attrValues, fromVersion):
# Starting with version 5, the focal length is now split on x and y
if fromVersion < Version(5, 0):
for intrinsic in attrValues['intrinsics']:
pxFocalLength = intrinsic['pxFocalLength']
if not isinstance(pxFocalLength, dict):
intrinsic['pxFocalLength'] = {"x": pxFocalLength, "y": pxFocalLength}
# Starting with version 6, the principal point is now relative to the image center # Starting with version 6, the principal point is now relative to the image center
if fromVersion < Version(6, 0): if fromVersion < Version(6, 0):
@ -271,6 +261,20 @@ The metadata needed are:
"y": int(principalPoint["y"] - 0.5 * intrinsic['height']) "y": int(principalPoint["y"] - 0.5 * intrinsic['height'])
} }
# Starting with version 7, the focal length is now in mm
if fromVersion < Version(7, 0):
for intrinsic in attrValues['intrinsics']:
pxInitialFocalLength = intrinsic['pxInitialFocalLength']
pxFocalLength = intrinsic['pxFocalLength']
sensorWidth = intrinsic['sensorWidth']
width = intrinsic['width']
focalLength = (pxFocalLength / width) * sensorWidth
initialFocalLength = (pxInitialFocalLength / width) * sensorWidth
intrinsic['initialFocalLength'] = initialFocalLength
intrinsic['focalLength'] = focalLength
intrinsic['pixelRatio'] = 1.0
intrinsic['pixelRatioLocked'] = False
return attrValues return attrValues
def readSfMData(self, sfmFile): def readSfMData(self, sfmFile):
@ -329,7 +333,6 @@ The metadata needed are:
intrinsics = node.intrinsics.getPrimitiveValue(exportDefault=True) intrinsics = node.intrinsics.getPrimitiveValue(exportDefault=True)
for intrinsic in intrinsics: for intrinsic in intrinsics:
intrinsic['principalPoint'] = [intrinsic['principalPoint']['x'], intrinsic['principalPoint']['y']] intrinsic['principalPoint'] = [intrinsic['principalPoint']['x'], intrinsic['principalPoint']['y']]
intrinsic['pxFocalLength'] = [intrinsic['pxFocalLength']['x'], intrinsic['pxFocalLength']['y']]
views = node.viewpoints.getPrimitiveValue(exportDefault=False) views = node.viewpoints.getPrimitiveValue(exportDefault=False)
# convert the metadata string into a map # convert the metadata string into a map
@ -338,7 +341,7 @@ The metadata needed are:
view['metadata'] = json.loads(view['metadata']) view['metadata'] = json.loads(view['metadata'])
sfmData = { sfmData = {
"version": [1, 2, 1], "version": [1, 2, 2],
"views": views + newViews, "views": views + newViews,
"intrinsics": intrinsics, "intrinsics": intrinsics,
"featureFolder": "", "featureFolder": "",

View file

@ -17,7 +17,7 @@ Performs Macbeth color checker chart detection.
Outputs: Outputs:
- the detected color charts position and colors - the detected color charts position and colors
- the associated tranform matrix from "theoric" to "measured" - the associated transform matrix from "theoric" to "measured"
assuming that the "theoric" Macbeth chart corners coordinates are: assuming that the "theoric" Macbeth chart corners coordinates are:
(0, 0), (1675, 0), (1675, 1125), (0, 1125) (0, 0), (1675, 0), (1675, 1125), (0, 1125)

View file

@ -63,6 +63,38 @@ Use a downscale factor of one (full-resolution) only if the quality of the input
uid=[0], uid=[0],
advanced=True, advanced=True,
), ),
desc.IntParam(
name='sgmScale',
label='SGM: Downscale factor',
description='Semi Global Matching: Downscale factor used to compute the similarity volume.',
value=-1,
range=(-1, 10, 1),
uid=[0],
),
desc.IntParam(
name='sgmStepXY',
label='SGM: Step XY',
description='Semi Global Matching: Step used to compute the similarity volume on X and Y axis.',
value=-1,
range=(-1, 10, 1),
uid=[0],
),
desc.IntParam(
name='sgmStepZ',
label='SGM: Step Z',
description='Semi Global Matching: Step used to compute the similarity volume on Z axis.',
value=-1,
range=(-1, 10, 1),
uid=[0],
),
desc.IntParam(
name='sgmMaxSideXY',
label='SGM: Max Side',
description='Semi Global Matching: Max side in pixels used to automatically decide for sgmScale/sgmStep if not defined.',
value=700,
range=(-1, 1000, 1),
uid=[0],
),
desc.IntParam( desc.IntParam(
name='sgmMaxTCams', name='sgmMaxTCams',
label='SGM: Nb Neighbour Cameras', label='SGM: Nb Neighbour Cameras',
@ -98,6 +130,59 @@ Use a downscale factor of one (full-resolution) only if the quality of the input
uid=[0], uid=[0],
advanced=True, advanced=True,
), ),
desc.FloatParam(
name='sgmP1',
label='SGM: P1',
description='Semi Global Matching: P1.',
value=10.0,
range=(0.0, 255.0, 0.5),
uid=[0],
advanced=True,
),
desc.FloatParam(
name='sgmP2',
label='SGM: P2',
description='Semi Global Matching: P2 weight.',
value=100.0,
range=(-255.0, 255.0, 0.5),
uid=[0],
advanced=True,
),
desc.IntParam(
name='sgmMaxDepths',
label='SGM: Max Depths',
description='Semi Global Matching: Max number of depths in the overall similarity volume.',
value=3000,
range=(1, 5000, 1),
uid=[0],
advanced=True,
),
desc.IntParam(
name='sgmMaxDepthsPerTc',
label='SGM: Max Depths Per Camera Pairs',
description='Semi Global Matching: Max number of depths to sweep in the similarity volume per Rc/Tc cameras.',
value=1500,
range=(1, 5000, 1),
uid=[0],
advanced=True,
),
desc.BoolParam(
name='sgmUseSfmSeeds',
label='SGM: Use SfM Landmarks',
description='Semi Global Matching: Use landmarks from SfM to define the ranges for the plane sweeping.',
value=True,
uid=[0],
advanced=True,
),
desc.StringParam(
name='sgmFilteringAxes',
label='SGM: Filtering Axes',
description="Semi Global Matching: Define axes for the filtering of the similarity volume.",
value='YX',
uid=[0],
advanced=True,
),
desc.IntParam( desc.IntParam(
name='refineMaxTCams', name='refineMaxTCams',
label='Refine: Nb Neighbour Cameras', label='Refine: Nb Neighbour Cameras',

View file

@ -74,6 +74,15 @@ This allows to filter unstable points before starting the fusion of all depth ma
range=(0, 10, 1), range=(0, 10, 1),
uid=[0], uid=[0],
), ),
desc.FloatParam(
name='pixToleranceFactor',
label='Tolerance Size',
description='Filtering tolerance size factor (in px).',
value=2.0,
range=(0.001, 10.0, 0.1),
uid=[0],
advanced=True,
),
desc.IntParam( desc.IntParam(
name="pixSizeBall", name="pixSizeBall",
label="Filtering Size in Pixels", label="Filtering Size in Pixels",

View file

@ -170,7 +170,7 @@ then it checks the number of features that validates this model and iterate thro
desc.BoolParam( desc.BoolParam(
name='crossMatching', name='crossMatching',
label='Cross Matching', label='Cross Matching',
description='Make sure that the matching process is symmetric (same matches for I->J than fo J->I)', description='Make sure that the matching process is symmetric (same matches for I->J than for J->I)',
value=False, value=False,
uid=[0], uid=[0],
), ),

View file

@ -43,7 +43,7 @@ Estimate the seams lines between the inputs to provide an optimal compositing in
desc.BoolParam( desc.BoolParam(
name='useGraphCut', name='useGraphCut',
label='Use Smart Seams', label='Use Smart Seams',
description='Use a graphcut algorithm to optmize seams for better transitions between images.', description='Use a graphcut algorithm to optimize seams for better transitions between images.',
value=True, value=True,
uid=[0], uid=[0],
), ),

View file

@ -200,7 +200,7 @@ Upload a textured mesh on Sketchfab.
modelEndpoint, **{'data': body, 'headers': headers}) modelEndpoint, **{'data': body, 'headers': headers})
chunk.logManager.completeProgressBar() chunk.logManager.completeProgressBar()
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
chunk.logger.error(u'An error occured: {}'.format(e)) chunk.logger.error(u'An error occurred: {}'.format(e))
raise RuntimeError() raise RuntimeError()
if r.status_code != requests.codes.created: if r.status_code != requests.codes.created:
chunk.logger.error(u'Upload failed with error: {}'.format(r.json())) chunk.logger.error(u'Upload failed with error: {}'.format(r.json()))

View file

@ -6,7 +6,7 @@ class Split360Images(desc.CommandLineNode):
commandLine = 'aliceVision_utils_split360Images {allParams}' commandLine = 'aliceVision_utils_split360Images {allParams}'
category = 'Utils' category = 'Utils'
documentation = '''This node is used to extract multiple images from equirectangular or dualfisheye images or image folder''' documentation = "This node is used to extract multiple images from equirectangular or dualfisheye images."
inputs = [ inputs = [
desc.File( desc.File(

View file

@ -116,7 +116,7 @@ It iterates like that, adding cameras and triangulating new 2D features into 3D
desc.ChoiceParam( desc.ChoiceParam(
name='observationConstraint', name='observationConstraint',
label='Observation Constraint', label='Observation Constraint',
description='Observation contraint mode used in the optimization:\n' description='Observation constraint mode used in the optimization:\n'
' * Basic: Use standard reprojection error in pixel coordinates\n' ' * Basic: Use standard reprojection error in pixel coordinates\n'
' * Scale: Use reprojection error in pixel coordinates but relative to the feature scale', ' * Scale: Use reprojection error in pixel coordinates but relative to the feature scale',
value='Scale', value='Scale',
@ -308,6 +308,13 @@ It iterates like that, adding cameras and triangulating new 2D features into 3D
value=False, value=False,
uid=[0], uid=[0],
), ),
desc.BoolParam(
name='computeStructureColor',
label='Compute Structure Color',
description='Enable/Disable color computation of each 3D point.',
value=True,
uid=[0],
),
desc.File( desc.File(
name='initialPairA', name='initialPairA',
label='Initial Pair A', label='Initial Pair A',

View file

@ -273,7 +273,7 @@ Many cameras are contributing to the low frequencies and only the best ones cont
desc.BoolParam( desc.BoolParam(
name='forceVisibleByAllVertices', name='forceVisibleByAllVertices',
label='Force Visible By All Vertices', label='Force Visible By All Vertices',
description='''Triangle visibility is based on the union of vertices visiblity.''', description='''Triangle visibility is based on the union of vertices visibility.''',
value=False, value=False,
uid=[0], uid=[0],
advanced=True, advanced=True,

View file

@ -31,7 +31,7 @@ def main():
parser.add_argument( parser.add_argument(
"--useBackground", type=strtobool, required=True, "--useBackground", type=strtobool, required=True,
help="Diplay the background image or not.", help="Display the background image or not.",
) )
parser.add_argument( parser.add_argument(
@ -262,8 +262,8 @@ def main():
# For showing an outline of the object, we need to add two materials to the mesh: # For showing an outline of the object, we need to add two materials to the mesh:
# Center and Edge, we are using a method that consists in having a "bold" effect on the Edge Material so we can see it # Center and Edge, we are using a method that consists in having a "bold" effect on the Edge Material so we can see it
# around the Center material. We use a Solidify Modifier on which we flip normals and reduce Thickness to bellow zero. # around the Center material. We use a Solidify Modifier on which we flip normals and reduce Thickness to below zero.
# The more the thickness get bellow zero, the more the egde will be largely revealed. # The more the thickness get below zero, the more the edge will be largely revealed.
elif args.model.lower().endswith('.obj'): elif args.model.lower().endswith('.obj'):
print("Import OBJ") print("Import OBJ")

View file

@ -12,7 +12,7 @@
}, },
"GPU": { "GPU": {
"NONE": [], "NONE": [],
"NORMAL": ["!\"*rnd*\""], "NORMAL": ["cuda8G"],
"INTENSIVE": ["!\"*rnd*\"", "@.nCPUs>=12"] "INTENSIVE": ["cuda16G"]
} }
} }

View file

@ -3,6 +3,7 @@
import os import os
import json import json
import logging
import simpleFarm import simpleFarm
from meshroom.core.desc import Level from meshroom.core.desc import Level
@ -12,14 +13,12 @@ currentDir = os.path.dirname(os.path.realpath(__file__))
binDir = os.path.dirname(os.path.dirname(os.path.dirname(currentDir))) binDir = os.path.dirname(os.path.dirname(os.path.dirname(currentDir)))
class SimpleFarmSubmitter(BaseSubmitter): class SimpleFarmSubmitter(BaseSubmitter):
if 'REZ_MESHROOM_VERSION' in os.environ:
MESHROOM_PACKAGE = "meshroom-{}".format(os.environ.get('REZ_MESHROOM_VERSION', ''))
else:
MESHROOM_PACKAGE = None
filepath = os.environ.get('SIMPLEFARMCONFIG', os.path.join(currentDir, 'simpleFarmConfig.json')) filepath = os.environ.get('SIMPLEFARMCONFIG', os.path.join(currentDir, 'simpleFarmConfig.json'))
config = json.load(open(filepath)) config = json.load(open(filepath))
reqPackages = []
environment = {}
ENGINE = '' ENGINE = ''
DEFAULT_TAGS = {'prod': ''} DEFAULT_TAGS = {'prod': ''}
@ -28,6 +27,32 @@ class SimpleFarmSubmitter(BaseSubmitter):
self.engine = os.environ.get('MESHROOM_SIMPLEFARM_ENGINE', 'tractor') self.engine = os.environ.get('MESHROOM_SIMPLEFARM_ENGINE', 'tractor')
self.share = os.environ.get('MESHROOM_SIMPLEFARM_SHARE', 'vfx') self.share = os.environ.get('MESHROOM_SIMPLEFARM_SHARE', 'vfx')
self.prod = os.environ.get('PROD', 'mvg') self.prod = os.environ.get('PROD', 'mvg')
if 'REZ_REQUEST' in os.environ:
packages = os.environ.get('REZ_REQUEST', '').split()
resolvedPackages = os.environ.get('REZ_RESOLVE', '').split()
resolvedVersions = {}
for r in resolvedPackages:
# remove implict packages
if r.startswith('~'):
continue
# logging.info('REZ: {}'.format(str(r)))
v = r.split('-')
# logging.info(' v: {}'.format(str(v)))
if len(v) == 2:
resolvedVersions[v[0]] = v[1]
for p in packages:
if p.startswith('~'):
continue
v = p.split('-')
self.reqPackages.append('-'.join([v[0], resolvedVersions[v[0]]]))
logging.debug('REZ Packages: {}'.format(str(self.reqPackages)))
elif 'REZ_MESHROOM_VERSION' in os.environ:
self.reqPackages = ["meshroom-{}".format(os.environ.get('REZ_MESHROOM_VERSION', ''))]
else:
self.reqPackages = None
if 'REZ_DEV_PACKAGES_ROOT' in os.environ:
self.environment['REZ_DEV_PACKAGES_ROOT'] = os.environ['REZ_DEV_PACKAGES_ROOT']
def createTask(self, meshroomFile, node): def createTask(self, meshroomFile, node):
tags = self.DEFAULT_TAGS.copy() # copy to not modify default tags tags = self.DEFAULT_TAGS.copy() # copy to not modify default tags
@ -50,10 +75,10 @@ class SimpleFarmSubmitter(BaseSubmitter):
task = simpleFarm.Task( task = simpleFarm.Task(
name=node.nodeType, name=node.nodeType,
command='{exe} --node {nodeName} "{meshroomFile}" {parallelArgs} --extern'.format( command='{exe} --node {nodeName} "{meshroomFile}" {parallelArgs} --extern'.format(
exe='meshroom_compute' if self.MESHROOM_PACKAGE else os.path.join(binDir, 'meshroom_compute'), exe='meshroom_compute' if self.reqPackages else os.path.join(binDir, 'meshroom_compute'),
nodeName=node.name, meshroomFile=meshroomFile, parallelArgs=parallelArgs), nodeName=node.name, meshroomFile=meshroomFile, parallelArgs=parallelArgs),
tags=tags, tags=tags,
rezPackages=[self.MESHROOM_PACKAGE] if self.MESHROOM_PACKAGE else None, rezPackages=self.reqPackages,
requirements={'service': str(','.join(allRequirements))}, requirements={'service': str(','.join(allRequirements))},
**arguments) **arguments)
return task return task
@ -74,6 +99,7 @@ class SimpleFarmSubmitter(BaseSubmitter):
job = simpleFarm.Job(name, job = simpleFarm.Job(name,
tags=mainTags, tags=mainTags,
requirements={'service': str(','.join(allRequirements))}, requirements={'service': str(','.join(allRequirements))},
environment=self.environment,
) )
nodeNameToTask = {} nodeNameToTask = {}

View file

@ -515,7 +515,7 @@ class UIGraph(QObject):
@Slot(Node, QPoint, QObject) @Slot(Node, QPoint, QObject)
def moveNode(self, node, position, nodes=None): def moveNode(self, node, position, nodes=None):
""" """
Move 'node' to the given 'position' and also update the positions of 'nodes' if neccessary. Move 'node' to the given 'position' and also update the positions of 'nodes' if necessary.
Args: Args:
node (Node): the node to move node (Node): the node to move

View file

@ -118,7 +118,7 @@ Dialog {
font.pointSize: 10 font.pointSize: 10
} }
Label { Label {
text: "2010-2021 AliceVision contributors" text: "2010-2022 AliceVision contributors"
} }
} }

View file

@ -20,7 +20,7 @@ Dialog {
/// Return the text content of this dialog as a simple string. /// Return the text content of this dialog as a simple string.
/// Used when copying the message in the system clipboard. /// Used when copying the message in the system clipboard.
/// Can be overriden in components extending MessageDialog /// Can be overridden in components extending MessageDialog
function getAsString() { function getAsString() {
return asString return asString
} }

View file

@ -7,7 +7,7 @@ import Controls 1.0
*/ */
QtObject { QtObject {
readonly property string defaultErrorText: "An unexpected error has occured" readonly property string defaultErrorText: "An unexpected error has occurred"
property Component infoDialog: Component { property Component infoDialog: Component {
MessageDialog { MessageDialog {

View file

@ -63,7 +63,7 @@ Item {
} }
} }
/// Duplicate a node and optionnally all the following ones /// Duplicate a node and optionally all the following ones
function duplicateNode(duplicateFollowingNodes) { function duplicateNode(duplicateFollowingNodes) {
if (duplicateFollowingNodes) { if (duplicateFollowingNodes) {
var nodes = uigraph.duplicateNodesFrom(uigraph.selectedNodes) var nodes = uigraph.duplicateNodesFrom(uigraph.selectedNodes)

View file

@ -48,6 +48,10 @@ Panel {
parseIntr() parseIntr()
} }
function changeCurrentIndex(newIndex) {
_reconstruction.cameraInitIndex = newIndex
}
function populate_model() function populate_model()
{ {
intrinsicModel.clear() intrinsicModel.clear()
@ -474,9 +478,8 @@ Panel {
property var columnWidths: [105, 75, 75, 75, 125, 60, 60, 45, 45, 200, 60, 60] property var columnWidths: [105, 75, 75, 75, 125, 60, 60, 45, 45, 200, 60, 60]
property var columnNames: [ property var columnNames: [
"intrinsicId", "intrinsicId",
"pxInitialFocalLength", "initialFocalLength",
"pxFocalLength.x", "focalLength",
"pxFocalLength.y",
"type", "type",
"width", "width",
"height", "height",
@ -499,7 +502,6 @@ Panel {
TableModelColumn { display: function(modelIndex){return parsedIntrinsic[modelIndex.row][intrinsicModel.columnNames[9]]} } TableModelColumn { display: function(modelIndex){return parsedIntrinsic[modelIndex.row][intrinsicModel.columnNames[9]]} }
TableModelColumn { display: function(modelIndex){return parsedIntrinsic[modelIndex.row][intrinsicModel.columnNames[10]]} } TableModelColumn { display: function(modelIndex){return parsedIntrinsic[modelIndex.row][intrinsicModel.columnNames[10]]} }
TableModelColumn { display: function(modelIndex){return parsedIntrinsic[modelIndex.row][intrinsicModel.columnNames[11]]} } TableModelColumn { display: function(modelIndex){return parsedIntrinsic[modelIndex.row][intrinsicModel.columnNames[11]]} }
TableModelColumn { display: function(modelIndex){return parsedIntrinsic[modelIndex.row][intrinsicModel.columnNames[12]]} }
//https://doc.qt.io/qt-5/qml-qt-labs-qmlmodels-tablemodel.html#appendRow-method //https://doc.qt.io/qt-5/qml-qt-labs-qmlmodels-tablemodel.html#appendRow-method
} }
@ -541,7 +543,7 @@ Panel {
font.family: MaterialIcons.fontFamily font.family: MaterialIcons.fontFamily
ToolTip.text: "Next Group (Alt+Right)" ToolTip.text: "Next Group (Alt+Right)"
ToolTip.visible: hovered ToolTip.visible: hovered
enabled: root.cameraInitIndex < root.cameraInits.count - 1 enabled: nodesCB.currentIndex < root.cameraInits.count - 1
onClicked: nodesCB.incrementCurrentIndex() onClicked: nodesCB.incrementCurrentIndex()
} }
} }

View file

@ -5,12 +5,12 @@ import QtQuick.Controls 2.3
/** /**
* SortFilderDelegateModel adds sorting and filtering capabilities on a source model. * SortFilderDelegateModel adds sorting and filtering capabilities on a source model.
* *
* The way model data is accessed can be overriden by redefining the modelData function. * The way model data is accessed can be overridden by redefining the modelData function.
* This is useful if the value is not directly accessible from the model and needs * This is useful if the value is not directly accessible from the model and needs
* some extra logic. * some extra logic.
* *
* Regarding filtering, any type of value can be used as 'filterValue' (variant). * Regarding filtering, any type of value can be used as 'filterValue' (variant).
* Filtering behavior can also be overriden by redefining the respectFilter function. * Filtering behavior can also be overridden by redefining the respectFilter function.
* *
* Based on http://doc.qt.io/qt-5/qtquick-tutorials-dynamicview-dynamicview4-example.html * Based on http://doc.qt.io/qt-5/qtquick-tutorials-dynamicview-dynamicview4-example.html
*/ */

View file

@ -1,7 +1,7 @@
.pragma library .pragma library
/** /**
* Perform 'GET' request on url, and bind 'callback' to onreadystatechange (with XHR objet as parameter). * Perform 'GET' request on url, and bind 'callback' to onreadystatechange (with XHR object as parameter).
*/ */
function get(url, callback) { function get(url, callback) {
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();

View file

@ -4,8 +4,8 @@ Item {
id: root id: root
// required for perspective transform // required for perspective transform
property real sizeX: 1675.0 // might be overrided in ColorCheckerViewer property real sizeX: 1675.0 // might be overridden in ColorCheckerViewer
property real sizeY: 1125.0 // might be overrided in ColorCheckerViewer property real sizeY: 1125.0 // might be overridden in ColorCheckerViewer
property var colors: null property var colors: null
property var window: null property var window: null

View file

@ -200,7 +200,7 @@ FloatingPane {
font.pointSize: 10 font.pointSize: 10
opacity: featureType.viewer.visible ? 1.0 : 0.6 opacity: featureType.viewer.visible ? 1.0 : 0.6
} }
// Tracks visibility toogle // Tracks visibility toggle
MaterialToolButton { MaterialToolButton {
id: tracksVisibilityButton id: tracksVisibilityButton
checkable: true checkable: true
@ -213,7 +213,7 @@ FloatingPane {
} }
font.pointSize: 10 font.pointSize: 10
} }
// Matches visibility toogle // Matches visibility toggle
MaterialToolButton { MaterialToolButton {
id: matchesVisibilityButton id: matchesVisibilityButton
checkable: true checkable: true
@ -225,7 +225,7 @@ FloatingPane {
} }
font.pointSize: 10 font.pointSize: 10
} }
// Landmarks visibility toogle // Landmarks visibility toggle
MaterialToolButton { MaterialToolButton {
id: landmarksVisibilityButton id: landmarksVisibilityButton
checkable: true checkable: true

View file

@ -94,7 +94,7 @@ void main()
else else
{ {
// Viewport projection breaks down for one or two vertices. // Viewport projection breaks down for one or two vertices.
// Caclulate what we can here and defer rest to fragment shader. // Calculate what we can here and defer rest to fragment shader.
// Since this is coherent for the entire primitive the conditional // Since this is coherent for the entire primitive the conditional
// in the fragment shader is still cheap as all concurrent // in the fragment shader is still cheap as all concurrent
// fragment shader invocations will take the same code path. // fragment shader invocations will take the same code path.

View file

@ -21,7 +21,7 @@ Entity {
property Layer frontLayerComponent property Layer frontLayerComponent
property var window property var window
/// Camera to consider for positionning /// Camera to consider for positioning
property Camera camera: null property Camera camera: null
/// True while at least one media is being loaded /// True while at least one media is being loaded
@ -190,7 +190,7 @@ Entity {
// whether MediaLoader has been fully instantiated by the NodeInstantiator // whether MediaLoader has been fully instantiated by the NodeInstantiator
property bool fullyInstantiated: false property bool fullyInstantiated: false
// explicitely store some attached model properties for outside use and ease binding // explicitly store some attached model properties for outside use and ease binding
readonly property var attribute: model.attribute readonly property var attribute: model.attribute
readonly property int idx: index readonly property int idx: index
readonly property var modelSource: attribute || model.source readonly property var modelSource: attribute || model.source
@ -216,7 +216,7 @@ Entity {
property string finalSource: model.requested ? currentSource : "" property string finalSource: model.requested ? currentSource : ""
// To use only if we want to draw the input source and not the current node output (Warning: to use with caution) // To use only if we want to draw the input source and not the current node output (Warning: to use with caution)
// There is maybe a better way to do this to avoid overwritting bindings which should be readonly properties // There is maybe a better way to do this to avoid overwriting bindings which should be readonly properties
function drawInputSource() { function drawInputSource() {
rawSource = Qt.binding(() => instantiatedEntity.currentNode ? instantiatedEntity.currentNode.attribute("input").value: "") rawSource = Qt.binding(() => instantiatedEntity.currentNode ? instantiatedEntity.currentNode.attribute("input").value: "")
currentSource = Qt.binding(() => rawSource) currentSource = Qt.binding(() => rawSource)

View file

@ -120,7 +120,7 @@ Item {
} }
Action { Action {
id: displayLensDistortionToolBarAction id: displayLensDistortionToolBarAction
text: "Display Lens Distorsion Toolbar" text: "Display Lens Distortion Toolbar"
checkable: true checkable: true
checked: true checked: true
enabled: viewer2D.useLensDistortionViewer enabled: viewer2D.useLensDistortionViewer

View file

@ -613,7 +613,7 @@ ApplicationWindow {
Action { Action {
text: "About Meshroom" text: "About Meshroom"
onTriggered: aboutDialog.open() onTriggered: aboutDialog.open()
// shoud be StandardKey.HelpContents, but for some reason it's not stable // should be StandardKey.HelpContents, but for some reason it's not stable
// (may cause crash, requires pressing F1 twice after closing the popup) // (may cause crash, requires pressing F1 twice after closing the popup)
shortcut: "F1" shortcut: "F1"
} }

View file

@ -358,8 +358,9 @@ class ViewpointWrapper(QObject):
""" Get camera vertical field of view in degrees. """ """ Get camera vertical field of view in degrees. """
if not self.solvedIntrinsics: if not self.solvedIntrinsics:
return None return None
pxFocalLength = self.solvedIntrinsics["pxFocalLength"] focalLength = self.solvedIntrinsics["focalLength"]
return 2.0 * math.atan(self.orientedImageSize.height() / (2.0 * float(pxFocalLength[0]))) * 180 / math.pi sensorHeight = self.solvedIntrinsics["sensorHeight"]
return 2.0 * math.atan(float(sensorHeight) / (2.0 * float(focalLength))) * 180.0 / math.pi
@Property(type=QUrl, notify=denseSceneParamsChanged) @Property(type=QUrl, notify=denseSceneParamsChanged)
def undistortedImageSource(self): def undistortedImageSource(self):

View file

@ -87,7 +87,7 @@ class QmlInstantEngine(QQmlApplicationEngine):
self._extensions = extensions self._extensions = extensions
def setVerbose(self, verboseValue): def setVerbose(self, verboseValue):
""" Activate (True) or desactivate (False) the verbose. """ """ Activate (True) or deactivate (False) the verbose. """
self._verbose = verboseValue self._verbose = verboseValue
def addFile(self, filename): def addFile(self, filename):