Applying Color Ramp to Single-Band Grayscale Images


Brandon Victor
 

Hello Eyat,

I just realised I didn't respond. Definitely, if it's not a once-off, a programmatic solution is the best way. Option #2 can be used with negative integers; the gotchya is that matplotlib interprets floating point numbers as scaling between 0-1, and integers as scaling between 0-256. You'll also have to set the dtype to int16 if your DEMs are stored in uint8 or int16 and you are doing a subtraction. You just have to set your range to include the negative values. Something like this (you can also replace np.int16 with np.float32 if you need):

```python
data = np.random.uniform(-256, 256, (100, 100)).astype(np.int16)
cmap_dict = {n: np.array(cmap(int((n+256)/2)))*256 for n in range(-256, 256, 2)}
with rasterio.open('scraps/mapped.tif', 'w', width=100, height=100, count=1, dtype=np.int16) as dst:
    dst.write(data, 1)
    dst.write_colormap(1, cmap_dict)
```

There are at least two reasons option #3 is not recommended:
  1. You bake the colours into the image, meaning that for downstream users, there's no practical way to recover the variable of interest from the image. That might be you, or it might be other people.
  2. You are multiplying your data storage requirements. This may or may not be relevant to you. Smaller files are easier to deal with.
Of course, the benefits of option #3 are that you have a more portable file; it could even be opened by a non-GIS image viewer. I assumed that processing utility was paramount; perhaps I shouldn't have.

Perhaps it's too untimely a response for you, but maybe it will help anyone else who stumbles on this page.


Eyal Saiet
 

Hello Brandon,
Thanks very much for the detailed response. Unforetonetly I cannot use a GUI because my project is a software that continuous (not a one-time)  analysis change (basically subtracting DEMs), sometimes the difference will include negative values. Thus I don't think I can use uint8 #option 2. Thus seems I will need to go with option #3. Why is option #3 not recommended?
Apart from options #2 and #3 how do people create spatial figures (.tif) with a consistent color scheme to reflect the quantity of a change?


On Fri, Apr 8, 2022 at 7:22 PM Brandon Victor <interdimensional.cabbage@...> wrote:
Here's my two cents,

The way I see it, you have three options to convert a greyscale image into a colour-mapped version.

  1. You can just import your greyscale data into ArcGIS/QGIS and tell it how to render that using the colourmap you want. In QGIS, this option is called "Singleband Pseudocolor".
  2. You can create your own colourmap dictionary from matplotlib (or another library) and add that to the tif with `write_colormap()`
  3. You can modify the greyscale image to just BE the colours.


``` python
import rasterio
import numpy as np
import matplotlib.cm

cmap = matplotlib.cm.get_cmap('viridis')
data = np.random.uniform(0, 256, (100, 100)).astype(np.uint8)

# Option 1: Just use greyscale, and then interpret it in GIS software
with rasterio.open('greyscale.tif', 'w', width=100, height=100, count=1, dtype=np.uint8) as dst:
    dst.write(data, 1)

# Option 2: Explicitly add a cmap obtained from somewhere else
cmap_dict = {n: np.array(cmap(n))*256 for n in range(256)}
with rasterio.open('mapped.tif', 'w', width=100, height=100, count=1, dtype=np.uint8) as dst:
    dst.write(data, 1)
    dst.write_colormap(1, cmap_dict)

# Option 3: Save the greyscale as a coloured image (not recommended)
colour = (cmap(data)*256).astype(np.uint8) # shaped [100, 100, {RGBA}]
with rasterio.open('coloured.tif', 'w', width=100, height=100, count=3, dtype=np.uint8) as dst:
    for x in range(3):
        dst.write(colour[..., x], x+1)
```

I think you are asking about option 2. The answer, then, is that you can just use matplotlib's colourmap library to generate your colormap for you.

Most GIS software allow you to do Option 1 very easily, anyway. So if it's a one-off, it's probably easier to create/select your colormap using a GUI.

Good luck.



--


Eyal Saiet

Project manager
Remote sensing and in-situ measurements

Geophysical Institute 
University of Alaska Fairbanks
Fairbanks, AK 99775
(907) 750 6555 (cell)



The mind is not a vessel to be filled, but a fire to be kindled. Plutarch


Brandon Victor
 

Here's my two cents,

The way I see it, you have three options to convert a greyscale image into a colour-mapped version.

  1. You can just import your greyscale data into ArcGIS/QGIS and tell it how to render that using the colourmap you want. In QGIS, this option is called "Singleband Pseudocolor".
  2. You can create your own colourmap dictionary from matplotlib (or another library) and add that to the tif with `write_colormap()`
  3. You can modify the greyscale image to just BE the colours.


``` python
import rasterio
import numpy as np
import matplotlib.cm

cmap = matplotlib.cm.get_cmap('viridis')
data = np.random.uniform(0, 256, (100, 100)).astype(np.uint8)

# Option 1: Just use greyscale, and then interpret it in GIS software
with rasterio.open('greyscale.tif', 'w', width=100, height=100, count=1, dtype=np.uint8) as dst:
    dst.write(data, 1)

# Option 2: Explicitly add a cmap obtained from somewhere else
cmap_dict = {n: np.array(cmap(n))*256 for n in range(256)}
with rasterio.open('mapped.tif', 'w', width=100, height=100, count=1, dtype=np.uint8) as dst:
    dst.write(data, 1)
    dst.write_colormap(1, cmap_dict)

# Option 3: Save the greyscale as a coloured image (not recommended)
colour = (cmap(data)*256).astype(np.uint8) # shaped [100, 100, {RGBA}]
with rasterio.open('coloured.tif', 'w', width=100, height=100, count=3, dtype=np.uint8) as dst:
    for x in range(3):
        dst.write(colour[..., x], x+1)
```

I think you are asking about option 2. The answer, then, is that you can just use matplotlib's colourmap library to generate your colormap for you.

Most GIS software allow you to do Option 1 very easily, anyway. So if it's a one-off, it's probably easier to create/select your colormap using a GUI.

Good luck.


Eyal Saiet
 

Hello Sean,
I am at the same place Nathan was a few years ago, and have not seen more development in rasterio on that font. If I would like to use a coloramp like "spectrum" in the matplolib library or something similar in ArcGIS/QGIS what is the format of a file to read a coloramp (.csv,.json,.txt, etc')? Do I need to generate the color ramp myself (dininiary) for each pixel value from 0-256 (8 bit)? The example you referred, to, and the only thing I found in the Rasterio Documentation is a classified raster with only a few colors.
dst.write_colormap(
            1, {
                0: (255, 0, 0, 255),
                255: (0, 0, 255, 255) })
https://rasterio.readthedocs.io/en/latest/topics/color.html

Does Rasterio not have a coloramp library likematplotlib has (https://matplotlib.org/stable/gallery/color/colormap_reference.html)?
Thanks

On Wed, Mar 25, 2020 at 10:04 AM Sean Gillies <sean.gillies@...> wrote:
Hi,

Have you seen https://rasterio.readthedocs.io/en/latest/topics/color.html#writing-colormaps ? It shows how to write a colormap (or color "ramp") to a new file. You can also open an existing file in "r+" mode and call the dataset's write_colormap() method.

On Tue, Mar 24, 2020 at 4:12 PM <nathan.raley@...> wrote:
Does anyone have any methods of applying a color ramp to a grayscale image? 

I have a NDVI calculated image I am trying to apply color ramp for the decimal based value ranges, but have no idea how to accomplish this.  I was wandering if this was possible via any of the rasterio libraries, and, if so, how would one go about accomplishing this?  I have other band based calculations I'd like to attempt, but until I can figure out how to apply the color ramps, I am at a stand still.

Thanks,

--
Sean Gillies



--


Eyal Saiet

Project manager
Remote sensing and in-situ measurements

Geophysical Institute 
University of Alaska Fairbanks
Fairbanks, AK 99775
(907) 750 6555 (cell)



The mind is not a vessel to be filled, but a fire to be kindled. Plutarch


Sean Gillies
 

Hi,

Have you seen https://rasterio.readthedocs.io/en/latest/topics/color.html#writing-colormaps ? It shows how to write a colormap (or color "ramp") to a new file. You can also open an existing file in "r+" mode and call the dataset's write_colormap() method.

On Tue, Mar 24, 2020 at 4:12 PM <nathan.raley@...> wrote:
Does anyone have any methods of applying a color ramp to a grayscale image? 

I have a NDVI calculated image I am trying to apply color ramp for the decimal based value ranges, but have no idea how to accomplish this.  I was wandering if this was possible via any of the rasterio libraries, and, if so, how would one go about accomplishing this?  I have other band based calculations I'd like to attempt, but until I can figure out how to apply the color ramps, I am at a stand still.

Thanks,

--
Sean Gillies


nathan.raley@...
 

Does anyone have any methods of applying a color ramp to a grayscale image? 

I have a NDVI calculated image I am trying to apply color ramp for the decimal based value ranges, but have no idea how to accomplish this.  I was wandering if this was possible via any of the rasterio libraries, and, if so, how would one go about accomplishing this?  I have other band based calculations I'd like to attempt, but until I can figure out how to apply the color ramps, I am at a stand still.

Thanks,