Sitemap

Distance Transformation

Photogrammetry-1

7 min readApr 7, 2026

--

So, I have recently implemented Distance Transform as part of an exercise while taking the course Photogrammetry-1 by Prof. Cyrill Stachniss. The main idea of the algorithm is to find out the distance between each image pixel and the foreground/background. What we do is fairly simple. We do 2 passes of the image. In the first pass, we go through the image as usual row by row, finding neighbors of each pixel and finding the distance from that pixel to the background/foreground using the neighbors which can be either 4 or 8. In the second pass, we go from bottom to top and from right to left while calculating distances as we did in the first pass.

Press enter or click to view image in full size
Considering that we are interested in distance calculation from the background. We assume 1 to represent foreground while 0 representing background.

In the example above, the pixel under consideration is the one with dot inside it. The distance from background is 1 using the neighbor above the pixel while it is 2 if we consider the neighbor to the left. We calculate distances from all neighbors and choose the minimum as the distance of the pixel from the background. The example shown utilizes N4 neighborhood, similar methodology can be applied for N8 neighborhood with the exception that the number of neighbors will be increased.

Get Talha Hanif Butt’s stories in your inbox

Join Medium for free to get updates from this writer.

So far, we have talked about the first pass of the image. We need to perform a second pass through the image which will be in reverse order which means instead of going from left to right and top to bottom, we will go from right to left and bottom to top. We will follow the same pattern, that is, selecting the minimum distance as we go along the reverse pass and assign a new distance to the current pixel if a shorter distance than current value is found.

In short, what we need is a distance matrix, representing distance of each pixel from the background/foreground, we can either find distance from background or foreground, we perform 2 passes of the image, one from top-down, left-right while the second from bottom-top, right-left, find neighbors and calculate distance of the neighbors to the foreground/background, which means going in a particular direction until we hit a background/foreground pixel or the end/start of the image, and choose the minimum as the distance of the current pixel.

The code of the algorithm is as follows:

import os
import cv2
import numpy as np
%matplotlib inline
from matplotlib import pyplot as plt
import random
import skimage

def distance_transformation(binary_img, neighborhood):

distance_image = np.zeros(np.shape(binary_img)) # image to get output as distance image

for row in range(np.shape(binary_img)[0]): # loop over the image rows
for col in range(np.shape(binary_img)[1]): # loop over the image columns

if binary_img[row,col] == 1: # check if it's a foreground pixel

if neighborhood == 4: # if we are considering 4 neighbors

row_up = row # saving row number to process for neighbors in the upward direction
col_up = col # saving column number to process for neighbors in the upward direction
dist_up = 0 # distance in the upward direction

row_left = row # saving row number to process for neighbors in the left direction
col_left = col # saving column number to process for neighbors in the left direction
dist_left = 0 # distance in the left direction

while row_up - 1 >= 0 and binary_img[row_up,col_up] == 1: # go in the upward direction until we reach end of neighbors or we hit a background pixel

row_up -= 1 # move upwards
dist_up += 1 # add a pixel as a distance to the background

while col_left - 1 >= 0 and binary_img[row_left,col_left] == 1: # go in the left direction until we reach end of neighbors or we hit a background pixel

col_left -= 1 # move left
dist_left += 1 # add a pixel as a distance to the background

if dist_left < dist_up: # assign distance from left if it is shorter else assign distance from the top

distance_image[row,col] = dist_left

else:

distance_image[row,col] = dist_up

if neighborhood == 8: # if we are considering 8 neighbors

row_up = row # saving row number to process for neighbors in the upward direction
col_up = col # saving column number to process for neighbors in the upward direction
dist_up = 0 # distance in the upward direction

row_left = row # saving row number to process for neighbors in the left direction
col_left = col # saving column number to process for neighbors in the left direction
dist_left = 0 # distance in the left direction

row_left_diagonal = row # saving row number to process for neighbors in the left diagonal direction
col_left_diagonal = col # saving column number to process for neighbors in the left diagonal direction
dist_left_diagonal = 0 # distance in the left diagonal direction

row_right_diagonal = row # saving row number to process for neighbors in the right diagonal direction
col_right_diagonal = col # saving column number to process for neighbors in the right diagonal direction
dist_right_diagonal = 0 # distance in the right diagonal direction

while row_up - 1 >= 0 and binary_img[row_up,col_up] == 1: # go in the upward direction until we reach end of neighbors or we hit a background pixel

row_up -= 1 # move upwards
dist_up += 1 # add a pixel as a distance to the background

while col_left - 1 >= 0 and binary_img[row_left,col_left] == 1: # go in the left direction until we reach end of neighbors or we hit a background pixel

col_left -= 1 # move left
dist_left += 1 # add a pixel as a distance to the background

while row_left_diagonal - 1 >= 0 and col_left_diagonal - 1 >= 0 and binary_img[row_left_diagonal,col_left_diagonal] == 1: # go in the left diagonal direction until we reach end of neighbors or we hit a background pixel

row_left_diagonal -= 1 # move left diagonal
col_left_diagonal -= 1 # move left diagonal
dist_left_diagonal += 1 # add a pixel as a distance to the background

while row_right_diagonal - 1 >= 0 and col_right_diagonal + 1 < np.shape(binary_img)[1] and binary_img[row_right_diagonal,col_right_diagonal] == 1: # go in the right diagonal direction until we reach end of neighbors or we hit a background pixel

row_right_diagonal -= 1 # move right diagonal
col_right_diagonal += 1 # move right diagonal
dist_right_diagonal += 1 # add a pixel as a distance to the background


distance_image[row,col] = min([dist_up, dist_left, dist_left_diagonal, dist_right_diagonal]) # assign the minimum distance to the current pixel location


for row in range(np.shape(binary_img)[0]-1,-1,-1): # loop over the image rows in reverse order
for col in range(np.shape(binary_img)[1]-1,-1,-1): # loop over the image columns in reverse order

if binary_img[row,col] == 1: # check if it's a foreground pixel

if neighborhood == 4: # if we are considering 4 neighbors

row_down = row # saving row for processing neighbors in the down direction
col_down = col # saving column for processing neighbors in the down direction
dist_down = 0 # distance in the down direction

row_right = row # saving row for processing neighbors in the right direction
col_right = col # saving column for processing neighbors in the right direction
dist_right = 0 # distance in the right direction

while row_down + 1 < np.shape(binary_img)[0] and binary_img[row_down,col_down] == 1: # go in the down direction until we reach end of neighbors or we hit a background pixel

row_down += 1 # move down
dist_down += 1 # add a pixel as a distance to the background

while col_right + 1 < np.shape(binary_img)[1] and binary_img[row_right,col_right] == 1: # go in the right direction until we reach end of neighbors or we hit a background pixel

col_right += 1 # move right
dist_right += 1 # add a pixel as a distance to the background

distance_image[row,col] = min([dist_down, dist_right, distance_image[row,col]]) # assign the minimum distance to the current pixel location

if neighborhood == 8: # if we are considering 8 neighbors

row_down = row # saving row for processing neighbors in the down direction
col_down = col # saving column for processing neighbors in the down direction
dist_down = 0 # distance in the down direction

row_right = row # saving row for processing neighbors in the right direction
col_right = col # saving column for processing neighbors in the right direction
dist_right = 0 # distance in the right direction

row_down_right_diagonal = row # saving row for processing neighbors in the down right diagonal direction
col_down_right_diagonal = col # saving column for processing neighbors in the down right diagonal direction
dist_down_right_diagonal = 0 # distance in the down right diagonal direction

row_down_left_digonal = row # saving row for processing neighbors in the down left diagonal direction
col_down_left_diagonal = col # saving column for processing neighbors in the down left diagonal direction
dist_down_left_diagonal = 0 # distance in the down left diagonal direction

while row_down + 1 < np.shape(binary_img)[0] and binary_img[row_down,col_down] == 1: # go in the down direction until we reach end of neighbors or we hit a background pixel

row_down += 1 # move down
dist_down += 1 # add a pixel as a distance to the background

while col_right + 1 < np.shape(binary_img)[1] and binary_img[row_right,col_right] == 1: # go in the right direction until we reach end of neighbors or we hit a background pixel

col_right += 1 # move right
dist_right += 1 # add a pixel as a distance to the background

while row_down_right_diagonal + 1 < np.shape(binary_img)[0] and col_down_right_diagonal + 1 < np.shape(binary_img)[1] and binary_img[row_down_right_diagonal,col_down_right_diagonal] == 1: # go in the down right diagonal direction until we reach end of neighbors or we hit a backgraound pixel

row_down_right_diagonal += 1 # move down right diagonal
col_down_right_diagonal += 1 # move down right diagonal
dist_down_right_diagonal += 1 # add a pixel as a distance to the background

while row_down_left_digonal + 1 < np.shape(binary_img)[0] and col_down_left_diagonal - 1 >= 0 and binary_img[row_down_left_digonal,col_down_left_diagonal] == 1: # go in the down left diagonal direction until we reach end of neighbors or we hit a background pixel

row_down_left_digonal += 1 # move down left diagonal
col_down_left_diagonal -= 1 # move down left diagonal
dist_down_left_diagonal += 1 # add a pixel as a distance to the background

distance_image[row,col] = min([dist_down, dist_right, dist_down_right_diagonal, dist_down_left_diagonal, distance_image[row,col]]) # assign the minimum distance to the current pixel location

return distance_image

I have used Adobe-240 dataset for this implementation. This video helped me understand the algorithm. That’s it for now. See you later.

--

--