Atheer
Atheer

Reputation: 921

Creating gray-level co-occurrence matrix from 16-bit image

I have a data set of images that are 16-bit and I want to create GLCM matrix from them to extract GLCM features.

However, the resulting matrix shows one value (as shown in the picture below), I wonder why.

16glcm

I tried using the same image but converted to 8-bit, the resulted GLCM show several values.

8glcm

Note: I used the following Matlab function:

glcm_matrix = graycomatrix(image.tif);

Here is a cropped sample from the 16-bit image:

rescaled_crop

Note: The image used in the computations can be downloaded from here. The original image is very low contrast and looks totally dark. The image shown above has its contrast stretched and is intended only for visualization purposes.

EDIT:

I used

glcm_matrix = graycomatrix(image.tif, 'GrayLimits', []); 

and it gives me the following results:

16glcmfixed

Upvotes: 1

Views: 1317

Answers (2)

Tonechas
Tonechas

Reputation: 13733

I'd just like to build on @Tapio's excellent answer.

The GLCM yielded by graycomatrix when you use the name/value pair GrayLimits', [] in the function call looks good. However, this approach might not be valid for your application. If you compute the GLCMs for a set of images in this way, the same elements of two different GLCMs corresponding to two different images are likely to have a different meaning. Indeed, as the intensity is being rescaled differently for each image, the components of the GLCM are actually encoding different co-occurrences from one image to another.

To avoid this you could first calculate the minimum and maximum intensities over the whole image dataset (for example minImgs and maxImgs) and then use those values to rescale the intensity of all the images that make up the dataset in the exact same way:

glcm_matrix = graycomatrix(image_tif, 'GrayLimits', [minImgs maxImgs]); 

Upvotes: 2

Tapio
Tapio

Reputation: 1642

It was a binning/scaling problem.

Let's take a peek inside:

edit graycomatrix

In this case we're interested in the two options, 'NumLevels' and 'GrayLimits'

%   'NumLevels'      An integer specifying the number of gray levels to use
%                    when scaling the grayscale values in I. For example,
%                    if 'NumLevels' is 8, GRAYCOMATRIX scales the values in
%                    I so they are integers between 1 and 8.  The number of
%                    gray levels determines the size of the gray-level
%                    co-occurrence matrix (GLCM).
%
%                    'NumLevels' must be an integer. 'NumLevels' must be 2
%                    if I is logical.
%  
%                    Default: 8 for numeric
%                             2 for logical
%
%   'GrayLimits'     A two-element vector, [LOW HIGH], that specifies how 
%                    the values in I are scaled into gray levels. If N is
%                    the number of gray levels (see parameter 'NumLevels')
%                    to use for scaling, the range [LOW HIGH] is divided
%                    into N equal width bins and values in a bin get mapped
%                    to a single gray level. Grayscale values less than or
%                    equal to LOW are scaled to 1. Grayscale values greater
%                    than or equal to HIGH are scaled to NumLevels. If
%                    'GrayLimits' is set to [], GRAYCOMATRIX uses the
%                    minimum and maximum grayscale values in I as limits,
%                    [min(I(:)) max(I(:))].

So in other words the function was binning your data into 8x8 bins and assuming that the scaling range was the full uint16 range (0-65535). However that sample image I you gave has a minimum of 305 and a maximum of 769, making it fall into the first bin (0-8192 or so). When I call A = graycomatrix(I) it gives me the following matrix :

A =

    6600           0           0           0           0           0           0           0
       0           0           0           0           0           0           0           0
       0           0           0           0           0           0           0           0
       0           0           0           0           0           0           0           0
       0           0           0           0           0           0           0           0
       0           0           0           0           0           0           0           0
       0           0           0           0           0           0           0           0
       0           0           0           0           0           0           0           0

However when A = graycomatrix(I,'GrayLimits', []) is called the scaling range is taken as min(I) - max(I), and the function works as expected :

A =
       4           2           1           0           0           0           0           0
       1           1           2           2           0           0           0           0
       2           2           4           7           1           0           0           0
       0           1           7         142          72           1           0           0
       0           0           0          65        1711         252           0           0
       0           0           0           0         230        3055         178           0
       0           0           0           0           0         178         654           8
       0           0           0           0           0           0           8           9

In your original example the single value is in the middle of the 8x8 matrix most likely because your original images are int16 and not uint16, so the graycomatrix is symmetric to take into account the possibility of negative values.

You can also of course scale the original images to fit their datatypes. For example percentile scaling might be a good idea if you expect outliers etc.

Upvotes: 3

Related Questions