Files and metadata¶
The Hypervision SDK supports multiple different hyperspectral image formats with a simple and unified interface for reading/writing data.
The supported file types are: ENVI, PAM, and Tiff. The table below shows the supported features of each format.
Feature |
ENVI |
PAM |
Tiff |
|---|---|---|---|
Interleave BSQ |
|||
Interleave BIL/BIP |
(with custom TUPLTYPE) |
||
Wavelength |
|||
Arbitrary metadata |
|||
Jpeg compression |
Working with files¶
The qtec_hv_sdk.open() qtec_hv_sdk.write() qtec_hv_sdk.Image
# All supported file formats are compatible with each other.
# The open/write functions determine the desired format from the file extension.
img = hs.open("<path>.pam")
hs.write(img, "<output-path>.hdr")
# You can write arbitrary qtec_hv_sdk.Image's to a file.
img = qtec_hv_sdk.Image.from_numpy(np.ones((200, 100, 50), dtype=np.uint8), hs.bsq)
hs.write(img, "<output-path>")
Metadata¶
Hyperspectral images are more than just the raw image data. Common metadata includes dimensions and data type, wavelengths, camera and optics information, radiometric scaling, acquisition timing, calibration provenance, sensor artifacts, pixel encoding, and display hints. The SDK stores these values in a single metadata object with grouped sub-objects for each category.
Warning
Both ENVI and Tiff support arbitrary metadata, but PAM only supports the image size and interleave. Therefore, all other metadata will be ignored when writing a PAM file.
All metadata is stored in qtec_hv_sdk.ImageMeta qtec_hv_sdk.Image qtec_hv_sdk.Image.meta
# Show the current metadata
print(img.meta)
# Operations will automatically update the relevant metadata
modified = img.ensure_dtype(hs.float32).binning(2, hs.bands)
print(modified.meta)
// Show the current metadata
hv_image_meta_t* meta = NULL;
err = hv_image_meta(img, &meta);
if (err) return err;
char* meta_str = hv_image_meta_debug_fmt(meta);
printf("%s\n", meta_str);
free(meta_str);
hv_image_meta_free(&meta);
// Operations will automatically update the relevant metadata
// Ensure dtype
hv_image_t* img_f32;
hv_image_ensure_dtype(img, HV_DTYPE_F32, &img_f32);
// Apply a binning of 2 for the bands
hv_image_t* modified;
hv_image_binning(img_f32, 2, HV_AXIS_BANDS, &modified);
hv_image_meta_t* modified_meta = NULL;
err = hv_image_meta(img, &modified_meta);
if (err) return err;
// Show the modified metadata
char* modified_meta_str = hv_image_meta_debug_fmt(modified_meta);
printf("%s\n", modified_meta_str);
free(modified_meta_str);
hv_image_meta_free(&modified_meta);
hv_image_free(&modified);
hv_image_free(&img_f32);
hv_image_free(&img);
qtec_hv_sdk.ImageMeta
Property |
Python class |
Typical contents |
|---|---|---|
|
Raw memory layout, plane shape, and interleave |
|
|
Camera, lens, serial numbers, and pixel pitch |
|
|
Wavelengths, spectral binning, response FWHM |
|
|
Focal length, slit width, spatial ROI, FOV |
|
|
Measurement unit, limits, scaling, gain, noise |
|
|
Exposure, frame time, averaging, trigger mode, timestamps |
|
|
Calibration process, date, and extra calibration info |
|
|
Bad pixels, bad bands, repaired pixels |
|
|
Byte order, scale factor, zero point, bits per pixel |
|
|
Default display bands and band names |
Common fields from the original API remain available as convenience properties. For example,
meta.default_bands updates meta.display.default_bands, meta.wavelength_info updates
meta.spectral.wavelengths, meta.measurement_info maps to the matching radiometric fields, and
meta.byte_order updates meta.encoding.byte_order.
# Get the metadata of the image (note that this is a read-only property, you can't set a new header on an image directly)
meta = img.meta
print(meta)
# You can modify the core metadata to your liking
meta.dtype = hs.float32
meta.interleave = hs.bil
# New metadata is grouped by category
meta.camera = hs.CameraMeta(
manufacturer="Qtechnology",
model_name="Hypervision 1700",
serial="1234",
)
meta.spectral = hs.SpectralMeta(
wavelengths=hs.WavelengthMeta(
[450.0, 550.0, 650.0],
hs.WavelengthUnit.Nanometer,
),
)
meta.radiometric = hs.RadiometricMeta(
unit=hs.MeasurementUnit.Reflectance,
limits=hs.MeasurementLimits(0.0, 1.0),
scaling=1000.0,
)
meta.temporal = hs.TemporalMeta(exposure_time_ms=12.5)
meta.display = hs.DisplayMeta(default_bands=[2, 1, 0])
# You can even set arbitrary attributes on the metadata
# These will be saved for the supported file formats.
meta["custom_field"] = {"val": 2, "otherval": [True, False]}
print(meta["custom_field"])
# It is also possible to create metadata from scratch.
meta = hs.ImageMeta(
shape=hs.ShapeMeta(
streaming_dim=500,
plane_dim=[920, 1096],
interleave=hs.bil,
),
dtype=hs.int64,
description="Plastics sample 2",
camera=hs.CameraMeta(model_name="Lab camera"),
display=hs.DisplayMeta(default_bands=[0, 1, 1]),
)
// Get metadata
hv_image_meta_t* meta = NULL;
hv_image_meta(img, &meta);
// You can modify the metadata to your liking
meta->dtype = HV_DTYPE_F32;
hv_shape_meta_set_interleave(meta->shape, HV_INTERLEAVE_B_I_L);
// You can even set arbitrary attributes on the metadata
// These will be saved for the supported file formats.
hv_image_meta_set(meta, "custom_field", "{\"val\": 2, \"otherval\": [true, false]");
char* meta_str = hv_image_meta_debug_fmt(meta);
printf("%s\n", meta_str);
free(meta_str);
// It is also possible to create a metadata object from scratch
hv_image_meta_t* meta_default = hv_image_meta_default();
Metadata modification¶
At some point, you want to use your modified metadata objects in a qtec_hv_sdk.Image
# You can't modify the metadata of an HSImage directly
try:
img.meta = meta
except AttributeError:
print("Can't write image metadata.")
# Instead, there is a special operation to take a modified metadata object
img = img.with_meta(meta)
# But be careful. There is nothing preventing you from setting invalid metadata values which will
# lead to errors. The following example will fail if the source image is not large enough (which is unlikely)
meta.shape = hs.Shape(2000, 5000, 10000)
try:
img.with_meta(meta).to_numpy()
except ValueError:
print("Shape does not match the source image.")
// To update the metadata on an image object, you first have to retrieve and modify the metadata
hv_image_meta_t* meta;
hv_image_meta(img, &meta);
hv_shape_meta_set_lines(meta->shape, 2000);
hv_shape_meta_set_samples(meta->shape, 5000);
hv_shape_meta_set_bands(meta->shape, 10000);
// and then use an operation to update the image metadata
int err = hv_image_with_meta(img, meta);
// But be careful. There is nothing preventing you from setting invalid meta values which will
// lead to errors. The example above will fail if the source image is not large enough (which is unlikely)