spectralpython / spectral

Python module for hyperspectral image processing
MIT License
574 stars 139 forks source link

How to use iterator function for image masking #116

Closed pythonic2020 closed 3 years ago

pythonic2020 commented 3 years ago

Hello,

I have a floating point cube with lots of zeros in it indicating NoData. I would like to perform band math to generate spectral indices, and want to try masking to avoid the divide-by-zero issues. I can't figure how to use the SPy iterator function to do this. I have tried:

import spectral as spy

# Make mask
non_zero_mask = myimage[:, :, 0] > 0 

mask_iterator = spy.algorithms.iterator(myimage, mask=non_zero_mask)

After that, I have tried using the iterator for looping, etc. but can't get anything to work. Could you please explain what I'm doing wrong? I'll bet the answer is simple.... I can get my ratios going by adding small float values to the bands before dividing them, and that works fine, but I am seeking a more elegant method using masking.

Thank you in advance.

tboggs commented 3 years ago

Not sure if I entirely understand what you're trying to do but if you're working with numpy arrays, using iterators is probably going to be very slow. I would try something like this:

In [26]: x = np.eye(3)                                                                                                                       

In [27]: y = 2 * x                                                                                                                           

In [28]: x                                                                                                                                   
Out[28]: 
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])

In [29]: y                                                                                                                                   
Out[29]: 
array([[2., 0., 0.],
       [0., 2., 0.],
       [0., 0., 2.]])

In [30]: z = np.zeros_like(y)                                                                                                                

In [31]: m = x > 0                                                                                                                           

In [32]: z[m] = x[m] / y[m]                                                                                                                  

In [33]: z                                                                                                                                   
Out[33]: 
array([[0.5, 0. , 0. ],
       [0. , 0.5, 0. ],
       [0. , 0. , 0.5]])
pythonic2020 commented 3 years ago

Very nice! I'll try that now. Many thanks!

Could you also give an example of how your iterator function is intended to be used? It looks powerful, and it piqued my interest.

tboggs commented 3 years ago

That is a base class for other iterators (e.g., ImageIterator) for general iteration over all image pixels (or all pixels associated with a ground truth mask). For most cases (e.g., simple band math), it's much more efficient to just use numpy masks but for some more complicated operations, they are handy. There are some examples in the linked code.

pythonic2020 commented 3 years ago

Thank you for the explanation! :-)