Home > front end >  python function to count nonzero patches in array
python function to count nonzero patches in array

Time:10-28

For a given array (1 or 2-dimensional) I would like to know, how many "patches" there are of nonzero elements. For example, in the array [0, 0, 1, 1, 0, 1, 0, 0] there are two patches.

I came up with a function for the 1-dimensional case, where I first assume the maximal number of patches and then decrease that number if a neighbor of a nonzero element is nonzero, too.

def count_patches_1D(array):
    
    patches = np.count_nonzero(array)
    
    for i in np.nonzero(array)[0][:-1]:
        if (array[i 1] != 0):
            patches -= 1
    return patches

I'm not sure if that method works for two dimensions as well. I haven't come up with a function for that case and I need some help for that.

Edit for clarification: I would like to count connected patches in the 2-dimensional case, including diagonals. So an array [[1, 0], [1, 1]] would have one patch as well as [[1, 0], [0, 1]].

Also, I am wondering if there is a build-in python function for this.

CodePudding user response:

The following should work:

import numpy as np
import copy


# create an array
A = np.array(
    [
        [0, 1, 1, 1, 0, 1],
        [0, 0, 1, 0, 0, 0],
        [1, 0, 0, 1, 0, 1],
        [1, 0, 0, 0, 0, 1],
        [0, 0, 1, 0, 0, 1]
    ]
)

def isadjacent(pos, newpos):
    """
    Check whether two coordinates are adjacent
    """

    # check for adjacent columns and rows
    return np.all(np.abs(np.array(newpos) - np.array(pos)) < 2):


def count_patches(A):
    """
    Count the number of non-zero patches in an array.
    """
    
    # get non-zero coordinates
    coords = np.nonzero(A)

    # add them to a list
    inipatches = list(zip(*coords))
    
    # list to contain all patches
    allpatches = []

    while len(inipatches) > 0:
        patch = [inipatches.pop(0)]

        i = 0
        # check for all points adjacent to the points within the current patch
        while True:
            plen = len(patch)
            curpatch = patch[i]
            remaining = copy.deepcopy(inipatches)
            for j in range(len(remaining)):
                if isadjacent(curpatch, remaining[j]):
                    patch.append(remaining[j])
                    inipatches.remove(remaining[j])
                    if len(inipatches) == 0:
                        break
        
            if len(inipatches) == 0 or plen == len(patch):
                # nothing added to patch or no points remaining
                break

            i  = 1
    
        allpatches.append(patch)
    
    return len(allpatches)

print(f"Number of patches is {count_patches(A)}")
Number of patches is 5

This should work for arrays with any number of dimensions.

  • Related