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 hsi.open() hsi.write() hsi.HSImage
# All supported file formats are compatible with each other.
# The open/write functions determine the desired format from the file extension.
img = hsi.open("<path>.pam")
hsi.write(img, "<output-path>.hdr")
# You can write arbitrary hsi.HSImage's to a file.
img = hsi.HSImage.from_numpy(np.ones((200, 100, 50), dtype=np.uint8), hsi.bsq)
hsi.write(img, "<output-path>")
Metadata¶
Hyperspectral images are more than just the raw image data. Common metadata includes the wavelengths of the bands, camera capture metadata (exposure, gain, etc.), data type and image dimensions. The SDK supports reading and adding/modifying arbitrary metadata.
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 hsi.HSIHeader hsi.HSImage hsi.HSImage.header
# Show the current header
print(img.header)
# Operations will automatically update the relevant header data
modified = img.ensure_dtype(hsi.float32).binning(2, hsi.bands)
print(modified.header)
// Show the current header
hv_hsi_header_t* header = NULL;
err = hv_hs_image_header(img, &header);
if (err) return err;
char* header_str = hv_hsi_header_debug_fmt(header);
printf("%s\n", header_str);
free(header_str);
hv_hsi_header_free(&header);
// Operations will automatically update the relevant header data
// Ensure dtype
hv_hs_image_t* img_f32;
hv_hs_image_ensure_dtype(img, HV_DTYPE_F32, &img_f32);
// Apply a binning of 2 for the bands
hv_hs_image_t* modified;
hv_hs_image_binning(img_f32, 2, HV_AXIS_BANDS, &modified);
hv_hsi_header_t* modified_header = NULL;
err = hv_hs_image_header(img, &modified_header);
if (err) return err;
// Show the modified header
char* modified_header_str = hv_hsi_header_debug_fmt(modified_header);
printf("%s\n", modified_header_str);
free(modified_header_str);
hv_hsi_header_free(&modified_header);
hv_hs_image_free(&modified);
hv_hs_image_free(&img_f32);
hv_hs_image_free(&img);
hsi.HSIHeader
# Get the header of the image (note that this is a read-only property, you can't set a new header on an image directly)
header = img.header
print(header)
# You can modify the metadata to your liking
header.dtype = hsi.float32
header.interleave hsi.bil
# You can even set arbitrary attributes on the header
# These will be saved for the supported file formats.
header["custom_field"] = {"val": 2, "otherval": [True, False]}
print(header["custom_field"])
# It is also possible to create a header from scratch
header = hsi.HSIHeader(
# These parameters are mandatory
shape=hsi.Shape((2, 3, 4))
interleave=hsi.bil,
dtype=hsi.int64,
# The rest are optional
description="Plastics sample 2"
)
// Get header
hv_hsi_header_t* header = NULL;
hv_hs_image_header(img, &header);
// You can modify the metadata to your liking
header->dtype = HV_DTYPE_F32;
hv_shape_meta_set_interleave(header->shape, HV_INTERLEAVE_B_I_L);
// You can even set arbitrary attributes on the header
// These will be saved for the supported file formats.
hv_hsi_header_set(header, "custom_field", "{\"val\": 2, \"otherval\": [true, false]")
char* header_str = hv_hsi_header_debug_fmt(header);
printf("%s\n", header_str);
free(header_str);
// It is also possible to create a header from scratch
hv_hsi_header_t* header_default = hv_hsi_header_default();
Header modification¶
At some point, you want to use your modified header objects in a hsi.HSImage
# You can't modify the header of an HSImage directly
try:
img.header = header
except AttributeError:
print("Can't write image header.")
# Instead, there is a special operation to take a modified header
img = img.with_header(header)
# But be careful. There is nothing preventing you from setting invalid header values which will
# lead to errors. The following example will fail if the source image is not large enough (which is unlikely)
header.shape = hsi.Shape(2000, 5000, 10000)
try:
img.with_header(header).to_numpy()
// To update the header on an image object, you first have to retrieve and modify the header
hv_hsi_header_t* header;
hv_hs_image_header(img, &header);
hv_shape_meta_set_lines(header->shape, 2000);
hv_shape_meta_set_samples(header->shape, 5000);
hv_shape_meta_set_bands(header->shape, 10000);
// and then use an operation to update the image header
int err = hv_hs_image_with_header(img, header);
// But be careful. There is nothing preventing you from setting invalid header values which will
// lead to errors. The example above will fail if the source image is not large enough (which is unlikely)