2

I want to find the GLCM matrix using python (numpy) I've written this code and it gave me a correct result from the four angles but it very slow , to processes 1000 picture with demonsion 128x128 it take about 35min

def getGLCM(image, distance, direction):

    npPixel = np.array(image) // image as numpy array

    glcm = np.zeros((255, 255), dtype=int)
    if direction == 1:  # direction 90° up ↑
        for i in range(distance, npPixel.shape[0]):
            for j in range(0, npPixel.shape[1]):
                glcm[npPixel[i, j], npPixel[i-distance, j]] += 1
    elif direction == 2:  # direction 45° up-right ↗
        for i in range(distance, npPixel.shape[0]):
            for j in range(0, npPixel.shape[1] - distance):
                glcm[npPixel[i, j], npPixel[i - distance, j + distance]] += 1
    elif direction == 3:  # direction 0° right →
        for i in range(0, npPixel.shape[0]):
            for j in range(0, npPixel.shape[1] - distance):
                glcm[npPixel[i, j], npPixel[i, j + distance]] += 1
    elif direction == 4:  # direction -45° down-right ↘
        for i in range(0, npPixel.shape[0] - distance):
            for j in range(0, npPixel.shape[1] - distance):
                glcm[npPixel[i, j], npPixel[i + distance, j + distance]] += 1

    return glcm

I need help to make this code faster Thanks.

KAnouar
  • 27
  • 5

1 Answers1

2

There is a bug in your code. You need to change the initialization of the gray level co-occurrence matrix to glcm = np.zeros((256, 256), dtype=int), otherwise if the image to process contains some pixels with the intensity level 255, the function getGLCM will throw an error.

Here's a pure NumPy implementation that improves performance through vectorization:

def vectorized_glcm(image, distance, direction):

    img = np.array(image)

    glcm = np.zeros((256, 256), dtype=int)
    
    if direction == 1:
        first = img[distance:, :]
        second = img[:-distance, :]
    elif direction == 2:
        first = img[distance:, :-distance]
        second = img[:-distance, distance:]
    elif direction == 3:
        first = img[:, :-distance]
        second = img[:, distance:]
    elif direction == 4:
        first = img[:-distance, :-distance]
        second = img[distance:, distance:]
    
    for i, j in zip(first.ravel(), second.ravel()):
        glcm[i, j] += 1
        
    return glcm

If you are open to use other packages, I would strongly recommend you to utilize scikit-image's greycomatrix. As shown below, this speeds up the calculation by two orders of magnitude.

Demo

In [93]: from skimage import data

In [94]: from skimage.feature import greycomatrix

In [95]: img = data.camera()

In [96]: a = getGLCM(img, 1, 1)

In [97]: b = vectorized_glcm(img, 1, 1)

In [98]: c = greycomatrix(img, distances=[1], angles=[-np.pi/2], levels=256)

In [99]: np.array_equal(a, b)
Out[99]: True

In [100]: np.array_equal(a, c[:, :, 0, 0])
Out[100]: True

In [101]: %timeit getGLCM(img, 1, 1)
240 ms ± 1.16 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [102]: %timeit vectorized_glcm(img, 1, 1)
203 ms ± 3.11 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [103]: %timeit greycomatrix(img, distances=[1], angles=[-np.pi/2], levels=256)
1.46 ms ± 15.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Community
  • 1
  • 1
Tonechas
  • 13,398
  • 16
  • 46
  • 80
  • This way is better than my way, But the difference is about 40ms not a much difference , thank you. I believe u need initialize`first` and `second` variables. and I have already use skimages in my project but when I got the features vectors and use it to evaluate my machine I got only 0.29 precision (29% of the correct) to compare between two vectore I calculate the **Distance** with `np.linalg.norm( featuresVector1- featuresVector2)`. my dataSet is good , i got 0.78 precision with **KNN** and 0.89 with **Color Histograme**, I don't know why i goot only 0.29 with **GLCM**, any Idea – KAnouar May 23 '19 at 20:41
  • 1
    I agree that a 15% drop in computing time is not sufficient for you application (but it's a significant improvement anyways). I don't think it's necessary to initialize `first` and `second`. My code had a bug, though, because I was not using parameter `distance` (thanks to @Noureim for the edit). And last, you are more likely to get help with this issue if you ask a new question. – Tonechas May 24 '19 at 00:04