Skip to content

Commit

Permalink
Merge pull request #2645 from alicevision/dev/extractMetadataWithExif…
Browse files Browse the repository at this point in the history
…Tool

Extract more metadata using exifTool
  • Loading branch information
servantftechnicolor authored Feb 5, 2025
2 parents 910736b + 534b95e commit 8a8cb8b
Showing 1 changed file with 133 additions and 0 deletions.
133 changes: 133 additions & 0 deletions meshroom/nodes/aliceVision/ExtractMetadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
__version__ = "0.1"

from meshroom.core import desc
from meshroom.core.utils import VERBOSE_LEVEL
from pathlib import Path

import pyalicevision as av

import distutils.dir_util as du
import shutil
import glob
import os
import subprocess


class ExtractMetadata(desc.Node):
size = desc.DynamicNodeSize("input")

category = 'Utils'
documentation = '''
Using exifTool, this node extracts metadata of all images referenced in a sfmData and store them in appropriate files.
'''

inputs = [
desc.File(
name="input",
label="Input",
description="SfMData file input.",
value="",
),
desc.BoolParam(
name="keepFilename",
label="Keep Filename",
description="Keep the filename of the inputs for the outputs.",
value=False,
),
desc.ChoiceParam(
name="extension",
label="Output File Extension",
description="Metadata file extension.",
value="txt",
values=["txt", "xml", "xmp"],
exclusive=True,
),
desc.StringParam(
name="arguments",
label="Arguments",
description="ExifTool command arguments",
value="",
),
desc.BoolParam(
name="insertInSfm",
label="Update sfmData",
description="Insert the extracted metadata in the sfmData file.",
value=False,
),
desc.ChoiceParam(
name="verboseLevel",
label="Verbose Level",
description="Verbosity level (fatal, error, warning, info, debug, trace).",
values=VERBOSE_LEVEL,
value="info",
),
]

outputs = [
desc.File(
name="output",
label="Result Folder",
description="Output path for the resulting metadata files.",
value=desc.Node.internalFolder,
),
]

def processChunk(self, chunk):
try:
chunk.logManager.start(chunk.node.verboseLevel.value)

if chunk.node.input.value == "" or chunk.node.input.value[-4:].lower() != '.sfm':
error = 'This node need to have a sfmData connected as input.'
chunk.logger.error(error)
raise RuntimeError(error)

if not os.path.exists(chunk.node.output.value):
os.mkdir(chunk.node.output.value)

dataAV = av.sfmData.SfMData()
if av.sfmDataIO.load(dataAV, chunk.node.input.value, av.sfmDataIO.ALL):
views = dataAV.getViews()
for id, v in views.items():
inputFile = v.getImage().getImagePath()
chunk.logger.info(f"Processing {inputFile}")

if chunk.node.keepFilename.value:
outputMetadataFilename = os.path.join(chunk.node.output.value, Path(inputFile).stem + "." + chunk.node.extension.value)
else:
outputMetadataFilename = os.path.join(chunk.node.output.value, str(id) + "." + chunk.node.extension.value)

if chunk.node.extension.value == 'txt':
cmd = 'exiftool ' + chunk.node.arguments.value.strip() + ' ' + inputFile + ' > ' + outputMetadataFilename
elif chunk.node.extension.value == 'xml':
cmd = 'exiftool -X ' + chunk.node.arguments.value.strip() + ' ' + inputFile + ' > ' + outputMetadataFilename
else: #xmp
cmd = 'exiftool -tagsfromfile ' + inputFile + ' ' + chunk.node.arguments.value.strip() + ' ' + outputMetadataFilename

chunk.logger.debug(cmd)
error = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stderr.read().decode()

chunk.logger.debug(error)

if error != "":
chunk.logger.error(error)
raise RuntimeError(error)
if not os.path.exists(outputMetadataFilename):
info = 'No metadata extracted for file ' + inputFile
chunk.logger.info(info)
elif chunk.node.insertInSfm.value:
cmd = 'exiftool ' + chunk.node.arguments.value.strip() + ' ' + inputFile
metadata = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.read().decode()
chunk.logger.debug(metadata)
lmeta = metadata.split('\n')
for i in range(1, len(lmeta)-1):
l = lmeta[i].split(':', 1)
v.getImageInfo().addMetadata('ExifTool:'+l[0].strip(), l[1].strip())

if chunk.node.insertInSfm.value:
outputSfm = os.path.join(chunk.node.output.value, Path(chunk.node.input.value).stem + ".sfm")
av.sfmDataIO.save(dataAV, outputSfm, av.sfmDataIO.ALL)

chunk.logger.info('Metadata extraction end')

finally:
chunk.logManager.end()

0 comments on commit 8a8cb8b

Please sign in to comment.