-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2645 from alicevision/dev/extractMetadataWithExif…
…Tool Extract more metadata using exifTool
- Loading branch information
Showing
1 changed file
with
133 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |