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)
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:
>> 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
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.
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]])
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