Search code examples
pythonmatlabimage-processingscikit-imageglcm

Python Implementation of MATLAB's graycomatrix and graycoprops


image of cat used

source: https://www.petfinder.com/cats/cat-grooming/

I am trying to receive in Python the exact same results of the functions graycomatrix and graycoprops as in MATLAB. But the results differ and I am not able to write the code which will repeat the results from MATLAB.

I need GLCM features like contrast, correlation, energy and homogeneity.

Any advice is very appreciated.

Example code in MATLAB:

% GLCM feature extraction

offset_GLCM = [0 1; -1 1; -1 0; -1 -1];
offset = [1*offset_GLCM ; 2*offset_GLCM; 3*offset_GLCM];

img = rgb2gray(imread('cat.jpg'));
Grauwertmatrix = graycomatrix(img,'NumLevels', 12, 'GrayLimits', [], 'Offset',offset);
GrauwertStats = graycoprops(Grauwertmatrix);
GLCMFeatureVector = [mean(GrauwertStats.Contrast) mean(GrauwertStats.Correlation) mean(GrauwertStats.Energy) mean(GrauwertStats.Homogeneity)];

disp(GLCMFeatureVector);

and the code above returns:

1.6212    0.8862    0.0607    0.7546

Now I want to receive exactly the same results in Python. I use Python code:

# GLCM feature extraction

import numpy as np
from skimage import feature, io
from sklearn import preprocessing

img = io.imread("cat.jpg", as_grey=True)

S = preprocessing.MinMaxScaler((0,11)).fit_transform(img).astype(int)
Grauwertmatrix = feature.greycomatrix(S, [1,2,3], [0, np.pi/4, np.pi/2, 3*np.pi/4], levels=12, symmetric=False, normed=True)

ContrastStats = feature.greycoprops(Grauwertmatrix, 'contrast')
CorrelationtStats = feature.greycoprops(Grauwertmatrix, 'correlation')
HomogeneityStats = feature.greycoprops(Grauwertmatrix, 'homogeneity')
ASMStats = feature.greycoprops(Grauwertmatrix, 'ASM')

print([np.mean(ContrastStats), np.mean(CorrelationtStats),\
np.mean(ASMStats), np.mean(HomogeneityStats)])

But I get the result:

[1.7607, 0.8844, 0.0429, 0.7085]

Another example. Different results on original image. Reason is that MATLAB by default processes image and Python does not. How to get in Python same result as in MATLAB?:

MATLAB:

>> img = rgb2gray(imread('cat.png'));
>> [Grauwertmatrix, S] = graycomatrix(img,'NumLevels',12,'GrayLimits',[0,12],'Offset',[0,1]);
>> Grauwertmatrix(1:5,1:5)

ans =

     4     7     4     8     0
     9    33    22    13    10
     5    18    16    10    10
     2    16    11    22    13
     4    12    11    14    14

Python:

>>> from skimage import io, feature
>>> img = io.imread("cat.png", as_grey=True)
>>> Grauwertmatrix = feature.greycomatrix(img, distances=[1], angles=[0], levels=12, symmetric=False, normed=False)
>>> Grauwertmatrix[0:5, 0:5, 0, 0]
array([[299720,      2,      0,      0,      0],
       [     2,      1,      0,      0,      0],
       [     0,      0,      0,      0,      0],
       [     0,      0,      0,      0,      0],
       [     0,      0,      0,      0,      0]], dtype=uint32)

Solution

  • The GLCM features computed with Matlab and Python are different because the result of preprocessing the original image (namely conversion to grayscale, scaling and requantization) with your Matlab code differs from the result yielded by your Python code (i.e. array S). The following snippets make it apparent:

    Matlab

    >> offset_GLCM = [0 1; -1 1; -1 0; -1 -1];
    >> offset = [1*offset_GLCM ; 2*offset_GLCM; 3*offset_GLCM];
    >> img = rgb2gray(imread('cat.png'));
    >> [Grauwertmatrix, S] = graycomatrix(img,'NumLevels', 12, 'GrayLimits', [], 'Offset',offset);
    
    >> S(100:105, 100:105)
    
    ans =
    
         4     5     7     8     8     6
         5     5     6     7     8     7
         4     4     4     6     7     7
         4     4     5     6     8     8
         5     6     6     7     8     8
         4     5     6     6     7     8
    

    Python

    In [36]: from skimage import io
    
    In [37]: from sklearn import preprocessing
    
    In [38]: img = io.imread("cat.png", as_grey=True)
    
    In [39]: S = preprocessing.MinMaxScaler((0,11)).fit_transform(img).astype(int)
    
    In [40]: S[99:105, 99:105]
    Out[40]: 
    array([[2, 4, 6, 7, 5, 5],
           [2, 3, 4, 5, 6, 5],
           [2, 1, 1, 3, 5, 6],
           [2, 2, 2, 4, 6, 7],
           [3, 4, 4, 5, 6, 7],
           [2, 3, 4, 4, 5, 7]])
    

    As a final remark, I would recommend that you use a lossless image format (such as BMP or PNG) to avoid potential discrepancies due to JPG-decompression.

    WORKAROUND

    In order to obtain the same results through Matlab and Python you should use the same preprocessed image in both cases. Such image can be generated for example like so:

    from skimage import io
    from sklearn import preprocessing
    img = io.imread("cat.png", as_grey=True)
    S = preprocessing.MinMaxScaler((0,11)).fit_transform(img).astype(int)
    io.imsave('cat_preprocessed.png', S)
    

    Notice that the resulting image has very low contrast as the intensity values range from 0 to 11.

    In order for Matlab's graycomatrix to correctly scale this image you need to pass 'NumLevels',12 and 'GrayLimits',[0,12] (rather than [0,11]):

    >> img = imread('cat_preprocessed.png');
    >> [Grauwertmatrix, S] = graycomatrix(img,'NumLevels',12,'GrayLimits',[0,12],'Offset',[0,1]);
    >> Grauwertmatrix(1:5,1:5)
    
    ans =
    
           21258        3250         452         186          91
            3208       20119        5268         827         267
             532        5242       40541        8508        1203
             208         848        8616       26436        6324
             102         285        1192        6216       14101
    
    >> graycoprops(Grauwertmatrix,{'contrast'})
    
    ans = 
    
        Contrast: 0.9681
    

    Python returns the same results:

    In [86]: from skimage import io, feature
    
    In [87]: img = io.imread("cat_preprocessed.png")
    
    In [88]: Grauwertmatrix = feature.greycomatrix(img, distances=[1], angles=[0], levels=12, symmetric=False, normed=False)
    
    In [89]: Grauwertmatrix[0:5, 0:5, 0, 0]
    Out[89]:
    array([[21258,  3250,   452,   186,    91],
           [ 3208, 20119,  5268,   827,   267],
           [  532,  5242, 40541,  8508,  1203],
           [  208,   848,  8616, 26436,  6324],
           [  102,   285,  1192,  6216, 14101]], dtype=uint32)
    
    In [90]: feature.greycoprops(Grauwertmatrix, 'contrast')
    Out[90]: array([[ 0.96812745]])
    

    Edit

    In reply to your comment, I don't think it's possible to obtain the same results from the original RGB image through Matlab and Python since the conversion to grayscale is performed differently. This is clearly stated in the documentation:

    Matlab's rgb2gray:

    rgb2gray converts RGB values to grayscale values by forming a weighted sum of the R, G, and B components:

        0.2989 * R + 0.5870 * G + 0.1140 * B
    

    scikit-image's rgb2gray:

    The weights used in this conversion are calibrated for contemporary CRT phosphors:

    Y = 0.2125 R + 0.7154 G + 0.0721 B