Main Content

Find Vegetation in a Multispectral Image

This example shows how to use MATLAB® array arithmetic to process images and plot image data. In particular, this example works with a three-dimensional image array where the three planes represent the image signal from different parts of the electromagnetic spectrum, including the visible red and near-infrared (NIR) channels.

Image data differences can be used to distinguish different surface features of an image, which have varying reflectivity across different spectral channels. By finding differences between the visible red and NIR channels, the example identifies areas containing significant vegetation.

Step 1: Import Color-Infrared Channels from a Multispectral Image File

This example finds vegetation in a LANDSAT Thematic Mapper image covering part of Paris, France, made available courtesy of Space Imaging, LLC. Seven spectral channels (bands) are stored in one file in the Erdas LAN format. The LAN file, paris.lan, contains a 7-channel 512-by-512 Landsat image. A 128-byte header is followed by the pixel values, which are band interleaved by line (BIL) in order of increasing band number. Pixel values are stored as unsigned 8-bit integers, in little-endian byte order.

The first step is to read bands 4, 3, and 2 from the LAN file using the MATLAB® function multibandread.

Channels 4, 3, and 2 cover the near infrared (NIR), the visible red, and the visible green parts of the electromagnetic spectrum. When they are mapped to the red, green, and blue planes, respectively, of an RGB image, the result is a standard color-infrared (CIR) composite. The final input argument to multibandread specifies which bands to read, and in which order, so that you can construct a composite in a single step.

CIR = multibandread('paris.lan',[512, 512, 7],'uint8=>uint8',...
                    128,'bil','ieee-le',{'Band','Direct',[4 3 2]});

Variable CIR is a 512-by-512-by-3 array of class uint8. It is an RGB image, but with false colors. When the image is displayed, red pixel values signify the NIR channel, green values signify the visible red channel, and blue values signify the visible green channel.

In the CIR image, water features are very dark (the Seine River) and green vegetation appears red (parks and shade trees). Much of the image appearance is due to the fact that healthy, chlorophyll-rich vegetation has a high reflectance in the near infrared. Because the NIR channel is mapped to the red channel in the composite image, any area with a high vegetation density appears red in the display. A noticeable example is the area of bright red on the left edge, a large park (the Bois de Boulogne) located west of central Paris within a bend of the Seine River.

imshow(CIR)
title('CIR Composite')
text(size(CIR,2),size(CIR,1) + 15,...
  'Image courtesy of Space Imaging, LLC',...
  'FontSize',7,'HorizontalAlignment','right')

Figure contains an axes object. The hidden axes object with title CIR Composite contains 2 objects of type image, text.

By analyzing differences between the NIR and red channels, you can quantify this contrast in spectral content between vegetated areas and other surfaces such as pavement, bare soil, buildings, or water.

Step 2: Construct an NIR-Red Spectral Scatter Plot

A scatter plot is a natural place to start when comparing the NIR channel (displayed as red pixel values) with the visible red channel (displayed as green pixel values). It's convenient to extract these channels from the original CIR composite into individual variables. It's also helpful to convert from class uint8 to class single so that the same variables can be used in the NDVI computation below, as well as in the scatter plot.

NIR = im2single(CIR(:,:,1));
R = im2single(CIR(:,:,2));

Viewing the two channels together as grayscale images, you can see how different they look.

imshow(R)
title('Visible Red Band')

Figure contains an axes object. The hidden axes object with title Visible Red Band contains an object of type image.

imshow(NIR)
title('Near Infrared Band')

Figure contains an axes object. The hidden axes object with title Near Infrared Band contains an object of type image.

With one simple call to the plot command in MATLAB, you can create a scatter plot displaying one point per pixel (as a blue cross, in this case), with its x-coordinate determined by its value in the red channel and its y-coordinate by the value its value in the NIR channel.

plot(R,NIR,'+b')
ax = gca;
ax.XLim  = [0 1];
ax.XTick = 0:0.2:1;
ax.YLim  =  [0 1];
ax.YTick = 0:0.2:1;
axis square
xlabel('red level')
ylabel('NIR level')
title('NIR vs. Red Scatter Plot')

Figure contains an axes object. The axes object with title NIR vs. Red Scatter Plot, xlabel red level, ylabel NIR level contains 512 objects of type line.

The appearance of the scatter plot of the Paris scene is characteristic of a temperate urban area with trees in summer foliage. There's a set of pixels near the diagonal for which the NIR and red values are nearly equal. This "gray edge" includes features such as road surfaces and many rooftops. Above and to the left is another set of pixels for which the NIR value is often well above the red value. This zone encompasses essentially all of the green vegetation.

Step 3: Compute Vegetation Index via MATLAB® Array Arithmetic

Observe from the scatter plot that taking the ratio of the NIR level to red level would be one way to locate pixels containing dense vegetation. However, the result would be noisy for dark pixels with small values in both channels. Also notice that the difference between the NIR and red channels should be larger for greater chlorophyll density. The Normalized Difference Vegetation Index (NDVI) is motivated by this second observation. It takes the (NIR - red) difference and normalizes it to help balance out the effects of uneven illumination such as the shadows of clouds or hills. In other words, on a pixel-by-pixel basis subtract the value of the red channel from the value of the NIR channel and divide by their sum.

ndvi = (NIR - R) ./ (NIR + R);

Notice how the array-arithmetic operators in MATLAB make it possible to compute an entire NDVI image in one simple command. Recall that variables R and NIR have class single. This choice uses less storage than class double but unlike an integer class also allows the resulting ratio to assume a smooth gradation of values.

Variable ndvi is a 2-D array of class single with a theoretical maximum range of [-1 1]. You can specify these theoretical limits when displaying ndvi as a grayscale image.

figure
imshow(ndvi,'DisplayRange',[-1 1])
title('Normalized Difference Vegetation Index')

Figure contains an axes object. The hidden axes object with title Normalized Difference Vegetation Index contains an object of type image.

The Seine River appears very dark in the NDVI image. The large light area near the left edge of the image is the park (Bois de Boulogne) noted earlier.

Step 4: Locate Vegetation -- Threshold the NDVI Image

In order to identify pixels most likely to contain significant vegetation, apply a simple threshold to the NDVI image.

threshold = 0.4;
q = (ndvi > threshold);

The percentage of pixels selected is thus

100 * numel(NIR(q(:))) / numel(NIR)
ans = 
5.2204

or about 5 percent.

The park and other smaller areas of vegetation appear white by default when displaying the logical (binary) image q.

imshow(q)
title('NDVI with Threshold Applied')

Figure contains an axes object. The hidden axes object with title NDVI with Threshold Applied contains an object of type image.

Step 5: Link Spectral and Spatial Content

To link the spectral and spatial content, you can locate above-threshold pixels on the NIR-red scatter plot, re-drawing the scatter plot with the above-threshold pixels in a contrasting color (green) and then re-displaying the threshold NDVI image using the same blue-green color scheme. As expected, the pixels having an NDVI value above the threshold appear to the upper left of the rest and correspond to the redder pixels in the CIR composite displays.

Create the scatter plot, then display the thresholded NDVI.

figure
subplot(1,2,1)
plot(R,NIR,'+b')
hold on
plot(R(q(:)),NIR(q(:)),'g+')
axis square
xlabel('red level')
ylabel('NIR level')
title('NIR vs. Red Scatter Plot')

subplot(1,2,2)
imshow(q)
colormap([0 0 1; 0 1 0]);
title('NDVI with Threshold Applied')

Figure contains 2 axes objects. Axes object 1 with title NIR vs. Red Scatter Plot, xlabel red level, ylabel NIR level contains 513 objects of type line. Hidden axes object 2 with title NDVI with Threshold Applied contains an object of type image.

See Also

| |

Related Examples

More About