Read ENVI Cube and Process using Model (Explicit Variant)
The example will read the example HSI cube MiniCube.hdr
and process
it using the instrument_function.fluxmdl
, and return the result of
the model for a couple of pixels. The model itself just calculates the
spectral average for each pixel.
This version of the example explicitly creates the processing context from the structure of the loaded cube, in contrast to the other variant of this example, which creates the processing context automatically from the loaded measurement.
C++
The source code of the example can be found in the file
example_read_envi_and_process_explicit.cpp
:
1#if defined(_WIN32) && defined(_MSC_VER)
2#include <windows.h>
3#endif
4
5#include <iostream>
6#include <string>
7#include <fstream>
8#include <streambuf>
9#include <algorithm>
10#include <utility>
11
12#include <cstddef>
13
14#include <fluxEngine/fluxEngine>
15
16#include "paths.h"
17#include "helpers.h"
18
19fluxEngine::ProcessingContext createCubeContextFor(fluxEngine::MeasurementList const& cube, int64_t maxHeight, fluxEngine::Model& model)
20{
21 fluxEngine::ValueType valueType{fluxEngine::ValueType::Intensity};
22 (void) cube.getValueType(0, valueType);
23 auto structure = cube.structure(0);
24 std::vector<double> wavelengths = cube.wavelengths(0);
25
26 fluxEngine::ReferenceInfo referenceInfo;
27 referenceInfo.valueType = valueType;
28 if (cube.hasReference(0, "WhiteReference")) {
29 auto referenceStructure = cube.referenceStructure(0, "WhiteReference");
30 if (referenceStructure.dataType == structure.dataType) {
31 std::pair<void const*, std::size_t> data = cube.rawReferenceData(0, "WhiteReference");
32 referenceInfo.whiteReference = data.first;
33 referenceInfo.whiteReferenceDimensions.push_back(1);
34 referenceInfo.whiteReferenceDimensions.push_back(referenceStructure.dimensions[0]);
35 referenceInfo.whiteReferenceDimensions.push_back(referenceStructure.dimensions[1]);
36 referenceInfo.whiteReferenceDimensions.push_back(referenceStructure.dimensions[2]);
37 }
38 }
39 if (cube.hasReference(0, "DarkReference")) {
40 auto referenceStructure = cube.referenceStructure(0, "DarkReference");
41 if (referenceStructure.dataType == structure.dataType) {
42 std::pair<void const*, std::size_t> data = cube.rawReferenceData(0, "DarkReference");
43 referenceInfo.darkReference = data.first;
44 referenceInfo.darkReferenceDimensions.push_back(1);
45 referenceInfo.darkReferenceDimensions.push_back(referenceStructure.dimensions[0]);
46 referenceInfo.darkReferenceDimensions.push_back(referenceStructure.dimensions[1]);
47 referenceInfo.darkReferenceDimensions.push_back(referenceStructure.dimensions[2]);
48 }
49 }
50
51 if (maxHeight < structure.dimensions[0])
52 maxHeight = structure.dimensions[0];
53
54 int64_t width = structure.dimensions[1];
55
56 return fluxEngine::ProcessingContext(model, fluxEngine::ProcessingContext::HSICube,
57 fluxEngine::HSICube_StorageOrder::BIP, structure.dataType,
58 maxHeight, -1, width, width, wavelengths, referenceInfo);
59}
60
61int main()
62{
63 try {
64 std::cout << "fluxEngine version: " << fluxEngine::versionString() << std::endl;
65 fluxEngine::Handle handle(readFile(g_licenseFileName));
66 handle.createProcessingThreads(4);
67
68 /* NOTE: if the license file is tied to the serial number of a
69 * camera, one must connect with the camera first (see the
70 * device examples for details) for the following lines of code
71 * to work (and not fail with a licensing error).
72 *
73 * If the license is tied to a dongle or a mainboard serial
74 * connecting to a camera is not necessary.
75 */
76
77 // Load data
78 fluxEngine::MeasurementList cubeList = fluxEngine::loadMeasurementList(handle, "ENVI", g_cubeFileName);
79 fluxEngine::Model model = fluxEngine::Model(handle, fluxEngine::Model::FromFile, g_modelFileName);
80
81 // Create a processing context
82 int64_t maxLines = 2048;
83 fluxEngine::ProcessingContext context = createCubeContextFor(cubeList, maxLines, model);
84 int const sinkIndex = context.findOutputSink(/* outputId = */ 0);
85
86 // Process the data
87 context.setSourceData(cubeList, 0);
88 context.processNext();
89 fluxEngine::ProcessingContext::OutputSinkData outputData = context.outputSinkData(sinkIndex);
90 fluxEngine::TensorData view{outputData};
91
92 if (view.order() != 3
93 || view.dataType() != fluxEngine::DataType::Float64
94 || view.dimension(2) != 1)
95 throw std::runtime_error("The model is not expected");
96
97 // The cube we are loading is very small (12x14 pixels),
98 // but if a larger cube is being loaded, this will produce
99 // a _lot_ of output!
100 for (int64_t y = 0; y < view.dimension(0); ++y) {
101 for (int64_t x = 0; x < view.dimension(1); ++x)
102 std::cout << "Pixel (" << x << ", " << y << ") has average value " << view.at<double>(y, x, 0) << '\n';
103 }
104 std::cout << std::flush;
105 } catch (std::exception& e) {
106 std::cerr << "Error: " << e.what() << std::endl;
107 return 1;
108 } catch (...) {
109 std::cerr << "Unknown error." << std::endl;
110 return 1;
111 }
112
113 return 0;
114}
This source file will compile to the executable
ExampleReadENVIAndProcessExplicit
.
The following classes and methods are among those used in this example:
.NET
The source code of the example can be found in the file
ExampleReadENVIAndProcessExplicit\Program.cs
.
1using System;
2
3namespace ExampleReadENVIAndProcessExplicit
4{
5 class Program
6 {
7 static LuxFlux.fluxEngineNET.ProcessingContext CreateCubeContextFor(LuxFlux.fluxEngineNET.MeasurementList cube, Int64 maxHeight, LuxFlux.fluxEngineNET.Model model)
8 {
9 var valueType = cube.GetValueType(0) ?? LuxFlux.fluxEngineNET.ValueType.Intensity;
10 var structure = cube.GetStructure(0);
11 double[] wavelengths = cube.GetWavelengths(0);
12
13 var inputConfiguration = new LuxFlux.fluxEngineNET.ProcessingContext.ExplicitInputConfiguration();
14 inputConfiguration.InputValueType = valueType;
15 inputConfiguration.InputIsIlluminationCorrected = cube.IsIlluminationCorrected(0);
16 inputConfiguration.CalibrationInfo = cube.GetCalibrationInfo(0);
17 var memoryReferenceInfo = new LuxFlux.fluxEngineNET.ProcessingContext.MemoryReferenceInput();
18 if (cube.HasReference(0, "WhiteReference"))
19 {
20 memoryReferenceInfo.WhiteReference = cube.GetReferenceTensorView(0, "WhiteReference").WithInsertedUnityDimension(0);
21 }
22 if (cube.HasReference(0, "IlluminationReference"))
23 {
24 memoryReferenceInfo.IlluminationReference = cube.GetReferenceTensorView(0, "IlluminationReference").WithInsertedUnityDimension(0);
25 }
26 if (cube.HasReference(0, "DarkReference"))
27 {
28 memoryReferenceInfo.DarkReference = cube.GetReferenceTensorView(0, "DarkReference").WithInsertedUnityDimension(0);
29 }
30
31 if (maxHeight < structure.Dimensions[0])
32 maxHeight = structure.Dimensions[0];
33 Int64 width = structure.Dimensions[1];
34
35 inputConfiguration.ReferenceInput = memoryReferenceInfo;
36 return LuxFlux.fluxEngineNET.ProcessingContext.CreateForHSICube(model, LuxFlux.fluxEngineNET.HSICube_StorageOrder.BIP, structure.DataType,
37 maxHeight, -1, width, width, wavelengths, inputConfiguration);
38 }
39
40 static void Main(string[] args)
41 {
42 Console.WriteLine("fluxEngine version: " + LuxFlux.fluxEngineNET.Version.String);
43 var handle = new LuxFlux.fluxEngineNET.Handle(ExampleHelpers.IO.ReadLicenseFile());
44 handle.CreateProcessingThreads(4);
45
46 /* NOTE: if the license file is tied to the serial number of a
47 * camera, one must connect with the camera first (see the
48 * device examples for details) for the following lines of code
49 * to work (and not fail with a licensing error).
50 *
51 * If the license is tied to a dongle or a mainboard serial
52 * connecting to a camera is not necessary.
53 */
54
55 // Load data
56 var cubeList = LuxFlux.fluxEngineNET.IO.LoadMeasurementList(handle, "ENVI", ExampleHelpers.Paths.ExampleDataFileName("MiniCube.hdr"));
57 var model = LuxFlux.fluxEngineNET.Model.LoadFromFile(handle, ExampleHelpers.Paths.ExampleDataFileName("instrument_function.fluxmdl"));
58
59 // Create a processing context
60 Int64 maxLines = 2048;
61 var context = CreateCubeContextFor(cubeList, maxLines, model);
62 int sinkIndex = context.OutputSinkInfoById(/* outputId = */ 0).Index;
63
64 // Process the data
65 context.SetSourceData(cubeList, 0);
66 context.ProcessNext();
67 var outputData = context.OutputSinkData(sinkIndex);
68 var data = outputData.AsTensorCopy();
69
70 if (data.Order != 3 || data.DataType != LuxFlux.fluxEngineNET.DataType.Float64 || data.Dimensions[2] != 1)
71 throw new Exception("The model is not expected");
72
73 // The cube we are loading is very small (12x14 pixels),
74 // but if a larger cube is being loaded, this will produce
75 // a _lot_ of output!
76 for (Int64 y = 0; y < data.Dimensions[0]; ++y)
77 {
78 for (Int64 x = 0; x < data.Dimensions[1]; ++x)
79 {
80 Console.WriteLine($"Pixel ({x}, {y}) has average value {data.Value<double>(y, x, 0)}");
81 }
82 }
83
84 context.Dispose();
85 model.Dispose();
86 cubeList.Dispose();
87 handle.Dispose();
88 }
89 }
90}
The following classes and methods are among those used in this example:
Python
The source code of the example can be found in the file
example_read_envi_and_process_explicit.py
:
1#!/usr/bin/env python3
2
3import fluxEngine
4import os, sys
5
6import fluxEngine_example_paths as paths
7data_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data')
8
9print('fluxEngine version {}'.format(fluxEngine.versionString()))
10with open(paths.licenseFileName, 'rb') as f:
11 handle = fluxEngine.Handle(f.read())
12handle.setDriverBaseDirectory(paths.driverDirectory)
13handle.createProcessingThreads(4)
14
15# NOTE: if the license file is tied to the serial number of a
16# camera, one must connect with the camera first (see the
17# device examples for details) for the following lines of code
18# to work (and not fail with a licensing error).
19#
20# If the license is tied to a dongle or a mainboard serial
21# connecting to a camera is not necessary.
22
23# Load model
24with open(os.path.join(data_dir, 'instrument_function.fluxmdl'), 'rb') as f:
25 model = fluxEngine.Model(handle, f.read())
26
27# Load cube
28cubeList = fluxEngine.loadMeasurementList(handle, 'ENVI', os.path.join(data_dir, 'MiniCube.hdr'))
29
30
31def add_front_unity_dimension(data):
32 return np.reshape(data, (1, ) + data.shape)
33
34def createCubeContextFor(cube, maxHeight, model):
35 valueType = cube.valueType(0)
36 data = cube.data(0)
37
38 referenceInfo = fluxEngine.ReferenceInfo()
39 referenceInfo.valueType = valueType
40 if cube.hasReference(0, "WhiteReference"):
41 referenceInfo.whiteReference = add_front_unity_dimension(cube.referenceData(0, "WhiteReference"))
42 if cube.hasReference(0, "DarkReference"):
43 referenceInfo.darkReference = add_front_unity_dimension(cube.referenceData(0, "DarkReference"))
44
45 if maxHeight < data.shape[0]:
46 maxHeight = data.shape[0]
47 if referenceInfo.whiteReference and maxHeight < referenceInfo.whiteReference.shape[1]:
48 maxHeight = referenceInfo.whiteReference.shape[1]
49 if referenceInfo.darkReference and maxHeight < referenceInfo.darkReference.shape[1]:
50 maxHeight = referenceInfo.darkReference.shape[1]
51 width = data.shape[1]
52
53 return fluxEngine.ProcessingContext(model, fluxEngine.ProcessingContext.HSICube,
54 storageOrder=fluxEngine.HSICube_StorageOrder.BIP,
55 dataType=data.type,
56 maxHeight=maxHeight,
57 height=-1,
58 maxWidth=width,
59 width=width,
60 wavelengths=cube.wavelengths(0),
61 referenceInfo=referenceInfo)
62
63# Create a processing context
64context = fluxEngine.ProcessingContext(model, fluxEngine.ProcessingContext.MeasurementProcessing,
65 measurementList=cubeList, index=0)
66
67sinkIndex = context.findOutputSink(0)
68
69context.setSourceData(cubeList, 0)
70context.processNext()
71outputData = context.outputSinkData(sinkIndex)
72
73# The cube we are loading is very small (12x14 pixels),
74# but if a larger cube is being loaded, this will produce
75# a _lot_ of output!
76print(outputData[:, :, 0])
The following classes and methods are among those used in this example:
Expected Output
The output should look like the following:
fluxEngine version: [...]
Pixel (0, 0) has average value 0.652092
Pixel (1, 0) has average value 0.641689
Pixel (2, 0) has average value 0.633773
Pixel (3, 0) has average value 0.636609
Pixel (4, 0) has average value 0.633638
Pixel (5, 0) has average value 0.648021
Pixel (6, 0) has average value 0.652871
Pixel (7, 0) has average value 0.661865
Pixel (8, 0) has average value 0.655668
Pixel (9, 0) has average value 0.656452
Pixel (10, 0) has average value 0.661276
Pixel (11, 0) has average value 0.671736
Pixel (12, 0) has average value 0.663536
Pixel (13, 0) has average value 0.666235
Pixel (0, 1) has average value 0.664377
Pixel (1, 1) has average value 0.656757
Pixel (2, 1) has average value 0.648442
[...]
Pixel (10, 11) has average value 0.713334
Pixel (11, 11) has average value 0.728156
Pixel (12, 11) has average value 0.725411
Pixel (13, 11) has average value 0.745923