Hallo,
ich habe ein Code Snippet gefunden, welches mir radiometrische JPGs zu TIFFs konvertiert. Danach habe ich die Pfade angepasst und mit einem Thermalfoto getestet. Das Code Snippet läuft nicht durch.
Leider habe ich nicht sehr viel Erfahrung mit Python bis jetzt.
Das ist das Code Snippet:
import glob
import os
import subprocess
import PIL.Image
import numpy as np
import io
import json
import skimage
import matplotlib.image
# specify the name format (this should be standard for FLIR jpgs)
INPUT_FILE_MASK = "*_T.jpg"
# input the exiftool location (you may need to download it)
EXIFTOOL = "C:/Users/CopterLogServices/Deskto/TEST_ConvertRJPGtoTIFF/exiftool.exe"
def process_image(filename, radiometric_corr=True, save_false_colour_png=False):
""" Read data from JPG image and write to h5-handler """
# read meta-data and binary image
meta = get_string_meta_data(filename)
img = get_raw_thermal_image(filename)
# extract "IR_xxx" as frame identifier
folder_name = os.path.split(filename)[0]
name = os.path.split(filename)[-1]
name = os.path.splitext(name)[0]
# converison to temperature:
# according to http://u88.n24.queensu.ca/exiftool/foru ... l#msg23972
# extract radiometric parameters
R1, R2, B, F, O = tuple(meta["Planck{}".format(s)]
for s in ("R1", "R2", "B", "F", "O"))
# for the case of emissivity != 1
if radiometric_corr:
emissivity = meta["Emissivity"]
# drop the C on the temp and increase to Kelvin
T_refl = float(meta["ReflectedApparentTemperature"][:-1]) + 273.15
RAW_refl=R1/(R2*(np.exp(B/T_refl)-F))-O
RAW_obj=(img-(1-emissivity)*RAW_refl)/emissivity
T = B / np.log(R1/(R2*(RAW_obj+O))+F)
# (for the case: emissivity == 1)
else:
T = B / np.log(R1/(R2*(img+O))+F)
if save_false_colour_png:
conv_T = skimage.exposure.rescale_intensity(T)
matplotlib.image.imsave("{}.png".format(os.path.join(folder_name, name)), conv_T, cmap='inferno')
T = PIL.Image.fromarray(T)
T.save("{}.tiff".format(os.path.join(folder_name, name)))
def get_raw_thermal_image(filename, key="RawThermalImage"):
""" Use exiftool to extract 'RawThermalImage' from FLIR-JPG """
# call exiftool and extract binary data
cmd = [EXIFTOOL, filename, "-b", "-{}".format(key)]
r_data = subprocess.check_output(cmd)
# read in image (should detect image format)
im = PIL.Image.open(io.BytesIO(r_data))
# convert image to array
return np.array(im)
def get_string_meta_data(filename):
""" Read all exif-data using exiftool """
# call exiftool with 'JSON'-output flag
cmd = [EXIFTOOL, filename, "-j"]
dta = subprocess.check_output(cmd, universal_newlines=True)
# convert to stream and load using 'json' library
data = json.load(io.StringIO(dta))
# reduce dimension if singleton
if isinstance(data, list) and len(data) == 1:
data = data[0]
return data
# set the folder location that holds the radiometric jpgs
# files will be saved as tiff files with the same name
# if specified, the images will also be saved as regular jpegs in a colormap suitable for thermal images
# this option will not produce publishing quality images as there is no contrast adjustment or other processing
filt=INPUT_FILE_MASK
folder="C:/Users/CopterLogServices/Desktop/TEST_ConvertRJPGtoTIFF/footage"
filt = os.path.join(folder, filt)
for filename in glob.iglob(filt):
process_image(filename, radiometric_corr=True, save_false_colour_png=False)
Folgende Fehler erhalte ich, wenn ich das Code Snippet ausführe:
Traceback (most recent call last):
File "C:\Users\CopterLogServices\Desktop\TEST_ConvertRJPGtoTIFF\code\ConvertFLIR_mod.py", line 92, in <module>
process_image(filename, radiometric_corr=True, save_false_colour_png=False)
File "C:\Users\CopterLogServices\Desktop\TEST_ConvertRJPGtoTIFF\code\ConvertFLIR_mod.py", line 20, in process_image
meta = get_string_meta_data(filename)
File "C:\Users\CopterLogServices\Desktop\TEST_ConvertRJPGtoTIFF\code\ConvertFLIR_mod.py", line 72, in get_string_meta_data
dta = subprocess.check_output(cmd, universal_newlines=True)
File "C:\Users\CopterLogServices\AppData\Local\Programs\Python\Python310\lib\subprocess.py", line 420, in check_output
return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
File "C:\Users\CopterLogServices\AppData\Local\Programs\Python\Python310\lib\subprocess.py", line 501, in run
with Popen(*popenargs, **kwargs) as process:
File "C:\Users\CopterLogServices\AppData\Local\Programs\Python\Python310\lib\subprocess.py", line 966, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "C:\Users\CopterLogServices\AppData\Local\Programs\Python\Python310\lib\subprocess.py", line 1435, in _execute_child
hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
FileNotFoundError: [WinError 2] Das System kann die angegebene Datei nicht finden
Vielleicht kann mir jemand von euch helfen.
Danke im Voraus!
Konvertierung von radiometrischen JPG zu TIFF
- __blackjack__
- User
- Beiträge: 14078
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@Kodiak01: Anmerkungen zum Quelltext: Statt `os.path` würde man eher `pathlib` verwenden.
Einige Namen sind schlecht gewählt. Was soll denn bitte `filt` bedeuten? Namen sollen dem Leser vermitteln was der Wert der dahinter steckt im Kontext des Programms bedeutet. Kryptische Abkürzungen bewirken da eher das Gegenteil.
In `process_image()` ist das definieren von Namen teilweise zu weit von der Stelle entfernt an der sie dann tatsächlich verwendet werden. Die Funktion ist auch recht lang und verwendet recht viele lokale Namen. Wenn man da Definitionen und Verwendung so weit über die ganze Funktion verstreut, macht es das unnötig schwerer die Funktion zu verstehen und aufzuteilen.
`os.path.split()` + magischem Index wird statt `os.path.dirname()` oder `os.path.basename()` verwendet, oder halt `os.path.split()` *einmal* und daraus dann *beide* Ergebnisse gleich an Namen binden, ohne magische Indexwerte. Entfällt/wird einfacher wenn man `pathlib` verwendet.
Es wird zwar oft von „tuple unpacking“ gesprochen, aber es ist eigentlich „iterable unpacking“. Es ist nicht notwendig den Wert der da entpackt werden soll tatsächlich extra in ein Tupel umzuwandeln.
Es wird an vielen Stellen die `format()`-Methode benutzt, wo man f-Zeichenkettenliterale verwenden könnte.
Der Kommentar vor ``if radiometric_corr:`` passt nicht so ganz zum Code denn der Wert für `emissivity` wird ja aus den Metadaten gelesen und kann dort doch durchaus auch 1 sein.
Die letzte Zeile in ``if`` und ``else`` ist jeweils nahezu gleich, das wäre besser nur einmal nach dem ``if``, denn das ``else`` fällt dann weg, weil das nur aus dieser einen Zeile besteht.
Das entfernen von dem "C" bei der Temperatur aus den Metadaten würde ich expliziter machen und auch prüfen ob da tatsächlich ein "C" verworfen wird. Nicht das da am Ende irgendwann auch mal "K" oder "F" steht und dann mit der falschen Temperatureinheit weitergerechnet wird.
Die Dokumentation von `process_image()` ist falsch. Oder wo wird da was in einen h5-Handler geschrieben? Die Funktion macht auch ein bisschen zu viel für meinen Geschmack, die könnte man sinnvoll aufteilen.
`json` hat auch eine `loads()`-Funktion. Das ist einfacher als die Daten erst in ein `io.StringIO`-Objekt zu verpacken und dann `json.load()` zu übergeben.
Die bedingte Reduktion der Dimension muss eigentlich immer stattfinden, denn wenn da keine Liste mit *einem* Element geliefert wird, dann hat der nachfolgende Code ”unlösbare” Probleme mit dem Rückgabewert und fällt dann halt dort auf die Nase.
Ungetesteter Zwischenstand:
Einige Namen sind schlecht gewählt. Was soll denn bitte `filt` bedeuten? Namen sollen dem Leser vermitteln was der Wert der dahinter steckt im Kontext des Programms bedeutet. Kryptische Abkürzungen bewirken da eher das Gegenteil.
In `process_image()` ist das definieren von Namen teilweise zu weit von der Stelle entfernt an der sie dann tatsächlich verwendet werden. Die Funktion ist auch recht lang und verwendet recht viele lokale Namen. Wenn man da Definitionen und Verwendung so weit über die ganze Funktion verstreut, macht es das unnötig schwerer die Funktion zu verstehen und aufzuteilen.
`os.path.split()` + magischem Index wird statt `os.path.dirname()` oder `os.path.basename()` verwendet, oder halt `os.path.split()` *einmal* und daraus dann *beide* Ergebnisse gleich an Namen binden, ohne magische Indexwerte. Entfällt/wird einfacher wenn man `pathlib` verwendet.
Es wird zwar oft von „tuple unpacking“ gesprochen, aber es ist eigentlich „iterable unpacking“. Es ist nicht notwendig den Wert der da entpackt werden soll tatsächlich extra in ein Tupel umzuwandeln.
Es wird an vielen Stellen die `format()`-Methode benutzt, wo man f-Zeichenkettenliterale verwenden könnte.
Der Kommentar vor ``if radiometric_corr:`` passt nicht so ganz zum Code denn der Wert für `emissivity` wird ja aus den Metadaten gelesen und kann dort doch durchaus auch 1 sein.
Die letzte Zeile in ``if`` und ``else`` ist jeweils nahezu gleich, das wäre besser nur einmal nach dem ``if``, denn das ``else`` fällt dann weg, weil das nur aus dieser einen Zeile besteht.
Das entfernen von dem "C" bei der Temperatur aus den Metadaten würde ich expliziter machen und auch prüfen ob da tatsächlich ein "C" verworfen wird. Nicht das da am Ende irgendwann auch mal "K" oder "F" steht und dann mit der falschen Temperatureinheit weitergerechnet wird.
Die Dokumentation von `process_image()` ist falsch. Oder wo wird da was in einen h5-Handler geschrieben? Die Funktion macht auch ein bisschen zu viel für meinen Geschmack, die könnte man sinnvoll aufteilen.
`json` hat auch eine `loads()`-Funktion. Das ist einfacher als die Daten erst in ein `io.StringIO`-Objekt zu verpacken und dann `json.load()` zu übergeben.
Die bedingte Reduktion der Dimension muss eigentlich immer stattfinden, denn wenn da keine Liste mit *einem* Element geliefert wird, dann hat der nachfolgende Code ”unlösbare” Probleme mit dem Rückgabewert und fällt dann halt dort auf die Nase.
Ungetesteter Zwischenstand:
Code: Alles auswählen
#!/usr/bin/env python3
import io
import json
import subprocess
from pathlib import Path
import matplotlib.image
import numpy as np
import PIL.Image
import skimage
#
# Specify the name format (this should be standard for FLIR jpgs).
#
INPUT_FILE_MASK = "*_T.jpg"
#
# Input the exiftool location (you may need to download it).
#
EXIFTOOL = (
"C:/Users/CopterLogServices/Desktop/TEST_ConvertRJPGtoTIFF/exiftool.exe"
)
def get_string_meta_data(file_path):
"""
Read all exif data using exiftool.
"""
return json.load(
subprocess.check_output([EXIFTOOL, "-json", str(file_path)])
)[0]
def get_raw_thermal_image(file_path, key="RawThermalImage"):
"""
Use exiftool to extract 'RawThermalImage' from FLIR-JPG.
"""
image_file_data = subprocess.check_output(
[EXIFTOOL, "-binary", f"-{key}", str(file_path)]
)
return np.array(PIL.Image.open(io.BytesIO(image_file_data)))
def process_image(
file_path, radiometric_correction=True, save_false_colour_png=False
):
#
# Conversion to temperature:
# according to http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,4898.msg23972.html#msg23972
#
# Extract radiometric parameters.
#
meta_data = get_string_meta_data(file_path)
r_1, r_2, b, f, o = (
meta_data[f"Planck{name}"] for name in ("R1", "R2", "B", "F", "O")
)
image_data = get_raw_thermal_image(file_path)
if radiometric_correction:
emissivity = meta_data["Emissivity"]
#
# Drop the C on the temperature and increase to Kelvin.
#
value_text, unit = meta_data["ReflectedApparentTemperature"].split()
if unit != "C":
raise ValueError(f"expected temperature unit 'C', got {unit!r}")
reflected_temperature = float(value_text) + 273.15
reflected_factor = (
r_1 / (r_2 * (np.exp(b / reflected_temperature) - f)) - o
)
image_data = (
image_data - (1 - emissivity) * reflected_factor
) / emissivity
temperature_data = b / np.log(r_1 / (r_2 * (image_data + o)) + f)
if save_false_colour_png:
matplotlib.image.imsave(
file_path.with_suffix(".png"),
skimage.exposure.rescale_intensity(temperature_data),
cmap="inferno",
)
PIL.Image.fromarray(temperature_data).save(file_path.with_suffix(".tiff"))
def main():
#
# Set the folder location that holds the radiometric jpgs files will be
# saved as tiff files with the same name.
#
# If specified, the images will also be saved as regular jpegs in a colormap
# suitable for thermal images.
#
# This option will not produce publishing quality images as there is no
# contrast adjustment or other processing.
#
folder = Path(
"C:/Users/CopterLogServices/Desktop/TEST_ConvertRJPGtoTIFF/footage"
)
for file_path in folder.glob(INPUT_FILE_MASK):
process_image(
file_path, radiometric_correction=True, save_false_colour_png=False
)
if __name__ == "__main__":
main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari