Question: I have following cells: cells = np.array([[1, 1, 1], [1, 1, 0], [1, 0, 0], [1, 0, 1], [1, 0, 0], [1, 1, 1]])  and I want to calculate horizontal and vertical adjacencies to come to this result: # horizontal adjacency array([[3, 2, 1], [2, 1, 0], [1, 0, 0], [1, 0, 1], [1, 0, 0], [3, 2, 1]]) # vertical adjacency array([[6, 2, 1], [5, 1, 0], [4, 0, 0], [3, 0, 1], [2, 0, 0], [1, 1, 1]])  The actual sollution looks like this: def get_horizontal_adjacency(cells): adjacency_horizontal = np.zeros(cells.shape, dtype=int) for y in range(cells.shape[0]): span = 0 for x in reversed(range(cells.shape[1])): if cells[y, x] > 0: span += 1 else: span = 0 adjacency_horizontal[y, x] = span return adjacency_horizontal def get_vertical_adjacency(cells): adjacency_vertical = np.zeros(cells.shape, dtype=int) for x in range(cells.shape[1]): span = 0 for y in reversed(range(cells.shape[0])): if cells[y, x] > 0: span += 1 else: span = 0 adjacency_vertical[y, x] = span return adjacency_vertical  The Algorithm is basically (for horizontal adjacency):  loop throgh rows loop backward throgh columns if the x, y value of cells is not zero, add 1 to the actual span if the x, y value of cells is zero, reset actual span to zero set the span as new x, y value of the resulting array  Since I need to loop two times over all array elements this is slow for bigger arrays (e.g. images). Is there a way to improve the algorithm using vectorization or some other numpy magic? Summary: Great suggestions have been made by joni and Mark Setchell! I created a small Repo with a sample image and a python file with the comparisons. The results are astonishing:  Original Approach: 3.675 s Using Numba: 0.002 s Using Cython: 0.005 s 

Answer: I had a really quick attempt at this with Numba but have not checked it too thoroughly though the results seem about right: #!/usr/bin/env python3 # https://stackoverflow.com/q/69854335/2836621 # magick -size 1920x1080 xc:black -fill white -draw "circle 960,540 960,1040" -fill black -draw "circle 960,540 960,800" a.png import cv2 import numpy as np import numba as nb def get_horizontal_adjacency(cells): adjacency_horizontal = np.zeros(cells.shape, dtype=int) for y in range(cells.shape[0]): span = 0 for x in reversed(range(cells.shape[1])): if cells[y, x] > 0: span += 1 else: span = 0 adjacency_horizontal[y, x] = span return adjacency_horizontal @nb.jit('void(uint8[:,::1], int32[:,::1])',parallel=True) def nb_get_horizontal_adjacency(cells, result): for y in nb.prange(cells.shape[0]): span = 0 for x in range(cells.shape[1]-1,-1,-1): if cells[y, x] > 0: span += 1 else: span = 0 result[y, x] = span return # Load image im = cv2.imread('a.png', cv2.IMREAD_GRAYSCALE) %timeit get_horizontal_adjacency(im) result = np.zeros((im.shape[0],im.shape[1]),dtype=np.int32) %timeit nb_get_horizontal_adjacency(im, result)  The timings are good, showing 4000x speed-up, if it works correctly: In [15]: %timeit nb_get_horizontal_adjacency(im, result) 695 µs ± 9.12 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) In [17]: %timeit get_horizontal_adjacency(im) 2.78 s ± 44.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)  Input Input image was created in 1080p dimensions, i.e. 1920x1080, with ImageMagick using: magick -size 1920x1080 xc:black -fill white -draw "circle 960,540 960,1040" -fill black -draw "circle 960,540 960,800" a.png   Output (contrast adjusted)