Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate perimeter of numpy array

I want to calculate the perimeter of a given numpy array structure. With perimeter i mean the exact perimeter of the structure in the numpy array. The structure could include holes.

My current aproach is something like this:

import numpy   
a = numpy.zeros((6,6), dtype=numpy.int)
a[1:5, 1:5] = 1;a[3,3] = 0
# Way 1
s = ndimage.generate_binary_structure(2,1)
c = ndimage.binary_dilation(a,s).astype(a.dtype)
b = c - a  
numpy.sum(b) # The result, however the hole is calculated as 1, although there are 4 edges

# Way 2
b = ndimage.distance_transform_cdt(a == 0,metric='taxicab') == 1 
b = b.astype(int)
numpy.sum(b) # same as above

enter image description here

As you can see it displays all adjacent cells, however the sum of them doesn't equal the perimeter of the patch. The hole in the example array is calculated as 1 although it correctly has 4 edges. There are similar issues with greater holes of different shapes.

I have asked similar questions in the past, but all provided solutions which somehow didn't resolve in the correct output values in the end. Someone has an idea how to accomplish this? No other packages than numpy, scipy and the base packages please.

like image 487
Curlew Avatar asked Nov 18 '12 18:11

Curlew


2 Answers

Count the number of edges in the interior and at the edges (assumes binary image):

n_interior = abs(diff(a, axis=0)).sum() + abs(diff(a, axis=1)).sum()
n_boundary = a[0,:].sum() + a[:,0].sum() + a[-1,:].sum() + a[:,-1].sum()
perimeter = n_interior + n_boundary

You can leave out n_boundary if the image is properly zero padded.

like image 108
pv. Avatar answered Oct 15 '22 02:10

pv.


Do you mean, in the image, the total number of length-1 edges that separate blue-colored from red-colored tiles? In the picture above this number would be 28. In the example you give in code (which is slightly different, not having the 4 corners differ from the rest of the border tiles) it would be 20.

If that's what you want to compute, you can do something like:

numpy.sum(a[:,1:] != a[:,:-1]) + numpy.sum(a[1:,:] != a[:-1,:])

like image 40
Armin Rigo Avatar answered Oct 15 '22 04:10

Armin Rigo