-
Notifications
You must be signed in to change notification settings - Fork 279
Write hyperspectral data #889
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 13 commits
170f590
6bad113
39032ef
a279e48
ebecb03
e28b574
f2002f5
73156b3
47963f9
2aab6d1
074b547
a861499
3b5ac2b
0cf1163
c51e166
a3c8f8f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| ## Write data | ||
|
|
||
| Write a hyperspectral image in ENVI format to the specified file. | ||
| It creates a text header file with extension .hdr and a binary file with | ||
| extension .raw. This function only supports Band-interleaved-by-line (BIL) | ||
| interleave. | ||
|
|
||
| **plantcv.hyperspectral.write_data**(*filename, spectral_data*): | ||
|
|
||
| **returns** Bool | ||
JorgeGtz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| - **Parameters:** | ||
| - filename- desired name of the hyperspectral image file. The extensions are ignored and .hdr and .raw are used. | ||
| - spectral_data- Hyperspectral data object | ||
|
|
||
| - **Context:** | ||
| - Used to save a modified hyperspectral image | ||
|
|
||
| - **Example use:** | ||
|
|
||
| ```python | ||
| from plantcv import plantcv as pcv | ||
|
|
||
| modified_spectral = pcv.Spectral_data(array_data=modified_array_data, | ||
| max_wavelength=list(source_spectral.wavelength_dict.keys())[-1], | ||
| min_wavelength=list(source_spectral.wavelength_dict.keys())[0], | ||
| max_value=float(np.amax(modified_array_data)), | ||
| min_value=float(np.amin(modified_array_data)), | ||
| d_type=modified_array_data.dtype, | ||
| wavelength_dict=source_spectral.wavelength_dict, | ||
| samples=modified_array_data.shape[1], | ||
| lines=modified_array_data.shape[0], interleave='bil', | ||
| wavelength_units=source_spectral.wavelength_units, | ||
| array_type="datacube", | ||
| pseudo_rgb=None, | ||
| filename=source_spectral.filename, | ||
| default_bands=None) | ||
|
|
||
| pcv.hyperspectral.write_data('test-hyperspectral', modified_spectral) | ||
| ``` | ||
|
|
||
| **Source Code:** [Here](https://github.com/danforthcenter/plantcv/blob/master/plantcv/plantcv/hyperspectral/write_data.py) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| import os | ||
| import numpy as np | ||
|
|
||
| from plantcv.plantcv import _version | ||
|
|
||
| __version__ = _version.get_versions()['version'] | ||
|
|
||
| def write_data(filename, spectral_data): | ||
| """Write hyperspectral image data to a file. | ||
| Inputs: | ||
| filename = Name of file to write | ||
| spectral_data = Hyperspectral data object | ||
|
|
||
| Returns: | ||
|
|
||
| :param filename: str | ||
| :param spectral_data: __main__.Spectral_data | ||
| """ | ||
|
|
||
| filename = os.path.splitext(filename)[0] | ||
|
|
||
| # create header | ||
| lines, samples, bands = spectral_data.array_data.shape | ||
| dtype_dict = {'B': "1", 'h': "2", 'i': "3", 'f': "4", 'd': "5", 'F': "6", | ||
| 'D': "9", 'H': "12", 'I': "13", 'l': "14", 'L': "15"} | ||
| wavelenghths = list(spectral_data.wavelength_dict.keys()) | ||
| with open(filename+'.hdr', mode='w') as f: | ||
| f.write('ENVI\n') | ||
| f.write(f'; this file was created using PlantCV version {__version__}\n') | ||
| f.write(f'; original file: {spectral_data.filename}\n') | ||
| f.write('interleave = bil\n') | ||
| f.write(f'samples = {samples}\n') | ||
| f.write(f'lines = {lines}\n') | ||
| f.write(f'bands = {bands}\n') | ||
| f.write(f'data type = {dtype_dict[spectral_data.array_data.dtype.char]}\n') | ||
| f.write(f'wavelength units = {spectral_data.wavelength_units}\n') | ||
| f.write(f'default bands ={spectral_data.default_bands}\n') | ||
| f.write('wavelength = {\n') | ||
| for wl in wavelenghths[:-1]: | ||
| f.write(f'{wl},\n') | ||
| f.write(f'{wavelenghths[-1]}\n') | ||
| f.write('}') | ||
|
|
||
| # create raw binary file containing the hyperspectral array values | ||
| with open(filename+'.raw', mode='w+b') as f: | ||
| f.write(spectral_data.array_data.transpose(0,2,1).tobytes(order='C')) | ||
|
|
||
| return True | ||
JorgeGtz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| import os | ||
| import pytest | ||
| import numpy as np | ||
|
|
||
| from plantcv.plantcv import Spectral_data | ||
| from plantcv.plantcv.hyperspectral import read_data | ||
| from plantcv.plantcv.hyperspectral import write_data | ||
|
|
||
| def test_write_data_default(tmpdir): | ||
| """Test for PlantCV.""" | ||
| rng = np.random.default_rng() | ||
|
|
||
| # Create a test tmp directory | ||
| cache_dir = tmpdir.mkdir("cache") | ||
|
|
||
| lines = 32 | ||
| samples = 32 | ||
| bands = 5 | ||
|
|
||
| # Create random array data in the interval [0-65535] and wavelengths in the | ||
| # interval [400-1000) | ||
| rand_array = rng.integers(0, 65535, size=(lines, samples, bands), dtype=np.uint16, endpoint=True) | ||
| rand_wavelengths = np.sort(600.0*rng.random(size=bands) + 400.0) | ||
| # Create dictionary of wavelengths | ||
| wavelength_dict = {} | ||
| for j, wavelength in enumerate(rand_wavelengths): | ||
| wavelength_dict.update({wavelength: float(j)}) | ||
|
|
||
| # Create spectral data object | ||
| rand_spectral_array = Spectral_data(array_data=rand_array, | ||
| max_wavelength=rand_wavelengths[-1], | ||
| min_wavelength=rand_wavelengths[0], | ||
| max_value=float(np.amax(rand_array)), | ||
| min_value=float(np.amin(rand_array)), | ||
| d_type=rand_array.dtype, | ||
| wavelength_dict=wavelength_dict, | ||
| samples=samples, | ||
| lines=lines, | ||
| interleave='bil', | ||
| wavelength_units='nm', | ||
| array_type="datacube", | ||
| pseudo_rgb=None, | ||
| filename='random_hyperspectral_test', | ||
| default_bands=None) | ||
|
|
||
|
|
||
| filename = os.path.join(cache_dir, 'plantcv_hyperspectral_write_data.raw') | ||
| out = write_data(filename=filename, spectral_data=rand_spectral_array) | ||
JorgeGtz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| # Read written hyperspectral image | ||
| array_data = read_data(filename=filename) | ||
| assert np.shape(array_data.array_data) == (lines, samples, bands) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would going beyond checking if the dimensions are the same to see if some of the values are the same be helpful? Or is just checking that they're the same shape usually sufficient
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is a good question. We could check some values or also verify that it's the exact array. I think it depends on what can go wrong. Since the array is vectorized and written as a binary array, in order to have the correct dimensions the data type and the interleave format should be correct.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok cool, would just a simple
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think both ways are good options
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would going beyond checking if the dimensions are the same to see if some of the values are the same be helpful? Or is just checking that they're the same shape usually sufficient |
||
Uh oh!
There was an error while loading. Please reload this page.