A thermal JPEG can contain an ordinary preview, standard image metadata, and manufacturer-specific measurement information. Renaming it as a text file does not extract any of those structures. This workflow is for inspection and integration teams that need searchable metadata without confusing image headers with temperature measurements. You will identify the supported reader, export the available fields, flatten nested records into tab-separated text, and check that names, units, and repeated records survive.
Decide which metadata you actually need
Choose the export scope before choosing a conversion tool. A general image reader may expose dimensions and descriptive tags while leaving proprietary measurement blocks undecoded.
| Information needed | Suitable starting point | What the output does not establish |
|---|---|---|
| JPEG dimensions and encoding information | A reader that reports standard JPEG headers | Whether radiometric measurements exist |
| Acquisition time and descriptive tags | A metadata reader supporting the tags present | Whether timestamps include a time zone or describe acquisition |
| Measurement settings and calibration identifiers | Manufacturer-supported application, SDK, or documented reader | Whether every setting is available in every file |
| Embedded measurement arrays | Documented radiometric export workflow | Whether ordinary metadata fields contain pixel temperatures |
A .jpg extension identifies a file format, not a measurement contract. Some thermal JPEG files include additional measurement information; others contain only a rendered image and ordinary tags. Confirm the actual file type through its documented acquisition workflow.
If you need a pixel array rather than descriptive fields, follow the separate workflow for exporting high-bitdepth grayscale images. If you need temperatures from sensor values, use the raw-count calibration guidance. Neither task should be silently folded into a metadata export.
Prepare the original file and an export contract
- Work from an untouched acquisition file. Make a copy before opening it in software that might resave images. Record its filename, byte size, and a content hash if traceability matters.
- Choose a reader for the required scope. For ordinary headers, use a reader supporting the relevant JPEG metadata structures. For proprietary fields, use the manufacturer's supported application or SDK, obtained through its official distribution channel.
- Write down the expected fields. Specify the field name, expected type, unit if applicable, and whether multiple records can occur. Mark essential fields separately from optional ones.
Treat an export contract as a small acceptance checklist. For example, your application might require an acquisition timestamp, a measurement-settings record, and a calibration identifier. Their exact names and availability must come from the supported reader's documentation, not assumptions about other cameras.
Keep acquisition time, file modification time, and export time separate. A timestamp without a documented time zone should remain explicitly unspecified; do not silently label it as UTC.
Export structured metadata before flattening it
- Export all relevant records through the supported interface. Prefer a documented structured export when available. Otherwise, use the SDK's documented field-access functions to create an intermediate JSON document.
- Preserve the original structure and meanings. Retain group names, repeated records, array order, unit fields, identifiers, and missing-value indicators. Save reader warnings and unsupported-field notices in a companion log.
Do not assume every application offers JSON output. If it exports another structured format, a small adapter may be necessary. Keep that adapter separate from the flattening stage so you can test extraction and formatting independently.
Avoid selecting only the first returned record. Later entries may describe additional images, settings groups, or other metadata objects. Inspect the documented record structure before filtering anything.
When both raw and interpreted values are available, retain them with distinct names. A reader may display a friendly description for an encoded value, but that description should not overwrite the original identifier.
Binary blocks need a separate decision. Preserve the original file and record the block's identifier and size when the reader exposes them. Use a documented decoder for meaningful interpretation rather than treating arbitrary bytes as text.
An ordinary color preview is not a substitute for these fields. The explanation of mapping thermal image colors to values shows why rendered colors alone do not establish measurement values.
Flatten the exported JSON into a text table
- Use one row per field path, not one wide row per image. This long-table layout handles nested objects and repeated records without inventing hundreds of columns.
The example below uses Python's standard library. It reads an already exported JSON document; it does not decode proprietary JPEG blocks. Its output is a UTF-8, tab-separated .txt file containing the source filename, source hash, field path, value type, and JSON-encoded value.
Field paths use JSON Pointer escaping: ~ becomes ~0, and / inside a field name becomes ~1. Array indexes remain in the path, so separate records stay separate. Container rows identify objects and arrays, including empty ones.
import csv
import hashlib
import json
import sys
from pathlib import Path
def unique_object(pairs):
obj = {}
for key, value in pairs:
if key in obj:
raise ValueError(f"Duplicate JSON key: {key!r}")
obj[key] = value
return obj
def escape_token(token):
return str(token).replace("~", "~0").replace("/", "~1")
def flatten(value, path=""):
if isinstance(value, dict):
yield path, "object", {}
for key, child in value.items():
yield from flatten(child, path + "/" + escape_token(key))
elif isinstance(value, list):
yield path, "array", []
for index, child in enumerate(value):
yield from flatten(child, path + "/" + str(index))
else:
kinds = {
type(None): "null", bool: "boolean", int: "integer",
float: "number", str: "string"
}
yield path, kinds[type(value)], value
metadata_path = Path(sys.argv[1])
image_path = Path(sys.argv[2])
output_path = Path(sys.argv[3])
inputs = {metadata_path.resolve(), image_path.resolve()}
if output_path.resolve() in inputs:
raise ValueError("Output must not overwrite an input file")
with metadata_path.open(encoding="utf-8-sig") as handle:
metadata = json.load(handle, object_pairs_hook=unique_object)
source_hash = hashlib.sha256(image_path.read_bytes()).hexdigest()
with output_path.open("w", encoding="utf-8", newline="") as handle:
writer = csv.writer(handle, delimiter="\t", lineterminator="\n")
writer.writerow([
"source_file", "source_sha256", "field_path",
"value_type", "value_json"
])
for path, kind, value in flatten(metadata):
encoded = json.dumps(value, ensure_ascii=False, allow_nan=False)
writer.writerow([image_path.name, source_hash, path, kind, encoded])
Run the script after creating the structured export:
python flatten_metadata.py metadata.json original.jpg metadata.txt
Use a different output filename for every export you intend to retain. The script protects its input files, but an existing output file will be replaced.
The source hash identifies the image supplied to this conversion step. It does not prove that the JSON was extracted from that image; maintain that association during extraction.
JSON encoding preserves embedded tabs, line breaks, quotes, and null values without manual string concatenation. Duplicate object keys cause an error rather than silently replacing an earlier field.
Verify names, units, and record counts
- Test the layout with a small known example. The following JSON is illustrative, not a promised camera export schema:
{
"frames": [
{
"temperature": {
"value": 21.5,
"unit": "degC"
}
},
{
"temperature": {
"value": 22.0,
"unit": "degC"
}
}
]
}
The scalar portion of the text output should contain these paths:
| Field path | Value type | JSON value |
|---|---|---|
/frames/0/temperature/value |
number | 21.5 |
/frames/0/temperature/unit |
string | "degC" |
/frames/1/temperature/value |
number | 22.0 |
/frames/1/temperature/unit |
string | "degC" |
Count the expected output explicitly:
The output therefore contains ten data rows plus its header. The empty path identifies the root container. An object or array row is a structural marker, not a second copy of its descendants.
- Compare a real export against the supported reader. Check representative fields from every relevant group, including the last repeated record. Verify exact field paths, values, units, and whether missing fields differ from fields explicitly set to null.
-
Read the text back with a tab-separated parser. Confirm the column count and decode
value_jsonrather than interpreting its contents by appearance. Spreadsheet software can alter timestamps, identifiers, and long numbers during import.
For batch processing, track an extraction status for each file. If you select twelve images and one fails, the job should report eleven successful exports and one failure—not silently present the successful subset as complete.
Diagnose common export failures
| Symptom | Likely cause | Test and correction |
|---|---|---|
| Dimensions appear, but measurement fields do not | Reader supports ordinary headers only, or file lacks those fields | Compare the same original in the supported application |
| Only one metadata record survives | Export code selects the first element | Inspect array lengths before and after flattening |
| Different fields share a column name | Nested group names were discarded | Retain the complete escaped path |
| A value has no unit | Unit field was omitted, or the unit is defined externally | Preserve the documented unit or explicitly mark it unknown |
| Text columns shift unexpectedly | Delimiters were inserted through string concatenation | Use a quoting-aware table writer and matching reader |
| Required metadata disappears after editing | The edited copy may not retain additional metadata | Return to the original and compare supported-reader exports |
Do not substitute plausible values for absent metadata. An unknown unit, undocumented field, or unsupported block should remain unresolved until the documented interface establishes its meaning.
Prevent recurrence by saving the reader version, adapter version, and export configuration alongside each batch. Repeat the verification sample after software updates or acquisition-setting changes.
Check acquisition compatibility before ordering
Metadata access is a workflow requirement, not something established by an interface label or a readable preview. Use the infrared cameras category and camera finder to identify acquisition candidates, then request representative files and supported export documentation.
The LS-IRC-0044 is one catalog option for that discussion. Confirm its applicable file and software workflow before specifying metadata requirements.
- Lens mount
- C-mount
- Interface
- GigE
- Resolution
- Up to 3 MP
- Spectrum
- LWIR
The LS-IRC-0016 is another acquisition candidate. Its catalog listing alone does not establish compatibility with this JPEG metadata workflow.
- Interface
- USB3
Before committing to a pipeline, check:
- Original-file access: Can the acquisition system retain the unmodified source rather than only a rendered preview?
- Documented field coverage: Does the supported reader expose every essential metadata group?
- Repeated-record handling: Can the export retain all relevant records and their associations?
- Units and precision: Are units explicit, and can critical numerical values survive the chosen representation?
- Automation rights: Does the intended SDK or batch-export method have the required license and deployment permissions?
- Verification evidence: Have representative files passed field, record-count, and round-trip checks?
If acquisition hardware is still undecided, start with the camera configuration step. For an existing system, send the required field list and a description of the supported export workflow through applications support before changing hardware.
Questions
Can every thermal JPEG provide radiometric metadata?
Not reliably. The filename extension does not indicate whether proprietary measurement information is embedded. Establish compatibility using an original sample file, its acquisition documentation, and the manufacturer's supported reader. A general image library may report valid dimensions while exposing none of the measurement-specific information.
Should metadata be saved as TXT, CSV, or JSON?
A tab-separated text table is convenient for filtering and comparison, while JSON is better suited to preserving the extracted hierarchy. Retain both when possible. Define the delimiter, character encoding, field-path convention, and value representation so another application can read the table consistently.
Why do two readers export different fields from the same image?
Different readers support different metadata groups and may display interpreted descriptions instead of raw identifiers. Compare the same untouched file, record both software versions, and check their documented field coverage. Missing output should not be interpreted as proof that the original file contains no additional metadata.
Does a metadata text export contain a temperature for every pixel?
No. Metadata can include settings, identifiers, and calibration information without exposing a temperature array. Pixel-level temperature extraction requires a documented measurement-data workflow and the relevant calibration model. Keep that operation separate so a metadata table is not mistaken for a temperature map.

