mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-04-28 17:57:16 +02:00
239 lines
7.8 KiB
Python
239 lines
7.8 KiB
Python
import os
|
|
|
|
# Supported image extensions
|
|
imageExtensions = (
|
|
# bmp:
|
|
'.bmp',
|
|
# cineon:
|
|
'.cin',
|
|
# dds
|
|
'.dds',
|
|
# dpx:
|
|
'.dpx',
|
|
# gif:
|
|
'.gif',
|
|
# hdr:
|
|
'.hdr', '.rgbe',
|
|
# heif
|
|
'.heic', '.heif', '.avif',
|
|
# ico:
|
|
'.ico',
|
|
# iff:
|
|
'.iff', '.z',
|
|
# jpeg:
|
|
'.jpg', '.jpe', '.jpeg', '.jif', '.jfif', '.jfi',
|
|
# jpeg2000:
|
|
'.jp2', '.j2k', '.j2c',
|
|
# openexr:
|
|
'.exr', '.sxr', '.mxr',
|
|
# png:
|
|
'.png',
|
|
# pnm:
|
|
'.ppm', '.pgm', '.pbm', '.pnm', '.pfm',
|
|
# psd:
|
|
'.psd', '.pdd', '.psb',
|
|
# ptex:
|
|
'.ptex', '.ptx',
|
|
# raw:
|
|
'.bay', '.bmq', '.cr2', '.cr3', '.crw', '.cs1', '.dc2', '.dcr', '.dng', '.erf', '.fff', '.k25', '.kdc', '.mdc',
|
|
'.mos', '.mrw', '.nef', '.orf', '.pef', '.pxn', '.raf', '.raw', '.rdc', '.sr2', '.srf', '.x3f', '.arw', '.3fr',
|
|
'.cine', '.ia', '.kc2', '.mef', '.nrw', '.qtk', '.rw2', '.sti', '.rwl', '.srw', '.drf', '.dsc', '.cap', '.iiq',
|
|
'.rwz',
|
|
# rla:
|
|
'.rla',
|
|
# sgi:
|
|
'.sgi', '.rgb', '.rgba', '.bw', '.int', '.inta',
|
|
# socket:
|
|
'.socket',
|
|
# softimage:
|
|
'.pic',
|
|
# tiff:
|
|
'.tiff', '.tif', '.tx', '.env', '.sm', '.vsm',
|
|
# targa:
|
|
'.tga', '.tpic',
|
|
# webp:
|
|
'webp',
|
|
# zfile:
|
|
'.zfile',
|
|
# osl:
|
|
'.osl', '.oso', '.oslgroup', '.oslbody',
|
|
)
|
|
videoExtensions = (
|
|
'.avi', '.mov', '.qt',
|
|
'.mkv', '.webm',
|
|
'.mp4', '.mpg', '.mpeg', '.m2v', '.m4v',
|
|
'.wmv',
|
|
'.ogv', '.ogg',
|
|
'.mxf',
|
|
)
|
|
panoramaInfoExtensions = ('.xml')
|
|
meshroomSceneExtensions = ('.mg')
|
|
|
|
|
|
def hasExtension(filepath, extensions):
|
|
""" Return whether filepath is one of the following extensions. """
|
|
return os.path.splitext(filepath)[1].lower() in extensions
|
|
|
|
|
|
class FilesByType:
|
|
def __init__(self):
|
|
self.images = []
|
|
self.videos = []
|
|
self.panoramaInfo = []
|
|
self.meshroomScenes = []
|
|
self.other = []
|
|
|
|
def __bool__(self):
|
|
return self.images or self.videos or self.panoramaInfo or self.meshroomScenes
|
|
|
|
def extend(self, other):
|
|
self.images.extend(other.images)
|
|
self.videos.extend(other.videos)
|
|
self.panoramaInfo.extend(other.panoramaInfo)
|
|
self.meshroomScenes.extend(other.meshroomScenes)
|
|
self.other.extend(other.other)
|
|
|
|
def addFile(self, file):
|
|
if hasExtension(file, imageExtensions):
|
|
self.images.append(file)
|
|
elif hasExtension(file, videoExtensions):
|
|
self.videos.append(file)
|
|
elif hasExtension(file, panoramaInfoExtensions):
|
|
self.panoramaInfo.append(file)
|
|
elif hasExtension(file, meshroomSceneExtensions):
|
|
self.meshroomScenes.append(file)
|
|
else:
|
|
self.other.append(file)
|
|
|
|
def addFiles(self, files):
|
|
for file in files:
|
|
self.addFile(file)
|
|
|
|
|
|
def findFilesByTypeInFolder(folder, recursive=False):
|
|
"""
|
|
Return all files that are images in 'folder' based on their extensions.
|
|
|
|
Args:
|
|
folder (str): folder to look into or list of folder/files
|
|
|
|
Returns:
|
|
list: the list of image files with a supported extension.
|
|
"""
|
|
inputFolders = []
|
|
if isinstance(folder, (list, tuple)):
|
|
inputFolders = folder
|
|
else:
|
|
inputFolders.append(folder)
|
|
|
|
output = FilesByType()
|
|
for currentFolder in inputFolders:
|
|
currentFolder = os.path.abspath(currentFolder)
|
|
if os.path.isfile(currentFolder):
|
|
output.addFile(currentFolder)
|
|
continue
|
|
elif os.path.isdir(currentFolder):
|
|
if recursive:
|
|
for root, directories, files in os.walk(currentFolder):
|
|
for filename in files:
|
|
output.addFile(os.path.join(root, filename))
|
|
else:
|
|
output.addFiles([os.path.join(currentFolder, filename) for filename in os.listdir(currentFolder)])
|
|
else:
|
|
# if not a directory or a file, it may be an expression
|
|
import glob
|
|
paths = glob.glob(currentFolder)
|
|
filesByType = findFilesByTypeInFolder(paths, recursive=recursive)
|
|
output.extend(filesByType)
|
|
|
|
return output
|
|
|
|
|
|
def mvsPipeline(graph, sfm=None):
|
|
"""
|
|
Instantiate a MVS pipeline inside 'graph'.
|
|
|
|
Args:
|
|
graph (Graph/UIGraph): the graph in which nodes should be instantiated
|
|
sfm (Node, optional): if specified, connect the MVS pipeline to this StructureFromMotion node
|
|
|
|
Returns:
|
|
list of Node: the created nodes
|
|
"""
|
|
if sfm and not sfm.nodeType == "StructureFromMotion":
|
|
raise ValueError("Invalid node type. Expected StructureFromMotion, got {}.".format(sfm.nodeType))
|
|
|
|
prepareDenseScene = graph.addNewNode('PrepareDenseScene',
|
|
input=sfm.output if sfm else "")
|
|
depthMap = graph.addNewNode('DepthMap',
|
|
input=prepareDenseScene.input,
|
|
imagesFolder=prepareDenseScene.output)
|
|
depthMapFilter = graph.addNewNode('DepthMapFilter',
|
|
input=depthMap.input,
|
|
depthMapsFolder=depthMap.output)
|
|
meshing = graph.addNewNode('Meshing',
|
|
input=depthMapFilter.input,
|
|
depthMapsFolder=depthMapFilter.output)
|
|
meshFiltering = graph.addNewNode('MeshFiltering',
|
|
inputMesh=meshing.outputMesh)
|
|
texturing = graph.addNewNode('Texturing',
|
|
input=meshing.output,
|
|
imagesFolder=depthMap.imagesFolder,
|
|
inputMesh=meshFiltering.outputMesh)
|
|
|
|
return [
|
|
prepareDenseScene,
|
|
depthMap,
|
|
depthMapFilter,
|
|
meshing,
|
|
meshFiltering,
|
|
texturing
|
|
]
|
|
|
|
|
|
def sfmAugmentation(graph, sourceSfm, withMVS=False):
|
|
"""
|
|
Create a SfM augmentation inside 'graph'.
|
|
|
|
Args:
|
|
graph (Graph/UIGraph): the graph in which nodes should be instantiated
|
|
sourceSfm (Node, optional): if specified, connect the MVS pipeline to this StructureFromMotion node
|
|
withMVS (bool): whether to create a MVS pipeline after the augmented SfM branch
|
|
|
|
Returns:
|
|
tuple: the created nodes (sfmNodes, mvsNodes)
|
|
"""
|
|
cameraInit = graph.addNewNode('CameraInit')
|
|
|
|
featureExtraction = graph.addNewNode('FeatureExtraction',
|
|
input=cameraInit.output)
|
|
imageMatchingMulti = graph.addNewNode('ImageMatchingMultiSfM',
|
|
input=featureExtraction.input,
|
|
featuresFolders=[featureExtraction.output]
|
|
)
|
|
featureMatching = graph.addNewNode('FeatureMatching',
|
|
input=imageMatchingMulti.outputCombinedSfM,
|
|
featuresFolders=imageMatchingMulti.featuresFolders,
|
|
imagePairsList=imageMatchingMulti.output,
|
|
describerTypes=featureExtraction.describerTypes)
|
|
structureFromMotion = graph.addNewNode('StructureFromMotion',
|
|
input=featureMatching.input,
|
|
featuresFolders=featureMatching.featuresFolders,
|
|
matchesFolders=[featureMatching.output],
|
|
describerTypes=featureMatching.describerTypes)
|
|
graph.addEdge(sourceSfm.output, imageMatchingMulti.inputB)
|
|
|
|
sfmNodes = [
|
|
cameraInit,
|
|
featureExtraction,
|
|
imageMatchingMulti,
|
|
featureMatching,
|
|
structureFromMotion
|
|
]
|
|
|
|
mvsNodes = []
|
|
|
|
if withMVS:
|
|
mvsNodes = mvsPipeline(graph, structureFromMotion)
|
|
|
|
return sfmNodes, mvsNodes
|