OpenDroneMap-ODM/opendm/exiftool.py

101 wiersze
3.3 KiB
Python

import json
import os
import tempfile
import base64
import numpy as np
from rasterio.io import MemoryFile
from opendm.system import run
from opendm import log
from opendm.utils import double_quote
def extract_raw_thermal_image_data(image_path):
try:
f, tmp_file_path = tempfile.mkstemp(suffix='.json')
os.close(f)
try:
output = run("exiftool -b -x ThumbnailImage -x PreviewImage -j \"%s\" > \"%s\"" % (image_path, tmp_file_path), quiet=True)
with open(tmp_file_path) as f:
j = json.loads(f.read())
if isinstance(j, list):
j = j[0] # single file
if "RawThermalImage" in j:
imageBytes = base64.b64decode(j["RawThermalImage"][len("base64:"):])
with MemoryFile(imageBytes) as memfile:
with memfile.open() as dataset:
img = dataset.read()
bands, h, w = img.shape
if bands != 1:
raise Exception("Raw thermal image has more than one band? This is not supported")
# (1, 512, 640) --> (512, 640, 1)
img = img[0][:,:,None]
del j["RawThermalImage"]
elif "ThermalData" in j:
thermal_data = base64.b64decode(j["ThermalData"][len("base64:"):])
thermal_buf = np.frombuffer(thermal_data, dtype=np.int16)
# TODO: how to interpret these?
# https://exiftool.org/forum/index.php?topic=11401.45
return extract_temperature_params_from(j), img
else:
raise Exception("Invalid JSON (not a list)")
except Exception as e:
log.ODM_WARNING("Cannot extract tags using exiftool: %s" % str(e))
return {}, None
finally:
if os.path.isfile(tmp_file_path):
os.remove(tmp_file_path)
except Exception as e:
log.ODM_WARNING("Cannot create temporary file: %s" % str(e))
return {}, None
def unit(unit):
def _convert(v):
if isinstance(v, float):
return v
elif isinstance(v, str):
if not v[-1].isnumeric():
if v[-1].upper() != unit.upper():
log.ODM_WARNING("Assuming %s is in %s" % (v, unit))
return float(v[:-1])
else:
return float(v)
else:
return float(v)
return _convert
def extract_temperature_params_from(tags):
# Defaults
meta = {
"Emissivity": float,
"ObjectDistance": unit("m"),
"AtmosphericTemperature": unit("C"),
"ReflectedApparentTemperature": unit("C"),
"IRWindowTemperature": unit("C"),
"IRWindowTransmission": float,
"RelativeHumidity": unit("%"),
"PlanckR1": float,
"PlanckB": float,
"PlanckF": float,
"PlanckO": float,
"PlanckR2": float,
}
params = {}
for m in meta:
if m not in tags:
# All or nothing
raise Exception("Cannot find %s in tags" % m)
params[m] = (meta[m])(tags[m])
return params