Why is Gaussian Filter different between cv2 and skimage?

11,266

Solution 1

If anyone is curious about how to make skimage.gaussian_filter() match Matlab's equivalent imgaussfilt() (the reason I found this question), pass the parameter 'truncate=2' to skimage.gaussian_filter(). Both skimage and Matlab calculate the kernel size as a function of sigma. Matlab's default is 2. Skimage's default is 4, resulting in a significantly larger kernel by default.

Solution 2

For GaussianBlur, you are using a rather large kernel (size=33), which causes a lot of smoothing. Smoothing will depend drastically on you kernel size. With your parameters each new pixel value is "averaged" in a 33*33 pixel "window".

A definition of cv2.GaussianBlur can be found here http://docs.opencv.org/3.1.0/d4/d13/tutorial_py_filtering.html#gsc.tab=0

In contrast, skimage.filters.gaussian seems to work on a smaller kernel. In skimage, the "size" is defined by sigma which is related to kernel size as described here: https://en.wikipedia.org/wiki/Gaussian_filter

Definition can be found here: http://scikit-image.org/docs/dev/api/skimage.filters.html#skimage.filters.gaussian

In order to get corresponding results, you'd have to work with a smaller kernel for OpenCV.

Furthermore, for both libraries, I'd strongly recommend to use up to date library versions.

Solution 3

These two are equal:

gau_img = cv2.GaussianBlur(img, (5,5), 10.0) # 5*5 kernal, 2 on each side. 2 = 1/5 * 10 = 1/5 * sigma
gau_img = skimage.filters.gaussian(img, sigma=10, truncate=1/5)

The whole Gaussian kernel is defined by sigma only. But which part of gaussian kernel do you use to blur the image is defined by truncate (in skimage) or ksize (in opencv).

Share:
11,266
waldol1
Author by

waldol1

Updated on June 11, 2022

Comments

  • waldol1
    waldol1 almost 2 years

    I've got an image that I apply a Gaussian Blur to using both cv2.GaussianBlur and skimage.gaussian_filter libraries, but I get significantly different results. I'm curious as to why, and what can be done to make skimage look more like cv2. I know skimage.gaussian_filter is a wrapper around scipy.scipy.ndimage.filters.gaussian_filter. To clearly state the question, why are the two functions different and what can be done to make them more similar?

    Here is my test image:

    Original Image

    Here is the cv2 version (appears blurrier):

    cv2 image

    Here is the skimage/scipy version (appears sharper):

    skimage version

    Details:

    skimage_response = skimage.filters.gaussian_filter(im, 2, multichannel=True, mode='reflect')

    cv2_response = cv2.GaussianBlur(im, (33, 33), 2)

    So sigma=2 and the size of the filter is big enough that it shouldn't make a difference. Imagemagick covnert -gaussian-blur 0x2 visually agrees with cv2.

    Versions: cv2=2.4.10, skimage=0.11.3, scipy=0.13.3

  • waldol1
    waldol1 about 8 years
    The amount of smoothing is controlled by sigma, not the size. Pixels are not straight averaged, they are weighted averaged by a Gaussian kernel. Size just truncates computation and skimage computes a size that's 4*sigma. The versions shouldn't be the issue. This is old and basic functionality.
  • tfv
    tfv about 8 years
    As far as I can read here, you are using a deprecated funtion gaussian_filter scikit-image.org/docs/dev/api/… , but you are correct that this is basic functionality. You are also corrrect that sigma correlates to kernel size. However, I do not understand why a siga of 2 you are using in scikit should be equivalent to a kernel size of 33 in OpenCV.
  • tfv
    tfv about 8 years
    I am no mathematician, but the way I read en.wikipedia.org/wiki/Gaussian_filter , [quote] "A gaussian kernel requires 6{\sigma}-1 values, e.g. for a {\sigma} of 3 it needs a kernel of length 17". This would mean that your sima=2 is equivalent to a kernel of size 6*2-1=11. Sorry, I am no expert on this, but you may want to review your size assumtion.
  • waldol1
    waldol1 about 8 years
    Mathematically, a Gaussian kernel has infinite size, just the values far away from the center are so small that they can be ignored. The function gaussian_filter is deprecated, but I suspect that it is a name change only because they both just wrap the scipy filter. Scipy makes the size 8 * sigma + 1 (or 4 * sigma * 2 sides + 1 center), and opencv does something similar, but adding precision by a larger size shouldn't make it more or less blurry visually.
  • Paulo Scardine
    Paulo Scardine over 6 years
    Good to know but this is not really an answer. Sometimes I abuse the site posting a comment as an answer because the text would not fit a comment or because the comment includes code and the comment system does not handle well longer snippets of code - but I guess your text fits a comment.
  • dhamechaSpeaks
    dhamechaSpeaks over 3 years
    If I use the above, if truncate is 4.0 and sigma is 5.0, this may not work, right? Then it looks like the kernel size should be (0.25, 0.25)? But opencv requires the ksize to be positive and odd.
  • Haotao Wang
    Haotao Wang over 3 years
    @dhamechaSpeaks The ksize is required to be positive and odd because the kernel has to be symmetric. If ksize=5, then there are 2 pixels on each side. In this case, the truncate parameter in skimage should be set to (ksize-1)/2/sigma = 2/sigma
  • Andrew Marshall
    Andrew Marshall over 2 years
    Yes, this answer is not correct. You can have as large a kernel as you like, but sigma controls the weights in the kernel. A sigma value of 1.0 and a kernel size of, say 99, should give the same result as sigma=1.0 and a kernel size of 9. It's just that the larger kernel will contain mostly zeroes.