1

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

Tonechas
  • 13,398
  • 16
  • 46
  • 80
gin
  • 873
  • 2
  • 12
  • 23

2 Answers2

3

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.

Tapio
  • 1,502
  • 1
  • 12
  • 24
  • Thank you so much for your explanation, by scaling images you mean upscaling/downscaling (resizing) them, or changing the scale range? and can you elaborate on how can scaling helps in fitting datatypes? Also, for the 'NumLevels' and 'GrayLimits', How to choose the suitable levels and range? according to: https://www.researchgate.net/post/How_to_select_the_number_of_levels_in_GLCM. by increasing the number of levels until the point where entropy of the GLCM starts growing linearly. or there is a better way to select the levels, same for the scale range values? – gin Feb 09 '19 at 21:18
  • Changing the scale range. I like Tonechas idea, computing the min-max of the whole dataset should keep the results comparable between images instead of having the bins jump around. If there is a better way I'm not familiar with it. – Tapio Feb 10 '19 at 21:25
2

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]); 
Tonechas
  • 13,398
  • 16
  • 46
  • 80
  • Thank you, sir, for your note! so you suggest using the max and the min intensities of the whole dataset to generalize the extracted GLCM matrices – gin Feb 09 '19 at 21:47
  • Exactly. By doing so classification accuracy should get improved. – Tonechas Feb 09 '19 at 21:49
  • Great! what about the 'NumLevels' the number of grey levels, the default levels are 8, but I'm not sure whether to leave it as it is or should I change it. – gin Feb 09 '19 at 22:02
  • You could try out other values and see the results. If you do so, I would recommend you to use the same `NumLevels` for all the image data set. – Tonechas Feb 09 '19 at 22:07