Senyokbalgul
Senyokbalgul

Reputation: 1102

How to implement Matlab bwmorph(bw,'remove') in Python

I am trying to implement the Matlab function bwmorph(bw,'remove') in Python. This function removes interior pixels by setting a pixel to 0 if all of its 4-connected neighbor pixels are 1. The resulting image should return the boundary pixels. I've written a code but I'm not sure if this is how to do it.

# neighbors() function returns the values of the 4-connected neighbors
# bwmorph() function returns the input image with only the boundary pixels

def neighbors(input_matrix,input_array):
    indexRow = input_array[0]
    indexCol = input_array[1]
    output_array = []
    output_array[0] = input_matrix[indexRow - 1,indexCol]
    output_array[1] = input_matrix[indexRow,indexCol + 1]
    output_array[2] = input_matrix[indexRow + 1,indexCol]
    output_array[3] = input_matrix[indexRow,indexCol - 1]
    return output_array


def bwmorph(input_matrix):
    output_matrix = input_matrix.copy()
    nRows,nCols = input_matrix.shape
    for indexRow in range(0,nRows):
        for indexCol in range(0,nCols):
            center_pixel = [indexRow,indexCol]
            neighbor_array = neighbors(output_matrix,center_pixel)
            if neighbor_array == [1,1,1,1]:
                output_matrix[indexRow,indexCol] = 0
    return output_matrix

enter image description here

Upvotes: 1

Views: 668

Answers (1)

rayryeng
rayryeng

Reputation: 104525

Since you are using NumPy arrays, one suggestion I have is to change the if statement to use numpy.all to check if all values are nonzero for the neighbours. In addition, you should make sure that your input is a single channel image. Because grayscale images in colour share all of the same values in all channels, just extract the first channel. Your comments indicate a colour image so make sure you do this. You are also using the output matrix which is being modified in the loop when checking. You need to use an unmodified version. This is also why you're getting a blank output.

def bwmorph(input_matrix):
    output_matrix = input_matrix.copy()
    # Change. Ensure single channel
    if len(output_matrix.shape) == 3:
        output_matrix = output_matrix[:, :, 0]
    nRows,nCols = output_matrix.shape # Change
    orig = output_matrix.copy() # Need another one for checking 
    for indexRow in range(0,nRows): 
        for indexCol in range(0,nCols): 
            center_pixel = [indexRow,indexCol] 
            neighbor_array = neighbors(orig, center_pixel) # Change to use unmodified image
            if np.all(neighbor_array): # Change
                output_matrix[indexRow,indexCol] = 0 

    return output_matrix

In addition, a small grievance I have with your code is that you don't check for out-of-boundary conditions when determining the four neighbours. The test image you provided does not throw an error as you don't have any border pixels that are white. If you have a pixel along any of the borders, it isn't possible to check all four neighbours. However, one way to mitigate this would be to perhaps wrap around by using the modulo operator:

def neighbors(input_matrix,input_array):
    (rows, cols) = input_matrix.shape[:2] # New
    indexRow = input_array[0]
    indexCol = input_array[1]
    output_array = [0] * 4 # New - I like pre-allocating

    # Edit
    output_array[0] = input_matrix[(indexRow - 1) % rows,indexCol]
    output_array[1] = input_matrix[indexRow,(indexCol + 1) % cols]
    output_array[2] = input_matrix[(indexRow + 1) % rows,indexCol]
    output_array[3] = input_matrix[indexRow,(indexCol - 1) % cols]
    return output_array

Upvotes: 3

Related Questions