OpenCV's dilate differs from scipy, matlab

970 Views Asked by At
import numpy as np
import cv2
import scipy.ndimage as sn

timg = np.array([[0,0,0,0],
                 [0,0,1,0],
                 [0,0,0,0],
                 [0,0,0,0]])

tker = np.array([[1,1,0],
                 [1,1,1],
                 [1,1,1]])

scipy.ndimage:

>>> print(sn.morphology.binary_dilation(timg,tker).astype(int))

[[0 1 1 0]
 [0 1 1 1]
 [0 1 1 1]
 [0 0 0 0]]

OpenCV:

>>> print(cv2.dilate(timg.astype(np.uint8), tker.astype(np.uint8)))

[[0 1 1 1]
 [0 1 1 1]
 [0 0 1 1]
 [0 0 0 0]]

It seems as if ndimage places the kernel on the image's one 1 pixel and dilates it to wherever the kernel is 1, while OpenCV places the kernel on each pixel and sets it to the maximum of its neighbors (when the kernel is 1).

Which behavior is right? Wikipedia's animation seems to favor OpenCV. If I'm calling the wrong functions, is there any way to reproduce OpenCV's behavior with scipy?

Side notes:

  • matlab behaves like scipy
  • scipy's behavior also occurs in grey_dilation (though I wouldn't expect it to change behaviour)
1

There are 1 best solutions below

2
On BEST ANSWER

There are 2 different definitions of the dilation, which differ in a mirroring of the structuring element. Both satisfy all properties of the dilation, so there is no “right” way to do it. Either definition is valid.

These two libraries use opposite definitions of the dilation. To go from the one to the other, mirror the structuring element. Note that in 2D, mirroring is the same as rotating by 180 degrees:

tker = np.array([[1,1,0],
                 [1,1,1],
                 [1,1,1]])
tker2 = np.rot90(tker, 2)