diff --git a/meshroom/multiview.py b/meshroom/multiview.py index fcc2c130..d7323059 100644 --- a/meshroom/multiview.py +++ b/meshroom/multiview.py @@ -14,7 +14,7 @@ def isImageFile(filepath): return os.path.splitext(filepath)[1].lower() in imageExtensions -def findImageFiles(folder): +def findImageFiles(folder, recursive=False): """ Return all files that are images in 'folder' based on their extensions. @@ -24,7 +24,15 @@ def findImageFiles(folder): Returns: list: the list of image files. """ - return [os.path.join(folder, filename) for filename in os.listdir(folder) if isImageFile(filename)] + if recursive: + output = [] + for root, directories, files in os.walk(folder): + for filename in files: + if isImageFile(filename): + output.append(os.path.join(root, filename)) + return output + else: + return [os.path.join(folder, filename) for filename in os.listdir(folder) if isImageFile(filename)] def photogrammetry(inputImages=list(), inputViewpoints=list(), inputIntrinsics=list(), output=''): diff --git a/meshroom/ui/app.py b/meshroom/ui/app.py index 26604544..817375ea 100644 --- a/meshroom/ui/app.py +++ b/meshroom/ui/app.py @@ -61,9 +61,13 @@ class MeshroomApp(QApplication): parser.add_argument('input', metavar='INPUT', type=str, nargs='?', help='Meshroom project file (e.g. myProject.mg) or folder with images to reconstruct.') - parser.add_argument('--project', metavar='MESHROOM_FILE', type=str, required=False, + parser.add_argument('-i', '--import', metavar='IMAGES/FOLDERS', type=str, nargs='*', + help='Import images or folder with images to reconstruct.') + parser.add_argument('-I', '--importRecursive', metavar='FOLDERS', type=str, nargs='*', + help='Import images to reconstruct from specified folder and sub-folders.') + parser.add_argument('-p', '--project', metavar='MESHROOM_FILE', type=str, required=False, help='Meshroom project file (e.g. myProject.mg).') - parser.add_argument('--pipeline', metavar='MESHROOM_FILE', type=str, required=False, + parser.add_argument('-P', '--pipeline', metavar='MESHROOM_FILE', type=str, required=False, help='Override the default Meshroom pipeline with this external graph.') args = parser.parse_args(args[1:]) @@ -126,6 +130,19 @@ class MeshroomApp(QApplication): if defaultPipeline: r.setDefaultPipeline(args.pipeline) + if args.input: + if not os.path.isfile(args.input) and not os.path.isdir(args.input): + raise RuntimeError( + "Meshroom Command Line Error: 'INPUT' argument should be a Meshroom project file (.mg) or a folder with input images.\n" + "Invalid value: '{}'".format(args.input)) + if args.project and not os.path.isfile(args.project): + raise RuntimeError( + "Meshroom Command Line Error: '--project' argument should be a Meshroom project file (.mg).\n" + "Invalid value: '{}'".format(args.project)) + + if args.project and args.input and not os.path.isdir(args.input): + raise RuntimeError("Meshroom Command Line Error: 'INPUT' and '--project' arguments cannot both load a Meshroom project file (.mg).") + if args.project: r.load(args.project) @@ -134,7 +151,14 @@ class MeshroomApp(QApplication): # we assume that it is an ".mg" file. r.load(args.input) elif os.path.isdir(args.input): - r.importImagesFromFolder(args.input) + r.importImagesFromFolder(args.input, recursive=False) + + # import is a python keyword, so we have to access the attribute by a string + if getattr(args, "import", None): + r.importImagesFromFolder(getattr(args, "import"), recursive=False) + + if args.importRecursive: + r.importImagesFromFolder(args.importRecursive, recursive=True) self.engine.load(os.path.normpath(url)) diff --git a/meshroom/ui/reconstruction.py b/meshroom/ui/reconstruction.py index dc2b8260..b8852480 100755 --- a/meshroom/ui/reconstruction.py +++ b/meshroom/ui/reconstruction.py @@ -364,13 +364,27 @@ class Reconstruction(UIGraph): images.append(localFile) return images - def importImagesFromFolder(self, path): + def importImagesFromFolder(self, path, recursive=False): + """ + + Args: + path: A path to a folder or file or a list of files/folders + recursive: List files in folders recursively. + + """ images = [] - if os.path.isdir(path): # get folder content - images.extend(multiview.findImageFiles(path)) - elif multiview.isImageFile(path): - images.append(path) - self.buildIntrinsics(self.cameraInit, images) + paths = [] + if isinstance(path, (list, tuple)): + paths = path + else: + paths.append(path) + for p in paths: + if os.path.isdir(p): # get folder content + images.extend(multiview.findImageFiles(p, recursive)) + elif multiview.isImageFile(p): + images.append(p) + if images: + self.buildIntrinsics(self.cameraInit, images) def importImagesAsync(self, images, cameraInit): """ Add the given list of images to the Reconstruction. """