Search code examples
imagematlabsmoothing

Does there exist a way to directly figure out the "smoothness" of a digital image?


There exist several ways to evaluate an image, brightness, saturation, hue, intensity, contrast etc. And we always hear about the operation of smoothing or sharperning an image. From this, there must exist a way to evaluate the overall smoothness of an image and an exact way to figure out this value in one formula probably based on wavelet. Or fortunately anyone could even provide the MATLAB function or combination of them to directly calculate this value.

Thanks in advance!


Solution

  • Smoothness is a vague term. What considered smooth for one application might not be considered smooth for another.

    In the common case, smoothness is a function of the color gradients. Take a 2d gradient on the 3 color channels, then take their magnitude, sqrt(dx^2 + dy^2) and average, sum or some function over the 3 channels. That can give you local smoothness which you can then sum/average/least squares over the image.

    In the more common case, however, linear changes in color is also smooth (think 2 color gradients, or how light might be reflected from an object). For that, a second differential could be more suitable. A laplacian does exactly that.

    I've had much luck using the laplacian operator for calculating smoothness in Python with the scipy/numpy libraries. Similar utilities exist for matlab and other tools.

    Note that the resulting value isn't something absolute from the math books, you should only use it relative to itself and using constants you deem fit.


    Specific how to:

    First get scipy. If you are on Linux it's it available on pypi. For Windows you'll have to use a precompiled version here. You should open the image using scipy.ndimage.imread and then use scipy.ndimage.filters.laplace on the image you read. You don't actually have to mix the channels, you can simply call numpy.average and it should be close enough.

    import scipy as np
    import scipy.ndimage as ndi
    print np.average(np.absolute(ndi.filters.laplace(ndi.imread(path).astype(float) / 255.0)))
    

    This would give the average smoothness (for some meaning of smoothness) of the image. I use np.absolute since values can be positive or negative and we don't want them to even out when averaging. I convert to float and divide by 255 to have values between 0.0 and 1.0 instead of 0 to 256, since it's easier to work with.

    If you want to see the what the laplacian found, you can use matplotlib:

    import matplotlib.pyplot as plt
    v = np.absolute(ndi.filters.laplace(ndi.imread(path).astype(float) / 255.0))
    v2 = np.average(v, axis=2) # Mixing the channels down
    plt.imshow(v2);
    plt.figure();
    plt.imshow(v2 > 0.05);
    plt.show()