mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-06-11 07:11:52 +02:00
Merge pull request #1483 from alicevision/dev/masking
New ImageMasking and MeshMasking nodes
This commit is contained in:
commit
66e046c613
11 changed files with 442 additions and 23 deletions
|
@ -10,7 +10,7 @@ class Attribute(BaseObject):
|
|||
"""
|
||||
"""
|
||||
|
||||
def __init__(self, name, label, description, value, advanced, uid, group, enabled):
|
||||
def __init__(self, name, label, description, value, advanced, semantic, uid, group, enabled):
|
||||
super(Attribute, self).__init__()
|
||||
self._name = name
|
||||
self._label = label
|
||||
|
@ -20,6 +20,7 @@ class Attribute(BaseObject):
|
|||
self._group = group
|
||||
self._advanced = advanced
|
||||
self._enabled = enabled
|
||||
self._semantic = semantic
|
||||
|
||||
name = Property(str, lambda self: self._name, constant=True)
|
||||
label = Property(str, lambda self: self._label, constant=True)
|
||||
|
@ -29,6 +30,7 @@ class Attribute(BaseObject):
|
|||
group = Property(str, lambda self: self._group, constant=True)
|
||||
advanced = Property(bool, lambda self: self._advanced, constant=True)
|
||||
enabled = Property(Variant, lambda self: self._enabled, 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):
|
||||
|
@ -55,13 +57,13 @@ class Attribute(BaseObject):
|
|||
|
||||
class ListAttribute(Attribute):
|
||||
""" A list of Attributes """
|
||||
def __init__(self, elementDesc, name, label, description, group='allParams', advanced=False, enabled=True, joinChar=' '):
|
||||
def __init__(self, elementDesc, name, label, description, group='allParams', advanced=False, semantic='', enabled=True, joinChar=' '):
|
||||
"""
|
||||
: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, enabled=enabled)
|
||||
super(ListAttribute, self).__init__(name=name, label=label, description=description, value=[], uid=(), group=group, advanced=advanced, semantic=semantic, enabled=enabled)
|
||||
|
||||
elementDesc = Property(Attribute, lambda self: self._elementDesc, constant=True)
|
||||
uid = Property(Variant, lambda self: self.elementDesc.uid, constant=True)
|
||||
|
@ -92,13 +94,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, enabled=True, joinChar=' '):
|
||||
def __init__(self, groupDesc, name, label, description, group='allParams', advanced=False, semantic='', enabled=True, joinChar=' '):
|
||||
"""
|
||||
: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, enabled=enabled)
|
||||
super(GroupAttribute, self).__init__(name=name, label=label, description=description, value={}, uid=(), group=group, advanced=advanced, semantic=semantic, enabled=enabled)
|
||||
|
||||
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, enabled):
|
||||
super(Param, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, enabled=enabled)
|
||||
def __init__(self, name, label, description, value, uid, group, advanced, semantic, enabled):
|
||||
super(Param, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled)
|
||||
|
||||
|
||||
class File(Attribute):
|
||||
"""
|
||||
"""
|
||||
def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, enabled=True):
|
||||
super(File, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, enabled=enabled)
|
||||
def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, semantic='', enabled=True):
|
||||
super(File, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled)
|
||||
|
||||
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, enabled=True):
|
||||
super(BoolParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, enabled=enabled)
|
||||
def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, semantic='', enabled=True):
|
||||
super(BoolParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled)
|
||||
|
||||
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, enabled=True):
|
||||
def __init__(self, name, label, description, value, range, uid, group='allParams', advanced=False, semantic='', enabled=True):
|
||||
self._range = range
|
||||
super(IntParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, enabled=enabled)
|
||||
super(IntParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled)
|
||||
|
||||
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, enabled=True):
|
||||
def __init__(self, name, label, description, value, range, uid, group='allParams', advanced=False, semantic='', enabled=True):
|
||||
self._range = range
|
||||
super(FloatParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, enabled=enabled)
|
||||
super(FloatParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled)
|
||||
|
||||
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, enabled=True):
|
||||
def __init__(self, name, label, description, value, values, exclusive, uid, group='allParams', joinChar=' ', advanced=False, semantic='', enabled=True):
|
||||
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, enabled=enabled)
|
||||
super(ChoiceParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled)
|
||||
|
||||
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, enabled=True):
|
||||
super(StringParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, enabled=enabled)
|
||||
def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, semantic='', enabled=True):
|
||||
super(StringParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled)
|
||||
|
||||
def validateValue(self, value):
|
||||
if not isinstance(value, pyCompatibility.basestring):
|
||||
|
|
|
@ -38,6 +38,13 @@ It is robust to motion-blur, depth-of-field, occlusion. Be careful to have enoug
|
|||
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',
|
||||
|
|
147
meshroom/nodes/aliceVision/ImageMasking.py
Normal file
147
meshroom/nodes/aliceVision/ImageMasking.py
Normal file
|
@ -0,0 +1,147 @@
|
|||
__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.ChoiceParam(
|
||||
name='algorithm',
|
||||
label='Algorithm',
|
||||
description='',
|
||||
value='HSV',
|
||||
values=['HSV', 'AutoGrayscaleThreshold'],
|
||||
exclusive=True,
|
||||
uid=[0],
|
||||
),
|
||||
desc.GroupAttribute(
|
||||
name="hsv",
|
||||
label="HSV Parameters",
|
||||
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
|
||||
""",
|
||||
group=None,
|
||||
enabled=lambda node: node.algorithm.value == 'HSV',
|
||||
groupDesc=[
|
||||
desc.FloatParam(
|
||||
name='hsvHue',
|
||||
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]
|
||||
),
|
||||
desc.FloatParam(
|
||||
name='hsvHueRange',
|
||||
label='Tolerance',
|
||||
description='Tolerance around the hue value to isolate.',
|
||||
value=0.1,
|
||||
range=(0, 1, 0.01),
|
||||
uid=[0]
|
||||
),
|
||||
desc.FloatParam(
|
||||
name='hsvMinSaturation',
|
||||
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='hsvMaxSaturation',
|
||||
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='hsvMinValue',
|
||||
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='hsvMaxValue',
|
||||
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='''If ticked, the selected area is ignored.
|
||||
If not, only the selected area is considered.''',
|
||||
value=True,
|
||||
uid=[0]
|
||||
),
|
||||
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.File(
|
||||
name='depthMapFolder',
|
||||
label='Depth Mask Folder',
|
||||
description='''Depth Mask Folder''',
|
||||
value='',
|
||||
uid=[0],
|
||||
),
|
||||
desc.StringParam(
|
||||
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',
|
||||
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=[],
|
||||
),
|
||||
]
|
98
meshroom/nodes/aliceVision/MeshMasking.py
Normal file
98
meshroom/nodes/aliceVision/MeshMasking.py
Normal file
|
@ -0,0 +1,98 @@
|
|||
__version__ = "1.0"
|
||||
|
||||
from meshroom.core import desc
|
||||
|
||||
|
||||
class MeshMasking(desc.CommandLineNode):
|
||||
commandLine = 'aliceVision_meshMasking {allParams}'
|
||||
category = 'Mesh Post-Processing'
|
||||
documentation = '''
|
||||
Decimate triangles based on image masks.
|
||||
'''
|
||||
|
||||
inputs = [
|
||||
desc.File(
|
||||
name='input',
|
||||
label='Dense SfMData',
|
||||
description='SfMData file.',
|
||||
value='',
|
||||
uid=[0],
|
||||
),
|
||||
desc.File(
|
||||
name='inputMesh',
|
||||
label='Input Mesh',
|
||||
description='''Input Mesh (OBJ file format).''',
|
||||
value='',
|
||||
uid=[0],
|
||||
),
|
||||
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.IntParam(
|
||||
name='threshold',
|
||||
label='Threshold',
|
||||
description='The minimum number of visibility to keep a vertex.',
|
||||
value=1,
|
||||
range=(1, 100, 1),
|
||||
uid=[0]
|
||||
),
|
||||
desc.BoolParam(
|
||||
name='smoothBoundary',
|
||||
label='Smooth Boundary',
|
||||
description='Modify the triangles at the boundary to fit the masks.',
|
||||
value=False,
|
||||
uid=[0]
|
||||
),
|
||||
desc.BoolParam(
|
||||
name='invert',
|
||||
label='Invert',
|
||||
description='''If ticked, the selected area is ignored.
|
||||
If not, only the selected area is considered.''',
|
||||
value=False,
|
||||
uid=[0]
|
||||
),
|
||||
desc.BoolParam(
|
||||
name='undistortMasks',
|
||||
label='Undistort Masks',
|
||||
description='''Undistort the masks with the same parameters as the matching image.
|
||||
Tick it if the masks are drawn on the original images.''',
|
||||
value=False,
|
||||
uid=[0]
|
||||
),
|
||||
desc.BoolParam(
|
||||
name='usePointsVisibilities',
|
||||
label='Use points visibilities',
|
||||
description='''Use the points visibilities from the meshing to filter triangles.
|
||||
Example: when they are occluded, back-face, etc.''',
|
||||
value=False,
|
||||
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='outputMesh',
|
||||
label='Output Mesh',
|
||||
description='''Output mesh (OBJ file format).''',
|
||||
value=desc.Node.internalFolder + 'mesh.obj',
|
||||
uid=[],
|
||||
),
|
||||
]
|
|
@ -34,6 +34,18 @@ This node export undistorted images so the depth map and texturing can be comput
|
|||
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',
|
||||
|
|
67
meshroom/nodes/aliceVision/SfMDistances.py
Normal file
67
meshroom/nodes/aliceVision/SfMDistances.py
Normal file
|
@ -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 = [
|
||||
]
|
|
@ -53,7 +53,7 @@ The transformation can be based on:
|
|||
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],
|
||||
enabled=lambda node: node.method.value == "transformation" or node.method.value == "from_single_camera",
|
||||
|
|
|
@ -270,15 +270,36 @@ It iterates like that, adding cameras and triangulating new 2D features into 3D
|
|||
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.BoolParam(
|
||||
name='filterTrackForks',
|
||||
label='Filter Track Forks',
|
||||
|
|
|
@ -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
|
||||
|
@ -379,5 +382,66 @@ RowLayout {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: color_hue_component
|
||||
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
|
||||
|
||||
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);
|
||||
}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ import Utils 1.0
|
|||
case ".abc": if(Viewer3DSettings.supportAlembic) component = abcLoaderEntityComponent; break;
|
||||
case ".exr": if(Viewer3DSettings.supportDepthMap) component = exrLoaderComponent; break;
|
||||
case ".obj":
|
||||
case ".stl":
|
||||
default: component = sceneLoaderEntityComponent; break;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ Item {
|
|||
|
||||
// supported 3D files extensions
|
||||
readonly property var supportedExtensions: {
|
||||
var exts = ['.obj'];
|
||||
var exts = ['.obj', '.stl'];
|
||||
if(supportAlembic)
|
||||
exts.push('.abc');
|
||||
if(supportDepthMap)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue