# Signed distance function from grayscale image

I have a grayscale image and I would like to convert it to a signed distance function.

Right now I'm using DistanceTransform but I do not like the result.

image = Import[FileNameJoin[{NotebookDirectory[], "harbor.png"}]];
levelset =
ImageData[DistanceTransform[ColorNegate[image]] ] -
ImageData[DistanceTransform[image] ];
ListPlot3D[levelset]


harbor.png

output

You can clearly see the outline on the 3d plot which is really noisy, this is probably from the fact that DistanceTransform works on black&white images not on grayscale images.

What I really need is correct gradients near boundary but right now they are complete mess. Is there an easy way how to achieve this?

• Can you explain what you mean by a "signed distance function"? BTW - DistanceTransform does not require a black and white image. Mar 27, 2018 at 13:23

How exact do you need the result to be? You could just binarize an upscaled version of the image:

img = Import["https://i.stack.imgur.com/iMQGZ.png"];
b = Binarize[ImageResize[img, Scaled[8]], .5];
d = DistanceTransform[b] - DistanceTransform[1 - Dilation[b, 1]];


This yields relatively clean-looking gradients:

ListContourPlot[ImageData[d][[;; ;; 8, ;; ;; 8]]]


ListPlot3D[ImageData[d][[;; ;; 8, ;; ;; 8]]]


• Good idea to upscale and then downscale! This should suffice for my purpose.
– tom
Mar 27, 2018 at 15:12
• Just a small improvement. You probably want to divide the result by 8(or by whatever scaling factor you choose). At first I was a bit confused about the values I got.
– tom
Mar 27, 2018 at 15:36