# vtkImageDilateErode3D elliptical footprint is approximated as a square/cube

**URL:** <https://discourse.vtk.org/t/vtkimagedilateerode3d-elliptical-footprint-is-approximated-as-a-square-cube/16086>\
**Category:** Development\
**Created:** [October 7, 2025, 9:05pm UTC](https://discourse.vtk.org/t/vtkimagedilateerode3d-elliptical-footprint-is-approximated-as-a-square-cube/16086 "2025-10-07T21:05:05Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![user27182](https://discourse.vtk.org/user_avatar/discourse.vtk.org/user27182/32/10104_2.png) [@user27182](https://discourse.vtk.org/u/user27182)\
**Post date:** [October 7, 2025, 9:05pm UTC](https://discourse.vtk.org/t/vtkimagedilateerode3d-elliptical-footprint-is-approximated-as-a-square-cube/16086/1 "2025-10-07T21:05:06Z")

</div>

`vtkImageDilateErode3D` uses an elliptical footprint. But, for a 3x3 kernel, it seems that the ellipse is approximated as a square (or cube for 3D). Is this a bug? I would have expected more of a cross (i.e. rounded corners).

Output from the code below:

```auto
Input image:
[[0 0 0 0 0]
 [0 0 0 0 0]
 [0 0 255 0 0]
 [0 0 0 0 0]
 [0 0 0 0 0]]
Dilated image:
[[0 0 0 0 0]
 [0 255 255 255 0]
 [0 255 255 255 0]
 [0 255 255 255 0]
 [0 0 0 0 0]]

```

Expected output:

```auto
Dilated image:
[[0 0 0 0 0]
 [0 0 255 0 0]
 [0 255 255 255 0]
 [0 0 255 0 0]
 [0 0 0 0 0]]

```

```py
import vtk
import numpy as np

# Create a 5x5 image with one bright pixel in the center
size = 5
image = vtk.vtkImageData()
image.SetDimensions(size, size, 1)
image.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 1)

# Fill background with 0
for y in range(size):
    for x in range(size):
        image.SetScalarComponentFromFloat(x, y, 0, 0, 0)

# Set center pixel to 255
image.SetScalarComponentFromFloat(size // 2, size // 2, 0, 0, 255)

# Dilate image
dilate = vtk.vtkImageDilateErode3D()
dilate.SetInputData(image)
dilate.SetKernelSize(3, 3, 1)
dilate.SetDilateValue(255)
dilate.SetErodeValue(0)
dilate.Update()

# Show input and output arrays
def vtk_to_array(img):
    dims = img.GetDimensions()
    arr = np.zeros((dims[1], dims[0]), dtype=np.uint8)
    for y in range(dims[1]):
        for x in range(dims[0]):
            arr[y, x] = int(img.GetScalarComponentAsFloat(x, y, 0, 0))
    return arr

input_arr = vtk_to_array(image)
output_arr = vtk_to_array(dilate.GetOutput())

print("Input image:")
print(input_arr)
print("\nDilated image:")
print(output_arr)

```

---

<div class="post-metadata">

**Author:** ![user27182](https://discourse.vtk.org/user_avatar/discourse.vtk.org/user27182/32/10104_2.png) [@user27182](https://discourse.vtk.org/u/user27182)\
**Post date:** [October 7, 2025, 9:27pm UTC](https://discourse.vtk.org/t/vtkimagedilateerode3d-elliptical-footprint-is-approximated-as-a-square-cube/16086/2 "2025-10-07T21:27:39Z")

</div>

Both cases are a coarse approximation of an ellipse. If we compute the area, we have

- true area: pi\*1.5^2 = 7.07
- area of square: 3x3 = 9
- area of cross: 5

So it seems that a square is a _slightly_ better approximation of the ellipse.

I compared this to `scikit-image`’s elliptical footprint, and the result matches VTK, so this does seem like the correct approximation.

```auto
>>> from skimage.morphology import footprints
>>> footprints.ellipse(1,1)
array([[1, 1, 1],
       [1, 1, 1],
       [1, 1, 1]], dtype=uint8)

```

However, it would be nice to be able to manually specify the footprint, instead of only having ellipse as an option for these filters.

---

<div class="post-metadata">

**Author:** ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)\
**Post date:** [October 8, 2025, 2:28am UTC](https://discourse.vtk.org/t/vtkimagedilateerode3d-elliptical-footprint-is-approximated-as-a-square-cube/16086/3 "2025-10-08T02:28:47Z")

</div>

I haven’t really seen any demand for morphological operations with non-ellipsoidal kernels. A cross-shaped 3x3 kernel could be achieved by changing the interface to allow the diameter to be a non-integer value, so that might be the best approach.

The reason that a radius of 3 pixels gives a 3x3 square is simple math. The corner pixels are at a distance of sqrt(2) from the center, and sqrt(2) = 1.414. This is less than the radius of 1.5 of a 3x3 elliptical kernel, therefore, the corner pixels are considered to be inside the ellipse. A cross could be achieved by specifying any radius with a value greater than 1.0 and less than sqrt(2).
