From 3a0b3ac169ca92c424a7cff36c93322e032412cd Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Thu, 11 Apr 2019 11:38:01 +0200 Subject: [PATCH 01/34] [depthMap] new SGM parameters --- meshroom/nodes/aliceVision/DepthMap.py | 59 ++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/meshroom/nodes/aliceVision/DepthMap.py b/meshroom/nodes/aliceVision/DepthMap.py index 24fa4300..84d47d98 100644 --- a/meshroom/nodes/aliceVision/DepthMap.py +++ b/meshroom/nodes/aliceVision/DepthMap.py @@ -52,6 +52,38 @@ class DepthMap(desc.CommandLineNode): uid=[0], 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', + 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', + 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='sgmMaxSide', + label='SGM: Max Side', + description='Semi Global Matching: Max side in pixels used to automatically decide for sgmScale/sgmStep if not defined.', + value=200, + range=(-1, 1000, 1), + uid=[0], + ), desc.IntParam( name='sgmMaxTCams', label='SGM: Nb Neighbour Cameras', @@ -87,6 +119,33 @@ class DepthMap(desc.CommandLineNode): 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=[], + advanced=True, + ), desc.IntParam( name='refineMaxTCams', label='Refine: Nb Neighbour Cameras', From b55bf48da759f1ebd83b9aa66f33d01c1c0cc267 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Fri, 14 Jun 2019 15:47:43 +0200 Subject: [PATCH 02/34] [depthMap] new SGM parameters: P1, P2, filteringAxes --- meshroom/nodes/aliceVision/DepthMap.py | 28 +++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/meshroom/nodes/aliceVision/DepthMap.py b/meshroom/nodes/aliceVision/DepthMap.py index 84d47d98..f83d4013 100644 --- a/meshroom/nodes/aliceVision/DepthMap.py +++ b/meshroom/nodes/aliceVision/DepthMap.py @@ -120,6 +120,24 @@ class DepthMap(desc.CommandLineNode): 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=20.0, + range=(-255.0, 255.0, 0.5), + uid=[0], + advanced=True, + ), desc.IntParam( name='sgmMaxDepths', label='SGM: Max Depths', @@ -143,7 +161,15 @@ class DepthMap(desc.CommandLineNode): label='SGM: Use SfM Landmarks', description='Semi Global Matching: Use landmarks from SfM to define the ranges for the plane sweeping.', value=True, - uid=[], + 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( From e259294640319db455c2bb7ddbdc158ed64afef0 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Tue, 16 Jul 2019 21:21:00 +0200 Subject: [PATCH 03/34] [nodes][aliceVision] DepthMap: fix default value of sgmMaxSideXY --- meshroom/nodes/aliceVision/DepthMap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meshroom/nodes/aliceVision/DepthMap.py b/meshroom/nodes/aliceVision/DepthMap.py index f83d4013..ba14361d 100644 --- a/meshroom/nodes/aliceVision/DepthMap.py +++ b/meshroom/nodes/aliceVision/DepthMap.py @@ -77,10 +77,10 @@ class DepthMap(desc.CommandLineNode): uid=[0], ), desc.IntParam( - name='sgmMaxSide', + 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=200, + value=700, range=(-1, 1000, 1), uid=[0], ), From 366c3e7fd24ea64d117cb04d7ea5eeae619c10d7 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Tue, 16 Jul 2019 21:28:16 +0200 Subject: [PATCH 04/34] [nodes][aliceVision] DepthMapFilter: add new pixToleranceFactor param --- meshroom/nodes/aliceVision/DepthMapFilter.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/meshroom/nodes/aliceVision/DepthMapFilter.py b/meshroom/nodes/aliceVision/DepthMapFilter.py index a4f2ed5d..af78f805 100644 --- a/meshroom/nodes/aliceVision/DepthMapFilter.py +++ b/meshroom/nodes/aliceVision/DepthMapFilter.py @@ -68,6 +68,15 @@ class DepthMapFilter(desc.CommandLineNode): range=(0, 10, 1), 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( name="pixSizeBall", label="Filtering Size in Pixels", From 3ab83ec710af858c7dc7481424c5aad05f251877 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Tue, 1 Oct 2019 16:08:03 +0200 Subject: [PATCH 05/34] [nodes] DepthMap: fix labels of the 2 "step" params --- meshroom/nodes/aliceVision/DepthMap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meshroom/nodes/aliceVision/DepthMap.py b/meshroom/nodes/aliceVision/DepthMap.py index ba14361d..2da0cfcf 100644 --- a/meshroom/nodes/aliceVision/DepthMap.py +++ b/meshroom/nodes/aliceVision/DepthMap.py @@ -62,7 +62,7 @@ class DepthMap(desc.CommandLineNode): ), desc.IntParam( name='sgmStepXY', - label='SGM: Step', + 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), @@ -70,7 +70,7 @@ class DepthMap(desc.CommandLineNode): ), desc.IntParam( name='sgmStepZ', - label='SGM: Step', + label='SGM: Step Z', description='Semi Global Matching: Step used to compute the similarity volume on Z axis.', value=-1, range=(-1, 10, 1), From 1653bb9c4ca6b57413eb51fa6084ca5585ed5d0d Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Wed, 23 Oct 2019 16:03:26 +0200 Subject: [PATCH 06/34] [nodes] StructureFromMotion: expose new parameters minNbCamerasToRefinePrincipalPoint and rigMinNbCamerasForCalibration --- .../nodes/aliceVision/StructureFromMotion.py | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/meshroom/nodes/aliceVision/StructureFromMotion.py b/meshroom/nodes/aliceVision/StructureFromMotion.py index e592df55..6dd269b8 100644 --- a/meshroom/nodes/aliceVision/StructureFromMotion.py +++ b/meshroom/nodes/aliceVision/StructureFromMotion.py @@ -198,15 +198,36 @@ class StructureFromMotion(desc.CommandLineNode): uid=[0], advanced=True, ), + desc.IntParam( + name='rigMinNbCamerasForCalibration', + label='Min Nb Cameras For Rig Calibration', + description='Minimal number of cameras to start the calibration of the rig', + value=20, + range=(1, 50, 1), + uid=[0], + advanced=True, + ), desc.BoolParam( name='lockAllIntrinsics', - label='Force Lock of All Intrinsic Camera Parameters.', + label='Force Lock of All Intrinsic Camera Parameters', description='Force to keep constant all the intrinsics parameters of the cameras (focal length, \n' 'principal point, distortion if any) during the reconstruction.\n' 'This may be helpful if the input cameras are already fully calibrated.', value=False, uid=[0], ), + desc.IntParam( + name='minNbCamerasToRefinePrincipalPoint', + label='Min Nb Cameras To Refine Principal Point', + description='Minimal number of cameras to refine the principal point of the cameras (one of the intrinsic parameters of the camera). ' + 'If we do not have enough cameras, the principal point in consider is considered in the center of the image. ' + 'If minNbCamerasToRefinePrincipalPoint<=0, the principal point is never refined. ' + 'If minNbCamerasToRefinePrincipalPoint==1, the principal point is always refined.', + value=3, + range=(0, 20, 1), + uid=[0], + advanced=True, + ), desc.File( name='initialPairA', label='Initial Pair A', From 0cdc5540edefcb3201a97959af9c8381ffd068ad Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Tue, 5 Nov 2019 11:58:18 +0100 Subject: [PATCH 07/34] [nodes] add new node SfMDistances --- meshroom/nodes/aliceVision/SfMDistances.py | 67 ++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 meshroom/nodes/aliceVision/SfMDistances.py diff --git a/meshroom/nodes/aliceVision/SfMDistances.py b/meshroom/nodes/aliceVision/SfMDistances.py new file mode 100644 index 00000000..24ab2354 --- /dev/null +++ b/meshroom/nodes/aliceVision/SfMDistances.py @@ -0,0 +1,67 @@ +__version__ = "3.0" + +from meshroom.core import desc + + +class SfMDistances(desc.CommandLineNode): + commandLine = 'aliceVision_utils_sfmDistances {allParams}' + size = desc.DynamicNodeSize('input') + + inputs = [ + desc.File( + name='input', + label='Input', + description='''SfMData file.''', + value='', + uid=[0], + ), + desc.ChoiceParam( + name='objectType', + label='Type', + description='', + value='landmarks', + values=['landmarks', 'cameras'], + exclusive=True, + uid=[0], + ), + desc.ChoiceParam( + name='landmarksDescriberTypes', + label='Describer Types', + description='Describer types used to describe an image (only used when using "landmarks").', + value=['cctag3'], + values=['sift', 'sift_float', 'sift_upright', 'akaze', 'akaze_liop', 'akaze_mldb', 'cctag3', 'cctag4', 'sift_ocv', 'akaze_ocv'], + exclusive=False, + uid=[0], + joinChar=',', + ), + desc.StringParam( + name='A', + label='A IDs', + description='It will display the distances between A and B elements.\n' + 'This value should be an ID or a list of IDs of landmarks IDs or cameras (UID or filename without extension).\n' + 'It will list all elements if empty.', + value='', + uid=[0], + ), + desc.StringParam( + name='B', + label='B IDs', + description='It will display the distances between A and B elements.\n' + 'This value should be an ID or a list of IDs of landmarks IDs or cameras (UID or filename without extension).\n' + 'It will list all elements if empty.', + value='', + uid=[0], + ), + desc.ChoiceParam( + name='verboseLevel', + label='Verbose Level', + description='''verbosity level (fatal, error, warning, info, debug, trace).''', + value='info', + values=['fatal', 'error', 'warning', 'info', 'debug', 'trace'], + exclusive=True, + uid=[], + ), + ] + + outputs = [ + ] From 0b36d0dc85f23a086570269edfe05dd449088e2a Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Tue, 5 Nov 2019 11:58:59 +0100 Subject: [PATCH 08/34] [nodes] SfMTransform: update param tooltip --- meshroom/nodes/aliceVision/SfMTransform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meshroom/nodes/aliceVision/SfMTransform.py b/meshroom/nodes/aliceVision/SfMTransform.py index 6a9a975a..96592aa0 100644 --- a/meshroom/nodes/aliceVision/SfMTransform.py +++ b/meshroom/nodes/aliceVision/SfMTransform.py @@ -34,7 +34,7 @@ class SfMTransform(desc.CommandLineNode): label='Transformation', description="Required only for 'transformation' and 'from_single_camera' methods:\n" " * transformation: Align [X,Y,Z] to +Y-axis, rotate around Y by R deg, scale by S; syntax: X,Y,Z;R;S\n" - " * from_single_camera: Camera UID or image filename", + " * from_single_camera: Camera UID or simplified regular expression to match image filepath (like '*camera2*.jpg')", value='', uid=[0], ), From 59bdd51b74611daa587b8f7c8fa338a442c7f80b Mon Sep 17 00:00:00 2001 From: Guillaume Buisson Date: Mon, 21 Oct 2019 15:58:36 +0200 Subject: [PATCH 09/34] [nodes] new ImageMasking node --- meshroom/nodes/aliceVision/ImageMasking.py | 73 ++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 meshroom/nodes/aliceVision/ImageMasking.py diff --git a/meshroom/nodes/aliceVision/ImageMasking.py b/meshroom/nodes/aliceVision/ImageMasking.py new file mode 100644 index 00000000..bdd2891c --- /dev/null +++ b/meshroom/nodes/aliceVision/ImageMasking.py @@ -0,0 +1,73 @@ +__version__ = "3.0" + +from meshroom.core import desc + + +class ImageMasking(desc.CommandLineNode): + commandLine = 'aliceVision_imageMasking {allParams}' + size = desc.DynamicNodeSize('input') + parallelization = desc.Parallelization(blockSize=40) + commandLineRange = '--rangeStart {rangeStart} --rangeSize {rangeBlockSize}' + + inputs = [ + desc.File( + name='input', + label='Input', + description='''SfMData file.''', + value='', + uid=[0], + ), + #desc.GroupAttribute( + # name="colour", + # label="Keyed Colour", + # description="", + # groupDesc=[ + # desc.FloatParam(name="r", label="r", description="", value=0, uid=[0], range=(0, 1, 0.01)), + # desc.FloatParam(name="g", label="g", description="", value=0, uid=[0], range=(0, 1, 0.01)), + # desc.FloatParam(name="b", label="b", description="", value=0, uid=[0], range=(0, 1, 0.01)), + # ]), + desc.ChoiceParam( + name='algorithm', + label='Algorithm', + description='', + value='hsv', + values=['hsv'], + exclusive=True, + uid=[0], + ), + desc.FloatParam( + name='hue', + label='Hue', + description='Hue value to isolate in [0,1] range. 0 = red, 0.33 = green, 0.66 = blue, 1 = red.', + value=0.33, + range=(0, 1, 0.01), + uid=[0] + ), + desc.FloatParam( + name='hueRange', + label='Tolerance', + description='Tolerance around the hue value to isolate.', + value=0.1, + range=(0, 1, 0.01), + uid=[0] + ), + desc.ChoiceParam( + name='verboseLevel', + label='Verbose Level', + description='''verbosity level (fatal, error, warning, info, debug, trace).''', + value='info', + values=['fatal', 'error', 'warning', 'info', 'debug', 'trace'], + exclusive=True, + uid=[], + ), + ] + + outputs = [ + desc.File( + name='output', + label='Output', + description='''Output folder.''', + value=desc.Node.internalFolder, + uid=[], + ), + ] From 064d76de3de441ed74208f8b15f1779891a41b0b Mon Sep 17 00:00:00 2001 From: Guillaume Buisson Date: Fri, 15 Nov 2019 16:36:32 +0100 Subject: [PATCH 10/34] [attribute] refactor attribute/desc to customize command line arguments formatting --- meshroom/core/attribute.py | 19 +-------- meshroom/core/desc.py | 79 ++++++++++++++++++++++++++++---------- meshroom/core/node.py | 30 +++++++-------- 3 files changed, 74 insertions(+), 54 deletions(-) diff --git a/meshroom/core/attribute.py b/meshroom/core/attribute.py index 1bc105a2..496201c0 100644 --- a/meshroom/core/attribute.py +++ b/meshroom/core/attribute.py @@ -191,13 +191,8 @@ class Attribute(BaseObject): return self.desc.value return self._value - def getValueStr(self): - if isinstance(self.attributeDesc, desc.ChoiceParam) and not self.attributeDesc.exclusive: - assert(isinstance(self.value, collections.Sequence) and not isinstance(self.value, pyCompatibility.basestring)) - return self.attributeDesc.joinChar.join(self.value) - if isinstance(self.attributeDesc, (desc.StringParam, desc.File)): - return '"{}"'.format(self.value) - return str(self.value) + def format(self): + return self.desc.format(self.value) def defaultValue(self): return self.desc.value @@ -332,11 +327,6 @@ class ListAttribute(Attribute): else: return [attr.getPrimitiveValue(exportDefault=exportDefault) for attr in self._value if not attr.isDefault] - def getValueStr(self): - if isinstance(self.value, ListModel): - return self.attributeDesc.joinChar.join([v.getValueStr() for v in self.value]) - return super(ListAttribute, self).getValueStr() - # Override value property setter value = Property(Variant, Attribute._get_value, _set_value, notify=Attribute.valueChanged) isDefault = Property(bool, _isDefault, notify=Attribute.valueChanged) @@ -413,11 +403,6 @@ class GroupAttribute(Attribute): else: return {name: attr.getPrimitiveValue(exportDefault=exportDefault) for name, attr in self._value.items() if not attr.isDefault} - def getValueStr(self): - # sort values based on child attributes group description order - sortedSubValues = [self._value.get(attr.name).getValueStr() for attr in self.attributeDesc.groupDesc] - return self.attributeDesc.joinChar.join(sortedSubValues) - # Override value property value = Property(Variant, Attribute._get_value, _set_value, notify=Attribute.valueChanged) isDefault = Property(bool, _isDefault, notify=Attribute.valueChanged) diff --git a/meshroom/core/desc.py b/meshroom/core/desc.py index a9a96a10..9f44130a 100755 --- a/meshroom/core/desc.py +++ b/meshroom/core/desc.py @@ -1,4 +1,4 @@ -from meshroom.common import BaseObject, Property, Variant, VariantList +from meshroom.common import BaseObject, Property, Variant, VariantList, ListModel from meshroom.core import pyCompatibility from enum import Enum # available by default in python3. For python2: "pip install enum34" import collections @@ -11,7 +11,7 @@ class Attribute(BaseObject): """ """ - def __init__(self, name, label, description, value, advanced, uid, group): + def __init__(self, name, label, description, value, advanced, uid, group, formatter): super(Attribute, self).__init__() self._name = name self._label = label @@ -20,6 +20,7 @@ class Attribute(BaseObject): self._uid = uid self._group = group self._advanced = advanced + self._formatter = formatter or self._defaultFormatter name = Property(str, lambda self: self._name, constant=True) label = Property(str, lambda self: self._label, constant=True) @@ -45,17 +46,33 @@ class Attribute(BaseObject): except ValueError: return False return True + + def format(self, value): + """ Returns a list of (group, name, value) parameters """ + return self._formatter(self, value) + + @staticmethod + def _defaultFormatter(desc, value): + result_value = value + if isinstance(desc, ChoiceParam) and not desc.exclusive: + assert(isinstance(value, collections.Sequence) and not isinstance(value, pyCompatibility.basestring)) + result_value = desc.joinChar.join(value) + elif isinstance(desc, (StringParam, File)): + result_value = '"{}"'.format(value) + else: + result_value = str(value) + return ((desc.group, desc.name, result_value),) class ListAttribute(Attribute): """ A list of Attributes """ - def __init__(self, elementDesc, name, label, description, group='allParams', advanced=False, joinChar=' '): + def __init__(self, elementDesc, name, label, description, group='allParams', advanced=False, joinChar=' ', formatter=None): """ :param elementDesc: the Attribute description of elements to store in that list """ self._elementDesc = elementDesc self._joinChar = joinChar - super(ListAttribute, self).__init__(name=name, label=label, description=description, value=[], uid=(), group=group, advanced=advanced) + super(ListAttribute, self).__init__(name=name, label=label, description=description, value=[], uid=(), group=group, advanced=advanced, formatter=formatter) elementDesc = Property(Attribute, lambda self: self._elementDesc, constant=True) uid = Property(Variant, lambda self: self.elementDesc.uid, constant=True) @@ -75,16 +92,23 @@ class ListAttribute(Attribute): return self._elementDesc.matchDescription(value[0]) return True + @staticmethod + def _defaultFormatter(desc, value): + result_value = value + if isinstance(value, ListModel): + result_value = desc.joinChar.join([subv for v in value for _, _, subv in v.format()]) + return Attribute._defaultFormatter(desc, result_value) + class GroupAttribute(Attribute): """ A macro Attribute composed of several Attributes """ - def __init__(self, groupDesc, name, label, description, group='allParams', advanced=False, joinChar=' '): + def __init__(self, groupDesc, name, label, description, group='allParams', advanced=False, joinChar=' ', formatter=None): """ :param groupDesc: the description of the Attributes composing this group """ self._groupDesc = groupDesc self._joinChar = joinChar - super(GroupAttribute, self).__init__(name=name, label=label, description=description, value={}, uid=(), group=group, advanced=advanced) + super(GroupAttribute, self).__init__(name=name, label=label, description=description, value={}, uid=(), group=group, advanced=advanced, formatter=formatter) groupDesc = Property(Variant, lambda self: self._groupDesc, constant=True) @@ -120,6 +144,21 @@ class GroupAttribute(Attribute): allUids.extend(desc.uid) return allUids + @staticmethod + def _defaultFormatter(desc, value): + # sort values based on child attributes group description order + sortedSubValues = [subv for attr in desc.groupDesc for _, _, subv in value.get(attr.name).format()] + result_value = desc.joinChar.join(sortedSubValues) + return Attribute._defaultFormatter(desc, result_value) + + @staticmethod + def prefixFormatter(desc, value): + return [(group, desc.joinChar.join((desc.name, name)), v) for attr in desc.groupDesc for group, name, v in value.get(attr.name).format()] + + @staticmethod + def passthroughFormatter(desc, value): + return [item for attr in desc.groupDesc for item in value.get(attr.name).format()] + uid = Property(Variant, retrieveChildrenUids, constant=True) joinChar = Property(str, lambda self: self._joinChar, constant=True) @@ -127,15 +166,15 @@ class GroupAttribute(Attribute): class Param(Attribute): """ """ - def __init__(self, name, label, description, value, uid, group, advanced): - super(Param, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced) + def __init__(self, name, label, description, value, uid, group, advanced, formatter=None): + super(Param, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, formatter=formatter) class File(Attribute): """ """ - def __init__(self, name, label, description, value, uid, group='allParams', advanced=False): - super(File, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced) + def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, formatter=None): + super(File, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, formatter=formatter) def validateValue(self, value): if not isinstance(value, pyCompatibility.basestring): @@ -146,8 +185,8 @@ class File(Attribute): class BoolParam(Param): """ """ - def __init__(self, name, label, description, value, uid, group='allParams', advanced=False): - super(BoolParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced) + def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, formatter=None): + super(BoolParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, formatter=formatter) def validateValue(self, value): try: @@ -159,9 +198,9 @@ class BoolParam(Param): class IntParam(Param): """ """ - def __init__(self, name, label, description, value, range, uid, group='allParams', advanced=False): + def __init__(self, name, label, description, value, range, uid, group='allParams', advanced=False, formatter=None): self._range = range - super(IntParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced) + super(IntParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, formatter=formatter) def validateValue(self, value): # handle unsigned int values that are translated to int by shiboken and may overflow @@ -178,9 +217,9 @@ class IntParam(Param): class FloatParam(Param): """ """ - def __init__(self, name, label, description, value, range, uid, group='allParams', advanced=False): + def __init__(self, name, label, description, value, range, uid, group='allParams', advanced=False, formatter=None): self._range = range - super(FloatParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced) + super(FloatParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, formatter=formatter) def validateValue(self, value): try: @@ -194,13 +233,13 @@ class FloatParam(Param): class ChoiceParam(Param): """ """ - def __init__(self, name, label, description, value, values, exclusive, uid, group='allParams', joinChar=' ', advanced=False): + def __init__(self, name, label, description, value, values, exclusive, uid, group='allParams', joinChar=' ', advanced=False, formatter=None): assert values self._values = values self._exclusive = exclusive self._joinChar = joinChar self._valueType = type(self._values[0]) # cast to value type - super(ChoiceParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced) + super(ChoiceParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, formatter=formatter) def conformValue(self, val): """ Conform 'val' to the correct type and check for its validity """ @@ -225,8 +264,8 @@ class ChoiceParam(Param): class StringParam(Param): """ """ - def __init__(self, name, label, description, value, uid, group='allParams', advanced=False): - super(StringParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced) + def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, formatter=None): + super(StringParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, formatter=formatter) def validateValue(self, value): if not isinstance(value, pyCompatibility.basestring): diff --git a/meshroom/core/node.py b/meshroom/core/node.py index f2e98a2d..2a7b0f91 100644 --- a/meshroom/core/node.py +++ b/meshroom/core/node.py @@ -453,18 +453,19 @@ class BaseNode(BaseObject): for uidIndex, value in self._uids.items(): self._cmdVars['uid{}'.format(uidIndex)] = value + def populate(cmdVars, group, name, value): + cmdVars[name] = '--{name} {value}'.format(name=name, value=value) + cmdVars[name + 'Value'] = str(v) + if v: + cmdVars[group] = cmdVars.get(group, '') + ' ' + cmdVars[name] + # Evaluate input params - for name, attr in self._attributes.objects.items(): + for _, attr in self._attributes.objects.items(): if attr.isOutput: continue # skip outputs - v = attr.getValueStr() - - self._cmdVars[name] = '--{name} {value}'.format(name=name, value=v) - self._cmdVars[name + 'Value'] = str(v) - - if v: - self._cmdVars[attr.attributeDesc.group] = self._cmdVars.get(attr.attributeDesc.group, '') + \ - ' ' + self._cmdVars[name] + group_name_values = attr.format() + for group, name, v in group_name_values: + populate(self._cmdVars, group, name, v) # For updating output attributes invalidation values cmdVarsNoCache = self._cmdVars.copy() @@ -476,14 +477,9 @@ class BaseNode(BaseObject): continue # skip inputs attr.value = attr.attributeDesc.value.format(**self._cmdVars) attr._invalidationValue = attr.attributeDesc.value.format(**cmdVarsNoCache) - v = attr.getValueStr() - - self._cmdVars[name] = '--{name} {value}'.format(name=name, value=v) - self._cmdVars[name + 'Value'] = str(v) - - if v: - self._cmdVars[attr.attributeDesc.group] = self._cmdVars.get(attr.attributeDesc.group, '') + \ - ' ' + self._cmdVars[name] + group_name_values = attr.format() + for group, name, v in group_name_values: + populate(self._cmdVars, group, name, v) @property def isParallelized(self): From b9ea7934ee49f92199ed4d506375877b6f8a7c54 Mon Sep 17 00:00:00 2001 From: Guillaume Buisson Date: Fri, 15 Nov 2019 16:37:54 +0100 Subject: [PATCH 11/34] [nodes] update imageMasking featureExtraction and prepareDenseScene --- .../nodes/aliceVision/FeatureExtraction.py | 7 ++ meshroom/nodes/aliceVision/ImageMasking.py | 96 +++++++++++++++---- .../nodes/aliceVision/PrepareDenseScene.py | 12 +++ 3 files changed, 94 insertions(+), 21 deletions(-) diff --git a/meshroom/nodes/aliceVision/FeatureExtraction.py b/meshroom/nodes/aliceVision/FeatureExtraction.py index e5c1cfd4..03bc07a3 100644 --- a/meshroom/nodes/aliceVision/FeatureExtraction.py +++ b/meshroom/nodes/aliceVision/FeatureExtraction.py @@ -17,6 +17,13 @@ class FeatureExtraction(desc.CommandLineNode): value='', uid=[0], ), + desc.File( + name='masksFolder', + label='Masks Folder', + description='Use masks to filter features. Filename should be the same or the image uid.', + value='', + uid=[0], + ), desc.ChoiceParam( name='describerTypes', label='Describer Types', diff --git a/meshroom/nodes/aliceVision/ImageMasking.py b/meshroom/nodes/aliceVision/ImageMasking.py index bdd2891c..457016e9 100644 --- a/meshroom/nodes/aliceVision/ImageMasking.py +++ b/meshroom/nodes/aliceVision/ImageMasking.py @@ -17,15 +17,6 @@ class ImageMasking(desc.CommandLineNode): value='', uid=[0], ), - #desc.GroupAttribute( - # name="colour", - # label="Keyed Colour", - # description="", - # groupDesc=[ - # desc.FloatParam(name="r", label="r", description="", value=0, uid=[0], range=(0, 1, 0.01)), - # desc.FloatParam(name="g", label="g", description="", value=0, uid=[0], range=(0, 1, 0.01)), - # desc.FloatParam(name="b", label="b", description="", value=0, uid=[0], range=(0, 1, 0.01)), - # ]), desc.ChoiceParam( name='algorithm', label='Algorithm', @@ -35,20 +26,83 @@ class ImageMasking(desc.CommandLineNode): exclusive=True, uid=[0], ), - desc.FloatParam( - name='hue', - label='Hue', - description='Hue value to isolate in [0,1] range. 0 = red, 0.33 = green, 0.66 = blue, 1 = red.', - value=0.33, - range=(0, 1, 0.01), + desc.GroupAttribute( + name="hsv", + label="HSV Parameters", + description="", + formatter=desc.GroupAttribute.prefixFormatter, + joinChar='-', + groupDesc=[ + desc.FloatParam( + name='hue', + label='Hue', + description='Hue value to isolate in [0,1] range. 0 = red, 0.33 = green, 0.66 = blue, 1 = red.', + value=0.33, + range=(0, 1, 0.01), + uid=[0] + ), + desc.FloatParam( + name='hueRange', + label='Tolerance', + description='Tolerance around the hue value to isolate.', + value=0.1, + range=(0, 1, 0.01), + uid=[0] + ), + desc.FloatParam( + name='minSaturation', + label='Min Saturation', + description='Hue is meaningless if saturation is low. Do not mask pixels below this threshold.', + value=0.3, + range=(0, 1, 0.01), + uid=[0] + ), + desc.FloatParam( + name='maxSaturation', + label='Max Saturation', + description='Do not mask pixels above this threshold. It might be useful to mask white/black pixels.', + value=1, + range=(0, 1, 0.01), + uid=[0] + ), + desc.FloatParam( + name='minValue', + label='Min Value', + description='Hue is meaningless if value is low. Do not mask pixels below this threshold.', + value=0.3, + range=(0, 1, 0.01), + uid=[0] + ), + desc.FloatParam( + name='maxValue', + label='Max Value', + description='Do not mask pixels above this threshold. It might be useful to mask white/black pixels.', + value=1, + range=(0, 1, 0.01), + uid=[0] + ), + ]), + desc.BoolParam( + name='invert', + label='Invert', + description='Invert the selected area.', + value=False, uid=[0] ), - desc.FloatParam( - name='hueRange', - label='Tolerance', - description='Tolerance around the hue value to isolate.', - value=0.1, - range=(0, 1, 0.01), + desc.IntParam( + name='growRadius', + label='Grow Radius', + description='Grow the selected area. It might be used to fill the holes: then use shrinkRadius to restore the initial coutours.', + value=0, + range=(0, 50, 1), + uid=[0] + ), + desc.IntParam( + name='shrinkRadius', + label='Shrink Radius', + description='Shrink the selected area.', + value=0, + range=(0, 50, 1), uid=[0] ), desc.ChoiceParam( diff --git a/meshroom/nodes/aliceVision/PrepareDenseScene.py b/meshroom/nodes/aliceVision/PrepareDenseScene.py index 5467d576..816305d6 100644 --- a/meshroom/nodes/aliceVision/PrepareDenseScene.py +++ b/meshroom/nodes/aliceVision/PrepareDenseScene.py @@ -29,6 +29,18 @@ class PrepareDenseScene(desc.CommandLineNode): label="Images Folders", description='Use images from specific folder(s). Filename should be the same or the image uid.', ), + desc.ListAttribute( + elementDesc=desc.File( + name="masksFolder", + label="Masks Folder", + description="", + value="", + uid=[0], + ), + name="masksFolders", + label="Masks Folders", + description='Use masks from specific folder(s). Filename should be the same or the image uid.', + ), desc.ChoiceParam( name='outputFileType', label='Output File Type', From 63d0cc3b833177e0bb1d7f29dcd0672807a28f4f Mon Sep 17 00:00:00 2001 From: Guillaume Buisson Date: Fri, 15 Nov 2019 17:19:03 +0100 Subject: [PATCH 12/34] [nodes] add semantic to customize attibute UI --- meshroom/core/desc.py | 40 ++++++++++--------- meshroom/nodes/aliceVision/ImageMasking.py | 1 + .../qml/GraphEditor/AttributeItemDelegate.qml | 39 +++++++++++++++++- 3 files changed, 60 insertions(+), 20 deletions(-) diff --git a/meshroom/core/desc.py b/meshroom/core/desc.py index 9f44130a..110b2e6f 100755 --- a/meshroom/core/desc.py +++ b/meshroom/core/desc.py @@ -11,7 +11,7 @@ class Attribute(BaseObject): """ """ - def __init__(self, name, label, description, value, advanced, uid, group, formatter): + def __init__(self, name, label, description, value, advanced, semantic, uid, group, formatter): super(Attribute, self).__init__() self._name = name self._label = label @@ -20,6 +20,7 @@ class Attribute(BaseObject): self._uid = uid self._group = group self._advanced = advanced + self._semantic = semantic self._formatter = formatter or self._defaultFormatter name = Property(str, lambda self: self._name, constant=True) @@ -29,6 +30,7 @@ class Attribute(BaseObject): uid = Property(Variant, lambda self: self._uid, constant=True) group = Property(str, lambda self: self._group, constant=True) advanced = Property(bool, lambda self: self._advanced, constant=True) + semantic = Property(str, lambda self: self._semantic, constant=True) type = Property(str, lambda self: self.__class__.__name__, constant=True) def validateValue(self, value): @@ -66,13 +68,13 @@ class Attribute(BaseObject): class ListAttribute(Attribute): """ A list of Attributes """ - def __init__(self, elementDesc, name, label, description, group='allParams', advanced=False, joinChar=' ', formatter=None): + def __init__(self, elementDesc, name, label, description, group='allParams', advanced=False, semantic='', joinChar=' ', formatter=None): """ :param elementDesc: the Attribute description of elements to store in that list """ self._elementDesc = elementDesc self._joinChar = joinChar - super(ListAttribute, self).__init__(name=name, label=label, description=description, value=[], uid=(), group=group, advanced=advanced, formatter=formatter) + super(ListAttribute, self).__init__(name=name, label=label, description=description, value=[], uid=(), group=group, advanced=advanced, semantic=semantic, formatter=formatter) elementDesc = Property(Attribute, lambda self: self._elementDesc, constant=True) uid = Property(Variant, lambda self: self.elementDesc.uid, constant=True) @@ -102,13 +104,13 @@ class ListAttribute(Attribute): class GroupAttribute(Attribute): """ A macro Attribute composed of several Attributes """ - def __init__(self, groupDesc, name, label, description, group='allParams', advanced=False, joinChar=' ', formatter=None): + def __init__(self, groupDesc, name, label, description, group='allParams', advanced=False, semantic='', joinChar=' ', formatter=None): """ :param groupDesc: the description of the Attributes composing this group """ self._groupDesc = groupDesc self._joinChar = joinChar - super(GroupAttribute, self).__init__(name=name, label=label, description=description, value={}, uid=(), group=group, advanced=advanced, formatter=formatter) + super(GroupAttribute, self).__init__(name=name, label=label, description=description, value={}, uid=(), group=group, advanced=advanced, semantic=semantic, formatter=formatter) groupDesc = Property(Variant, lambda self: self._groupDesc, constant=True) @@ -166,15 +168,15 @@ class GroupAttribute(Attribute): class Param(Attribute): """ """ - def __init__(self, name, label, description, value, uid, group, advanced, formatter=None): - super(Param, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, formatter=formatter) + def __init__(self, name, label, description, value, uid, group, advanced, semantic='', formatter=None): + super(Param, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, formatter=formatter) class File(Attribute): """ """ - def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, formatter=None): - super(File, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, formatter=formatter) + def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, semantic='', formatter=None): + super(File, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, formatter=formatter) def validateValue(self, value): if not isinstance(value, pyCompatibility.basestring): @@ -185,8 +187,8 @@ class File(Attribute): class BoolParam(Param): """ """ - def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, formatter=None): - super(BoolParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, formatter=formatter) + def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, semantic='', formatter=None): + super(BoolParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, formatter=formatter) def validateValue(self, value): try: @@ -198,9 +200,9 @@ class BoolParam(Param): class IntParam(Param): """ """ - def __init__(self, name, label, description, value, range, uid, group='allParams', advanced=False, formatter=None): + def __init__(self, name, label, description, value, range, uid, group='allParams', advanced=False, semantic='', formatter=None): self._range = range - super(IntParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, formatter=formatter) + super(IntParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, formatter=formatter) def validateValue(self, value): # handle unsigned int values that are translated to int by shiboken and may overflow @@ -217,9 +219,9 @@ class IntParam(Param): class FloatParam(Param): """ """ - def __init__(self, name, label, description, value, range, uid, group='allParams', advanced=False, formatter=None): + def __init__(self, name, label, description, value, range, uid, group='allParams', advanced=False, semantic='', formatter=None): self._range = range - super(FloatParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, formatter=formatter) + super(FloatParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, formatter=formatter) def validateValue(self, value): try: @@ -233,13 +235,13 @@ class FloatParam(Param): class ChoiceParam(Param): """ """ - def __init__(self, name, label, description, value, values, exclusive, uid, group='allParams', joinChar=' ', advanced=False, formatter=None): + def __init__(self, name, label, description, value, values, exclusive, uid, group='allParams', joinChar=' ', advanced=False, semantic='', formatter=None): assert values self._values = values self._exclusive = exclusive self._joinChar = joinChar self._valueType = type(self._values[0]) # cast to value type - super(ChoiceParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, formatter=formatter) + super(ChoiceParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, formatter=formatter) def conformValue(self, val): """ Conform 'val' to the correct type and check for its validity """ @@ -264,8 +266,8 @@ class ChoiceParam(Param): class StringParam(Param): """ """ - def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, formatter=None): - super(StringParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, formatter=formatter) + def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, semantic='', formatter=None): + super(StringParam, self).__init__(name=name, label=label, description=description,value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, formatter=formatter) def validateValue(self, value): if not isinstance(value, pyCompatibility.basestring): diff --git a/meshroom/nodes/aliceVision/ImageMasking.py b/meshroom/nodes/aliceVision/ImageMasking.py index 457016e9..4d441e92 100644 --- a/meshroom/nodes/aliceVision/ImageMasking.py +++ b/meshroom/nodes/aliceVision/ImageMasking.py @@ -37,6 +37,7 @@ class ImageMasking(desc.CommandLineNode): name='hue', label='Hue', description='Hue value to isolate in [0,1] range. 0 = red, 0.33 = green, 0.66 = blue, 1 = red.', + semantic='color/hue', value=0.33, range=(0, 1, 0.01), uid=[0] diff --git a/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml b/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml index 795bd59d..ec711cf7 100644 --- a/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml +++ b/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml @@ -145,7 +145,10 @@ RowLayout { { case "ChoiceParam": return attribute.desc.exclusive ? comboBox_component : multiChoice_component case "IntParam": return slider_component - case "FloatParam": return slider_component + case "FloatParam": + if(attribute.desc.semantic === 'color/hue') + return color_hue_component + return slider_component case "BoolParam": return checkbox_component case "ListAttribute": return listAttribute_component case "GroupAttribute": return groupAttribute_component @@ -365,5 +368,39 @@ RowLayout { } } } + + Component { + id: color_hue_component + Slider { + readonly property int stepDecimalCount: 2 + readonly property real formattedValue: value.toFixed(stepDecimalCount) + enabled: root.editable + value: attribute.value + from: 0 + to: 1 + stepSize: 0.01 + snapMode: Slider.SnapAlways + onPressedChanged: { + if(!pressed) + _reconstruction.setAttribute(attribute, formattedValue) + } + + background: ShaderEffect { + width: control.availableWidth + height: control.availableHeight + blending: false + fragmentShader: " + varying mediump vec2 qt_TexCoord0; + vec3 hsv2rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); + } + void main() { + gl_FragColor = vec4(hsv2rgb(vec3(qt_TexCoord0.x, 1.0, 1.0)), 1.0); + }" + } + } + } } } From bb2dcaf7f5ec5deaca213e55a111fda866c1fee5 Mon Sep 17 00:00:00 2001 From: Guillaume Buisson Date: Wed, 20 Nov 2019 11:13:55 +0100 Subject: [PATCH 13/34] [attribute] hue semantic editor: add text editor and colored display --- .../qml/GraphEditor/AttributeItemDelegate.qml | 79 +++++++++++++------ 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml b/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml index ec711cf7..5955d227 100644 --- a/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml +++ b/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml @@ -371,34 +371,61 @@ RowLayout { Component { id: color_hue_component - Slider { - readonly property int stepDecimalCount: 2 - readonly property real formattedValue: value.toFixed(stepDecimalCount) - enabled: root.editable - value: attribute.value - from: 0 - to: 1 - stepSize: 0.01 - snapMode: Slider.SnapAlways - onPressedChanged: { - if(!pressed) - _reconstruction.setAttribute(attribute, formattedValue) + RowLayout { + TextField { + implicitWidth: 100 + enabled: root.editable + // cast value to string to avoid intrusive scientific notations on numbers + property string displayValue: String(slider.pressed ? slider.formattedValue : attribute.value) + text: displayValue + selectByMouse: true + validator: DoubleValidator { + locale: 'C' // use '.' decimal separator disregarding the system locale + } + onEditingFinished: setTextFieldAttribute(text) + onAccepted: setTextFieldAttribute(text) + Component.onDestruction: { + if(activeFocus) + setTextFieldAttribute(text) + } } + Rectangle { + height: slider.height + width: height + color: Qt.hsla(slider.pressed ? slider.formattedValue : attribute.value, 1, 0.5, 1) + } + Slider { + Layout.fillWidth: true - background: ShaderEffect { - width: control.availableWidth - height: control.availableHeight - blending: false - fragmentShader: " - varying mediump vec2 qt_TexCoord0; - vec3 hsv2rgb(vec3 c) { - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); - } - void main() { - gl_FragColor = vec4(hsv2rgb(vec3(qt_TexCoord0.x, 1.0, 1.0)), 1.0); - }" + id: slider + readonly property int stepDecimalCount: 2 + readonly property real formattedValue: value.toFixed(stepDecimalCount) + enabled: root.editable + value: attribute.value + from: 0 + to: 1 + stepSize: 0.01 + snapMode: Slider.SnapAlways + onPressedChanged: { + if(!pressed) + _reconstruction.setAttribute(attribute, formattedValue) + } + + background: ShaderEffect { + width: control.availableWidth + height: control.availableHeight + blending: false + fragmentShader: " + varying mediump vec2 qt_TexCoord0; + vec3 hsv2rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); + } + void main() { + gl_FragColor = vec4(hsv2rgb(vec3(qt_TexCoord0.x, 1.0, 1.0)), 1.0); + }" + } } } } From 04df44b5956cd0bc7c32532f1422ac999c4f9b1b Mon Sep 17 00:00:00 2001 From: Guillaume Buisson Date: Thu, 21 Nov 2019 08:56:37 +0100 Subject: [PATCH 14/34] [nodes] add image masking description --- meshroom/nodes/aliceVision/ImageMasking.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/meshroom/nodes/aliceVision/ImageMasking.py b/meshroom/nodes/aliceVision/ImageMasking.py index 4d441e92..05c8ddea 100644 --- a/meshroom/nodes/aliceVision/ImageMasking.py +++ b/meshroom/nodes/aliceVision/ImageMasking.py @@ -29,7 +29,11 @@ class ImageMasking(desc.CommandLineNode): desc.GroupAttribute( name="hsv", label="HSV Parameters", - description="", + description="""Values to select: + - Green: default values + - White: Tolerance = 1, minSaturation = 0, maxSaturation = 0.1, minValue = 0.8, maxValue = 1 + - Black: Tolerance = 1, minSaturation = 0, maxSaturation = 0.1, minValue = 0, maxValue = 0.2 + """, formatter=desc.GroupAttribute.prefixFormatter, joinChar='-', groupDesc=[ @@ -86,8 +90,9 @@ class ImageMasking(desc.CommandLineNode): desc.BoolParam( name='invert', label='Invert', - description='Invert the selected area.', - value=False, + description='''If ticked, the selected area is ignored. + If not, only the selected area is considered.''', + value=True, uid=[0] ), desc.IntParam( From 18be7cc15fd868123e969899c29b1001d400ef01 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Tue, 17 Dec 2019 22:35:58 +0100 Subject: [PATCH 15/34] [nodes] ImageMasking: add AutoGrayscaleThreshold algorithm and depthMap inputs --- meshroom/nodes/aliceVision/ImageMasking.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/meshroom/nodes/aliceVision/ImageMasking.py b/meshroom/nodes/aliceVision/ImageMasking.py index 05c8ddea..95de19f4 100644 --- a/meshroom/nodes/aliceVision/ImageMasking.py +++ b/meshroom/nodes/aliceVision/ImageMasking.py @@ -21,8 +21,8 @@ class ImageMasking(desc.CommandLineNode): name='algorithm', label='Algorithm', description='', - value='hsv', - values=['hsv'], + value='HSV', + values=['HSV', 'AutoGrayscaleThreshold'], exclusive=True, uid=[0], ), @@ -111,6 +111,20 @@ class ImageMasking(desc.CommandLineNode): range=(0, 50, 1), uid=[0] ), + desc.File( + name='depthMapFolder', + label='Depth Mask Folder', + description='''Depth Mask Folder''', + value='', + uid=[0], + ), + desc.File( + name='depthMapExp', + label='Depth Mask Expression', + description='''Depth Mask Expression, like "{inputFolder}/{stem}-depth.{ext}".''', + value='', + uid=[0], + ), desc.ChoiceParam( name='verboseLevel', label='Verbose Level', From 0d70a07e268909009e1a4adc80976e853cb46099 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Wed, 18 Dec 2019 09:33:23 +0100 Subject: [PATCH 16/34] [nodes] ImageMasking: use StringParam instead of FileParam for depthMapExp --- meshroom/nodes/aliceVision/ImageMasking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meshroom/nodes/aliceVision/ImageMasking.py b/meshroom/nodes/aliceVision/ImageMasking.py index 95de19f4..41504dd3 100644 --- a/meshroom/nodes/aliceVision/ImageMasking.py +++ b/meshroom/nodes/aliceVision/ImageMasking.py @@ -118,7 +118,7 @@ class ImageMasking(desc.CommandLineNode): value='', uid=[0], ), - desc.File( + desc.StringParam( name='depthMapExp', label='Depth Mask Expression', description='''Depth Mask Expression, like "{inputFolder}/{stem}-depth.{ext}".''', From 2b658c1c16fd4a1d18904ad3a9287975608799bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20De=20Lillo?= Date: Mon, 15 Nov 2021 17:10:45 +0100 Subject: [PATCH 17/34] [nodes] DepthMap: Change P2 default value to 100 --- meshroom/nodes/aliceVision/DepthMap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meshroom/nodes/aliceVision/DepthMap.py b/meshroom/nodes/aliceVision/DepthMap.py index a3f46bd9..dbccfe66 100644 --- a/meshroom/nodes/aliceVision/DepthMap.py +++ b/meshroom/nodes/aliceVision/DepthMap.py @@ -144,7 +144,7 @@ Use a downscale factor of one (full-resolution) only if the quality of the input name='sgmP2', label='SGM: P2', description='Semi Global Matching: P2 weight.', - value=20.0, + value=100.0, range=(-255.0, 255.0, 0.5), uid=[0], advanced=True, From a70f14dfc61c08ee4a9cea28daddbea8183d470a Mon Sep 17 00:00:00 2001 From: Simone Gasparini Date: Wed, 17 Nov 2021 19:08:13 +0100 Subject: [PATCH 18/34] [doc] fix author in bibtex --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb5ec25b..c1de1271 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ If you use this project for a publication, please cite the [paper](https://hal.a ``` @inproceedings{alicevision2021, 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}}, doi = {10.1145/3458305.3478443}, publisher = {ACM Press}, From 98904ce4bc41663758e9dffd29ce242a94913433 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 14 Dec 2021 21:20:39 +0100 Subject: [PATCH 19/34] minor doc text improvement --- meshroom/nodes/aliceVision/Split360Images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meshroom/nodes/aliceVision/Split360Images.py b/meshroom/nodes/aliceVision/Split360Images.py index 2b351b78..daee4598 100644 --- a/meshroom/nodes/aliceVision/Split360Images.py +++ b/meshroom/nodes/aliceVision/Split360Images.py @@ -6,7 +6,7 @@ class Split360Images(desc.CommandLineNode): commandLine = 'aliceVision_utils_split360Images {allParams}' 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 = [ desc.File( From f4dcf6557f0e29402e178b1b0dd63f8e4bba178d Mon Sep 17 00:00:00 2001 From: luz paz Date: Sat, 22 Jan 2022 07:39:05 -0500 Subject: [PATCH 20/34] Fix various typos in the source code ## Description Fix various typos in the source code. This includes user facing code, documentation, and source comments. This PR has not been tested. Closes #1605 --- meshroom/multiview.py | 4 ++-- meshroom/nodes/aliceVision/ColorCheckerDetection.py | 2 +- meshroom/nodes/aliceVision/FeatureMatching.py | 2 +- meshroom/nodes/aliceVision/PanoramaSeams.py | 2 +- meshroom/nodes/aliceVision/SketchfabUpload.py | 2 +- meshroom/nodes/aliceVision/StructureFromMotion.py | 2 +- meshroom/nodes/aliceVision/Texturing.py | 2 +- .../nodes/blender/scripts/renderAnimatedCameraInBlender.py | 6 +++--- meshroom/ui/graph.py | 2 +- meshroom/ui/qml/Controls/MessageDialog.qml | 2 +- meshroom/ui/qml/DialogsFactory.qml | 2 +- meshroom/ui/qml/GraphEditor/GraphEditor.qml | 2 +- meshroom/ui/qml/Utils/SortFilterDelegateModel.qml | 4 ++-- meshroom/ui/qml/Utils/request.js | 2 +- meshroom/ui/qml/Viewer/ColorCheckerEntity.qml | 4 ++-- meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml | 6 +++--- .../ui/qml/Viewer3D/Materials/shaders/robustwireframe.geom | 2 +- meshroom/ui/qml/Viewer3D/MediaLibrary.qml | 6 +++--- meshroom/ui/qml/WorkspaceView.qml | 2 +- meshroom/ui/qml/main.qml | 2 +- meshroom/ui/utils.py | 2 +- 21 files changed, 30 insertions(+), 30 deletions(-) diff --git a/meshroom/multiview.py b/meshroom/multiview.py index c85dc79f..b8ad1821 100644 --- a/meshroom/multiview.py +++ b/meshroom/multiview.py @@ -136,7 +136,7 @@ def findFilesByTypeInFolder(folder, recursive=False): else: output.addFiles([os.path.join(currentFolder, filename) for filename in os.listdir(currentFolder)]) 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 paths = glob.glob(currentFolder) 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' featureExtraction.attribute("describerTypes").value = ['sift'] # 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' return graph diff --git a/meshroom/nodes/aliceVision/ColorCheckerDetection.py b/meshroom/nodes/aliceVision/ColorCheckerDetection.py index f33c653a..f3109cfe 100644 --- a/meshroom/nodes/aliceVision/ColorCheckerDetection.py +++ b/meshroom/nodes/aliceVision/ColorCheckerDetection.py @@ -17,7 +17,7 @@ Performs Macbeth color checker chart detection. Outputs: - 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: (0, 0), (1675, 0), (1675, 1125), (0, 1125) diff --git a/meshroom/nodes/aliceVision/FeatureMatching.py b/meshroom/nodes/aliceVision/FeatureMatching.py index fdd4f634..831dda2d 100644 --- a/meshroom/nodes/aliceVision/FeatureMatching.py +++ b/meshroom/nodes/aliceVision/FeatureMatching.py @@ -170,7 +170,7 @@ then it checks the number of features that validates this model and iterate thro desc.BoolParam( name='crossMatching', 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, uid=[0], ), diff --git a/meshroom/nodes/aliceVision/PanoramaSeams.py b/meshroom/nodes/aliceVision/PanoramaSeams.py index 326d7959..c36beb92 100644 --- a/meshroom/nodes/aliceVision/PanoramaSeams.py +++ b/meshroom/nodes/aliceVision/PanoramaSeams.py @@ -43,7 +43,7 @@ Estimate the seams lines between the inputs to provide an optimal compositing in desc.BoolParam( name='useGraphCut', 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, uid=[0], ), diff --git a/meshroom/nodes/aliceVision/SketchfabUpload.py b/meshroom/nodes/aliceVision/SketchfabUpload.py index 2d980e4d..69d75aa2 100644 --- a/meshroom/nodes/aliceVision/SketchfabUpload.py +++ b/meshroom/nodes/aliceVision/SketchfabUpload.py @@ -200,7 +200,7 @@ Upload a textured mesh on Sketchfab. modelEndpoint, **{'data': body, 'headers': headers}) chunk.logManager.completeProgressBar() 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() if r.status_code != requests.codes.created: chunk.logger.error(u'Upload failed with error: {}'.format(r.json())) diff --git a/meshroom/nodes/aliceVision/StructureFromMotion.py b/meshroom/nodes/aliceVision/StructureFromMotion.py index d029656d..2db4aeb4 100644 --- a/meshroom/nodes/aliceVision/StructureFromMotion.py +++ b/meshroom/nodes/aliceVision/StructureFromMotion.py @@ -116,7 +116,7 @@ It iterates like that, adding cameras and triangulating new 2D features into 3D desc.ChoiceParam( name='observationConstraint', 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' ' * Scale: Use reprojection error in pixel coordinates but relative to the feature scale', value='Scale', diff --git a/meshroom/nodes/aliceVision/Texturing.py b/meshroom/nodes/aliceVision/Texturing.py index 894e6a2b..34ed45d4 100644 --- a/meshroom/nodes/aliceVision/Texturing.py +++ b/meshroom/nodes/aliceVision/Texturing.py @@ -273,7 +273,7 @@ Many cameras are contributing to the low frequencies and only the best ones cont desc.BoolParam( name='forceVisibleByAllVertices', 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, uid=[0], advanced=True, diff --git a/meshroom/nodes/blender/scripts/renderAnimatedCameraInBlender.py b/meshroom/nodes/blender/scripts/renderAnimatedCameraInBlender.py index 7549c990..e580aac3 100644 --- a/meshroom/nodes/blender/scripts/renderAnimatedCameraInBlender.py +++ b/meshroom/nodes/blender/scripts/renderAnimatedCameraInBlender.py @@ -31,7 +31,7 @@ def main(): parser.add_argument( "--useBackground", type=strtobool, required=True, - help="Diplay the background image or not.", + help="Display the background image or not.", ) 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: # 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. - # The more the thickness get bellow zero, the more the egde will be largely revealed. + # 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 below zero, the more the edge will be largely revealed. elif args.model.lower().endswith('.obj'): print("Import OBJ") diff --git a/meshroom/ui/graph.py b/meshroom/ui/graph.py index 3134e7a6..250abcd2 100644 --- a/meshroom/ui/graph.py +++ b/meshroom/ui/graph.py @@ -515,7 +515,7 @@ class UIGraph(QObject): @Slot(Node, QPoint, QObject) 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: node (Node): the node to move diff --git a/meshroom/ui/qml/Controls/MessageDialog.qml b/meshroom/ui/qml/Controls/MessageDialog.qml index cfb20df3..079bc202 100644 --- a/meshroom/ui/qml/Controls/MessageDialog.qml +++ b/meshroom/ui/qml/Controls/MessageDialog.qml @@ -20,7 +20,7 @@ Dialog { /// Return the text content of this dialog as a simple string. /// 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() { return asString } diff --git a/meshroom/ui/qml/DialogsFactory.qml b/meshroom/ui/qml/DialogsFactory.qml index 4a11f82b..f0ccaab8 100644 --- a/meshroom/ui/qml/DialogsFactory.qml +++ b/meshroom/ui/qml/DialogsFactory.qml @@ -7,7 +7,7 @@ import Controls 1.0 */ QtObject { - readonly property string defaultErrorText: "An unexpected error has occured" + readonly property string defaultErrorText: "An unexpected error has occurred" property Component infoDialog: Component { MessageDialog { diff --git a/meshroom/ui/qml/GraphEditor/GraphEditor.qml b/meshroom/ui/qml/GraphEditor/GraphEditor.qml index 7b7c14be..2d3591ab 100755 --- a/meshroom/ui/qml/GraphEditor/GraphEditor.qml +++ b/meshroom/ui/qml/GraphEditor/GraphEditor.qml @@ -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) { if (duplicateFollowingNodes) { var nodes = uigraph.duplicateNodesFrom(uigraph.selectedNodes) diff --git a/meshroom/ui/qml/Utils/SortFilterDelegateModel.qml b/meshroom/ui/qml/Utils/SortFilterDelegateModel.qml index 44fbfda1..29135b07 100644 --- a/meshroom/ui/qml/Utils/SortFilterDelegateModel.qml +++ b/meshroom/ui/qml/Utils/SortFilterDelegateModel.qml @@ -5,12 +5,12 @@ import QtQuick.Controls 2.3 /** * 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 * some extra logic. * * 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 */ diff --git a/meshroom/ui/qml/Utils/request.js b/meshroom/ui/qml/Utils/request.js index fba1a599..ffb5f2d6 100644 --- a/meshroom/ui/qml/Utils/request.js +++ b/meshroom/ui/qml/Utils/request.js @@ -1,7 +1,7 @@ .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) { var xhr = new XMLHttpRequest(); diff --git a/meshroom/ui/qml/Viewer/ColorCheckerEntity.qml b/meshroom/ui/qml/Viewer/ColorCheckerEntity.qml index 67e52768..385bb25c 100644 --- a/meshroom/ui/qml/Viewer/ColorCheckerEntity.qml +++ b/meshroom/ui/qml/Viewer/ColorCheckerEntity.qml @@ -4,8 +4,8 @@ Item { id: root // required for perspective transform - property real sizeX: 1675.0 // might be overrided in ColorCheckerViewer - property real sizeY: 1125.0 // might be overrided in ColorCheckerViewer + property real sizeX: 1675.0 // might be overridden in ColorCheckerViewer + property real sizeY: 1125.0 // might be overridden in ColorCheckerViewer property var colors: null property var window: null diff --git a/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml b/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml index 6f5e8038..d971c573 100644 --- a/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml +++ b/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml @@ -200,7 +200,7 @@ FloatingPane { font.pointSize: 10 opacity: featureType.viewer.visible ? 1.0 : 0.6 } - // Tracks visibility toogle + // Tracks visibility toggle MaterialToolButton { id: tracksVisibilityButton checkable: true @@ -213,7 +213,7 @@ FloatingPane { } font.pointSize: 10 } - // Matches visibility toogle + // Matches visibility toggle MaterialToolButton { id: matchesVisibilityButton checkable: true @@ -225,7 +225,7 @@ FloatingPane { } font.pointSize: 10 } - // Landmarks visibility toogle + // Landmarks visibility toggle MaterialToolButton { id: landmarksVisibilityButton checkable: true diff --git a/meshroom/ui/qml/Viewer3D/Materials/shaders/robustwireframe.geom b/meshroom/ui/qml/Viewer3D/Materials/shaders/robustwireframe.geom index 6eb0ecc7..86d0423c 100644 --- a/meshroom/ui/qml/Viewer3D/Materials/shaders/robustwireframe.geom +++ b/meshroom/ui/qml/Viewer3D/Materials/shaders/robustwireframe.geom @@ -94,7 +94,7 @@ void main() else { // 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 // in the fragment shader is still cheap as all concurrent // fragment shader invocations will take the same code path. diff --git a/meshroom/ui/qml/Viewer3D/MediaLibrary.qml b/meshroom/ui/qml/Viewer3D/MediaLibrary.qml index 624a579a..f3fa124f 100644 --- a/meshroom/ui/qml/Viewer3D/MediaLibrary.qml +++ b/meshroom/ui/qml/Viewer3D/MediaLibrary.qml @@ -21,7 +21,7 @@ Entity { property Layer frontLayerComponent property var window - /// Camera to consider for positionning + /// Camera to consider for positioning property Camera camera: null /// True while at least one media is being loaded @@ -190,7 +190,7 @@ Entity { // whether MediaLoader has been fully instantiated by the NodeInstantiator 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 int idx: index readonly property var modelSource: attribute || model.source @@ -216,7 +216,7 @@ Entity { 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) - // 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() { rawSource = Qt.binding(() => instantiatedEntity.currentNode ? instantiatedEntity.currentNode.attribute("input").value: "") currentSource = Qt.binding(() => rawSource) diff --git a/meshroom/ui/qml/WorkspaceView.qml b/meshroom/ui/qml/WorkspaceView.qml index d6291517..ced16fe2 100644 --- a/meshroom/ui/qml/WorkspaceView.qml +++ b/meshroom/ui/qml/WorkspaceView.qml @@ -120,7 +120,7 @@ Item { } Action { id: displayLensDistortionToolBarAction - text: "Display Lens Distorsion Toolbar" + text: "Display Lens Distortion Toolbar" checkable: true checked: true enabled: viewer2D.useLensDistortionViewer diff --git a/meshroom/ui/qml/main.qml b/meshroom/ui/qml/main.qml index e28a42b5..2b06ea18 100755 --- a/meshroom/ui/qml/main.qml +++ b/meshroom/ui/qml/main.qml @@ -613,7 +613,7 @@ ApplicationWindow { Action { text: "About Meshroom" 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) shortcut: "F1" } diff --git a/meshroom/ui/utils.py b/meshroom/ui/utils.py index cfdb3a55..700bb1b4 100755 --- a/meshroom/ui/utils.py +++ b/meshroom/ui/utils.py @@ -87,7 +87,7 @@ class QmlInstantEngine(QQmlApplicationEngine): self._extensions = extensions def setVerbose(self, verboseValue): - """ Activate (True) or desactivate (False) the verbose. """ + """ Activate (True) or deactivate (False) the verbose. """ self._verbose = verboseValue def addFile(self, filename): From 6f4541f76b712afde3aceef145d259a97da83878 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Sun, 6 Feb 2022 20:17:28 +0100 Subject: [PATCH 21/34] [core] add env var to load nodes from multiple folders New env var: MESHROOM_NODES_PATH --- meshroom/core/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/meshroom/core/__init__.py b/meshroom/core/__init__.py index 7f9760d3..968f620a 100644 --- a/meshroom/core/__init__.py +++ b/meshroom/core/__init__.py @@ -272,9 +272,15 @@ def loadSubmitters(folder, packageName): meshroomFolder = os.path.dirname(os.path.dirname(__file__)) +additionalNodesPath = os.environ.get("MESHROOM_NODES_PATH", "").split(os.pathsep) + # Load plugins: # - Nodes -loadAllNodes(folder=os.path.join(meshroomFolder, 'nodes')) +nodesFolders = [os.path.join(meshroomFolder, 'nodes')] + additionalNodesPath + +for f in nodesFolders: + loadAllNodes(folder=f) + # - Submitters subs = loadSubmitters(os.environ.get("MESHROOM_SUBMITTERS_PATH", meshroomFolder), 'submitters') From a99168448e2ffb4f185446754706bb6290bc3955 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 10 Feb 2022 00:20:16 +0100 Subject: [PATCH 22/34] 2022 Copyright The copyright year should eventually be adjusted automatically :) --- meshroom/ui/qml/AboutDialog.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meshroom/ui/qml/AboutDialog.qml b/meshroom/ui/qml/AboutDialog.qml index 08d57f6f..483a4dce 100644 --- a/meshroom/ui/qml/AboutDialog.qml +++ b/meshroom/ui/qml/AboutDialog.qml @@ -118,7 +118,7 @@ Dialog { font.pointSize: 10 } Label { - text: "2010-2021 AliceVision contributors" + text: "2010-2022 AliceVision contributors" } } From 0fec646776630c94584160fcfa681875ef75d50c Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Tue, 22 Feb 2022 15:12:00 +0100 Subject: [PATCH 23/34] Avoid to load project nodes twice --- meshroom/core/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meshroom/core/__init__.py b/meshroom/core/__init__.py index 968f620a..834ace0a 100644 --- a/meshroom/core/__init__.py +++ b/meshroom/core/__init__.py @@ -273,6 +273,8 @@ def loadSubmitters(folder, packageName): 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: # - Nodes From 3aa984a0a57bf1d48a2e4e508658eecbb3c1168f Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Tue, 22 Feb 2022 15:23:34 +0100 Subject: [PATCH 24/34] [submitters] simpleFarm: updates for rez packages versions detection Use REZ_REQUEST and REZ_RESOLVE to define the direct packages dependencies. --- meshroom/submitters/simpleFarmSubmitter.py | 38 ++++++++++++++++++---- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/meshroom/submitters/simpleFarmSubmitter.py b/meshroom/submitters/simpleFarmSubmitter.py index fc46bf8c..b04a4990 100644 --- a/meshroom/submitters/simpleFarmSubmitter.py +++ b/meshroom/submitters/simpleFarmSubmitter.py @@ -3,6 +3,7 @@ import os import json +import logging import simpleFarm 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))) 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')) config = json.load(open(filepath)) + reqPackages = [] + environment = {} ENGINE = '' DEFAULT_TAGS = {'prod': ''} @@ -28,6 +27,32 @@ class SimpleFarmSubmitter(BaseSubmitter): self.engine = os.environ.get('MESHROOM_SIMPLEFARM_ENGINE', 'tractor') self.share = os.environ.get('MESHROOM_SIMPLEFARM_SHARE', 'vfx') 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): tags = self.DEFAULT_TAGS.copy() # copy to not modify default tags @@ -50,10 +75,10 @@ class SimpleFarmSubmitter(BaseSubmitter): task = simpleFarm.Task( name=node.nodeType, 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), tags=tags, - rezPackages=[self.MESHROOM_PACKAGE] if self.MESHROOM_PACKAGE else None, + rezPackages=self.reqPackages, requirements={'service': str(','.join(allRequirements))}, **arguments) return task @@ -74,6 +99,7 @@ class SimpleFarmSubmitter(BaseSubmitter): job = simpleFarm.Job(name, tags=mainTags, requirements={'service': str(','.join(allRequirements))}, + environment=self.environment, ) nodeNameToTask = {} From 91b68e7f3bb5aafe97dbfa71f92988ba6225a391 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Tue, 22 Feb 2022 15:24:02 +0100 Subject: [PATCH 25/34] [submitters] simpleFarm: update gpu tags --- meshroom/submitters/simpleFarmConfig.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meshroom/submitters/simpleFarmConfig.json b/meshroom/submitters/simpleFarmConfig.json index 67fd4036..c5c2d5fe 100644 --- a/meshroom/submitters/simpleFarmConfig.json +++ b/meshroom/submitters/simpleFarmConfig.json @@ -12,7 +12,7 @@ }, "GPU": { "NONE": [], - "NORMAL": ["!\"*rnd*\""], - "INTENSIVE": ["!\"*rnd*\"", "@.nCPUs>=12"] + "NORMAL": ["cuda8G"], + "INTENSIVE": ["cuda16G"] } } From 22a2bbdf2a22f226525a23fe63e0df5a8b1d3664 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Tue, 22 Feb 2022 15:35:37 +0100 Subject: [PATCH 26/34] [bin] newNodeType: update - allow executable with multiple arguments - force utf8 conversion - fix typo in help --- bin/meshroom_newNodeType | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bin/meshroom_newNodeType b/bin/meshroom_newNodeType index 2ee23f27..7ba37b4e 100755 --- a/bin/meshroom_newNodeType +++ b/bin/meshroom_newNodeType @@ -5,6 +5,7 @@ import argparse import os import re import sys +import shlex from pprint import pprint def trim(s): @@ -60,7 +61,7 @@ parser.add_argument('node', metavar='NODE_NAME', type=str, help='New node name') parser.add_argument('bin', metavar='CMDLINE', type=str, default=None, - help='Output plugin folder') + help='Input executable') parser.add_argument('--output', metavar='DIR', type=str, default=os.path.dirname(__file__), help='Output plugin folder') @@ -77,7 +78,7 @@ soft = "{nodeType}" if args.bin: soft = args.bin 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() inputCmdLineDoc = stdout if stdout else stderr elif sys.stdin.isatty(): @@ -137,7 +138,7 @@ choiceValues1_re = re.compile('\* (?P\w+):') choiceValues2_re = re.compile('\((?P.+?)\)') choiceValues3_re = re.compile('\{(?P.+?)\}') -cmdLineArgs = args_re.findall(inputCmdLineDoc) +cmdLineArgs = args_re.findall(inputCmdLineDoc.decode('utf-8')) print('='*80) pprint(cmdLineArgs) From a2c255c917f2107394326c48f0123fc49d597e81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20De=20Lillo?= Date: Tue, 1 Mar 2022 01:36:59 +0100 Subject: [PATCH 27/34] [nodes] StructureFromMotion: add option computeStructureColor --- meshroom/nodes/aliceVision/StructureFromMotion.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/meshroom/nodes/aliceVision/StructureFromMotion.py b/meshroom/nodes/aliceVision/StructureFromMotion.py index 2db4aeb4..03b35ad1 100644 --- a/meshroom/nodes/aliceVision/StructureFromMotion.py +++ b/meshroom/nodes/aliceVision/StructureFromMotion.py @@ -308,6 +308,13 @@ It iterates like that, adding cameras and triangulating new 2D features into 3D value=False, 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( name='initialPairA', label='Initial Pair A', From 655dad9959657301fe5e5cfd539b2d05c1f70a4d Mon Sep 17 00:00:00 2001 From: fabien servant Date: Fri, 25 Mar 2022 11:00:52 +0100 Subject: [PATCH 28/34] [camerainit] update parameters to use focal in mm --- meshroom/nodes/aliceVision/CameraInit.py | 41 ++++++++++--------- meshroom/ui/qml/ImageGallery/ImageGallery.qml | 6 +-- meshroom/ui/reconstruction.py | 5 ++- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/meshroom/nodes/aliceVision/CameraInit.py b/meshroom/nodes/aliceVision/CameraInit.py index a5fcb8fc..ea5d5bc8 100644 --- a/meshroom/nodes/aliceVision/CameraInit.py +++ b/meshroom/nodes/aliceVision/CameraInit.py @@ -1,4 +1,4 @@ -__version__ = "6.0" +__version__ = "7.0" import os import json @@ -28,16 +28,17 @@ Viewpoint = [ Intrinsic = [ 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" "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" "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), - desc.GroupAttribute(name="pxFocalLength", label="Focal Length", description="Known/Calibrated Focal Length (in pixels)", groupDesc=[ - desc.FloatParam(name="x", label="x", description="", value=-1, uid=[], range=(0, 10000, 1)), - desc.FloatParam(name="y", label="y", description="", value=-1, uid=[], range=(0, 10000, 1)), - ]), + desc.FloatParam(name="focalLength", label="Focal Length", description="Known/Calibrated Focal Length (in mm)", value=1000, 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.BoolParam(name='pixelRatioLocked', label='Pixel ratio Locked', + description='the pixelRatio value is locked for estimation', + value=False, uid=[0]), desc.ChoiceParam(name="type", label="Camera Type", description="Mathematical Model used to represent a camera:\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']['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 if intrinsic['distortionParams'] == '': intrinsic['distortionParams'] = list() @@ -255,12 +251,6 @@ The metadata needed are: ] 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 if fromVersion < Version(6, 0): @@ -271,6 +261,20 @@ The metadata needed are: "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 def readSfMData(self, sfmFile): @@ -329,7 +333,6 @@ The metadata needed are: intrinsics = node.intrinsics.getPrimitiveValue(exportDefault=True) for intrinsic in intrinsics: intrinsic['principalPoint'] = [intrinsic['principalPoint']['x'], intrinsic['principalPoint']['y']] - intrinsic['pxFocalLength'] = [intrinsic['pxFocalLength']['x'], intrinsic['pxFocalLength']['y']] views = node.viewpoints.getPrimitiveValue(exportDefault=False) # convert the metadata string into a map @@ -338,7 +341,7 @@ The metadata needed are: view['metadata'] = json.loads(view['metadata']) sfmData = { - "version": [1, 2, 1], + "version": [1, 2, 2], "views": views + newViews, "intrinsics": intrinsics, "featureFolder": "", diff --git a/meshroom/ui/qml/ImageGallery/ImageGallery.qml b/meshroom/ui/qml/ImageGallery/ImageGallery.qml index 5041f32c..88e23af1 100644 --- a/meshroom/ui/qml/ImageGallery/ImageGallery.qml +++ b/meshroom/ui/qml/ImageGallery/ImageGallery.qml @@ -474,9 +474,8 @@ Panel { property var columnWidths: [105, 75, 75, 75, 125, 60, 60, 45, 45, 200, 60, 60] property var columnNames: [ "intrinsicId", - "pxInitialFocalLength", - "pxFocalLength.x", - "pxFocalLength.y", + "initialFocalLength", + "focalLength", "type", "width", "height", @@ -499,7 +498,6 @@ Panel { 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[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 } diff --git a/meshroom/ui/reconstruction.py b/meshroom/ui/reconstruction.py index 60b6c280..cd7a6daa 100755 --- a/meshroom/ui/reconstruction.py +++ b/meshroom/ui/reconstruction.py @@ -358,8 +358,9 @@ class ViewpointWrapper(QObject): """ Get camera vertical field of view in degrees. """ if not self.solvedIntrinsics: return None - pxFocalLength = self.solvedIntrinsics["pxFocalLength"] - return 2.0 * math.atan(self.orientedImageSize.height() / (2.0 * float(pxFocalLength[0]))) * 180 / math.pi + focalLength = self.solvedIntrinsics["focalLength"] + sensorHeight = self.solvedIntrinsics["sensorHeight"] + return 2.0 * math.atan(sensorHeight / (2.0 * float(focalLength))) * 180 / math.pi @Property(type=QUrl, notify=denseSceneParamsChanged) def undistortedImageSource(self): From fd4851b7e90ce7760ab3479fcdde01cb8035bbc9 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Wed, 6 Apr 2022 10:46:08 +0200 Subject: [PATCH 29/34] [bin] batch: allow to set params inside groups --- bin/meshroom_batch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/meshroom_batch b/bin/meshroom_batch index 5e141495..7a917039 100755 --- a/bin/meshroom_batch +++ b/bin/meshroom_batch @@ -177,7 +177,7 @@ with multiview.GraphModification(graph): if args.paramOverrides: print("\n") import re - reExtract = re.compile('(\w+)([:.])(\w+)=(.*)') + reExtract = re.compile('(\w+)([:.])(\w[\w.]*)=(.*)') for p in args.paramOverrides: result = reExtract.match(p) if not result: From a62c951bf5f58127bd756f0d25f1f5e3b75eeb36 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Mon, 11 Apr 2022 16:28:44 +0200 Subject: [PATCH 30/34] [core] more generic str to bool conversion --- meshroom/core/desc.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/meshroom/core/desc.py b/meshroom/core/desc.py index f74b7a03..66b3d80c 100755 --- a/meshroom/core/desc.py +++ b/meshroom/core/desc.py @@ -5,6 +5,8 @@ import math import os import psutil import ast +import distutils.util + class Attribute(BaseObject): """ @@ -191,7 +193,10 @@ class BoolParam(Param): def validateValue(self, value): 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: raise ValueError('BoolParam only supports bool value (param:{}, value:{}, type:{})'.format(self.name, value, type(value))) From 7083b01819c05f339c0852414e6a76687ca67f20 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Mon, 11 Apr 2022 17:01:38 +0200 Subject: [PATCH 31/34] [nodes] CameraInit: pixelRatioLocked True by default --- meshroom/nodes/aliceVision/CameraInit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meshroom/nodes/aliceVision/CameraInit.py b/meshroom/nodes/aliceVision/CameraInit.py index ea5d5bc8..91cf5fef 100644 --- a/meshroom/nodes/aliceVision/CameraInit.py +++ b/meshroom/nodes/aliceVision/CameraInit.py @@ -38,7 +38,7 @@ Intrinsic = [ desc.FloatParam(name="pixelRatio", label="pixel Ratio", description="ratio between pixel width and pixel height", value=1, uid=[], range=(0, 10, 0.1)), desc.BoolParam(name='pixelRatioLocked', label='Pixel ratio Locked', description='the pixelRatio value is locked for estimation', - value=False, uid=[0]), + value=True, uid=[0]), desc.ChoiceParam(name="type", label="Camera Type", description="Mathematical Model used to represent a camera:\n" " * pinhole: Simplest projective camera model without optical distortion (focal and optical center).\n" From 5829206ba85cb9014a02e3ad4913d6c8a3fab8d7 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Tue, 26 Apr 2022 17:08:08 +0200 Subject: [PATCH 32/34] [ui] ImageGallery: fix missing function changeCurrentIndex --- meshroom/ui/qml/ImageGallery/ImageGallery.qml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/meshroom/ui/qml/ImageGallery/ImageGallery.qml b/meshroom/ui/qml/ImageGallery/ImageGallery.qml index 88e23af1..6e0256e2 100644 --- a/meshroom/ui/qml/ImageGallery/ImageGallery.qml +++ b/meshroom/ui/qml/ImageGallery/ImageGallery.qml @@ -48,6 +48,10 @@ Panel { parseIntr() } + function changeCurrentIndex(newIndex) { + _reconstruction.cameraInitIndex = newIndex + } + function populate_model() { intrinsicModel.clear() @@ -539,7 +543,7 @@ Panel { font.family: MaterialIcons.fontFamily ToolTip.text: "Next Group (Alt+Right)" ToolTip.visible: hovered - enabled: root.cameraInitIndex < root.cameraInits.count - 1 + enabled: nodesCB.currentIndex < root.cameraInits.count - 1 onClicked: nodesCB.incrementCurrentIndex() } } From 8cfc5cbb453ec3139e41cdf64e29dfe4c73a5d01 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Thu, 2 Jun 2022 14:14:48 +0200 Subject: [PATCH 33/34] [core] fix ressources stats --- meshroom/core/stats.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/meshroom/core/stats.py b/meshroom/core/stats.py index 4a3b9d11..046b1c5c 100644 --- a/meshroom/core/stats.py +++ b/meshroom/core/stats.py @@ -95,23 +95,34 @@ class ComputerStatistics: return try: 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) gpuTree = smiTree.find('gpu') 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: logging.debug('Failed to get gpuMemoryUsed: "{}".'.format(str(e))) pass 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: logging.debug('Failed to get gpuUsed: "{}".'.format(str(e))) pass 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: logging.debug('Failed to get gpuTemperature: "{}".'.format(str(e))) pass @@ -191,7 +202,7 @@ class ProcStatistics: data = proc.as_dict(self.dynamicKeys) for k, v in data.items(): self._addKV(k, v) - + ## Note: Do not collect stats about open files for now, # as there is bug in psutil-5.7.2 on Windows which crashes the application. # https://github.com/giampaolo/psutil/issues/1763 From 7b467b649d7fc7700258a6b82789072de7092b3d Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Thu, 2 Jun 2022 14:15:18 +0200 Subject: [PATCH 34/34] fix: force float conversion --- meshroom/ui/reconstruction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meshroom/ui/reconstruction.py b/meshroom/ui/reconstruction.py index cd7a6daa..3915c42a 100755 --- a/meshroom/ui/reconstruction.py +++ b/meshroom/ui/reconstruction.py @@ -360,7 +360,7 @@ class ViewpointWrapper(QObject): return None focalLength = self.solvedIntrinsics["focalLength"] sensorHeight = self.solvedIntrinsics["sensorHeight"] - return 2.0 * math.atan(sensorHeight / (2.0 * float(focalLength))) * 180 / math.pi + return 2.0 * math.atan(float(sensorHeight) / (2.0 * float(focalLength))) * 180.0 / math.pi @Property(type=QUrl, notify=denseSceneParamsChanged) def undistortedImageSource(self):