Home > front end >  I need to separate an array into sub arrays where each sub array represents a distinct line on an im
I need to separate an array into sub arrays where each sub array represents a distinct line on an im

Time:07-13

My goal with this project is to start with one large 2d array and separate it into multiple arrays. Here is the original array:

arr = np.array([[0,0,0,0,0,0,0,0,0],
                [0,0,0,0,1,0,0,0,0],
                [0,1,0,0,1,0,0,0,0],
                [0,0,0,0,1,0,0,0,0],
                [0,0,0,0,1,0,0,1,0],
                [0,0,0,0,1,0,0,1,0],
                [0,1,0,0,1,0,0,1,0],
                [0,0,0,0,1,0,0,1,0],
                [0,0,0,0,1,0,0,1,0],
                [0,0,0,0,0,0,0,0,0],
                [0,0,0,0,0,0,0,0,0],
                [0,0,0,0,0,0,0,0,0],
                [0,0,0,0,0,0,0,0,0]])

This array represents two vertical lines (one line with len = 8 and the other with len = 5). The other two 1's are considered error. Firstly, I get rid of the error using this bit of code. It's job is to check neighboring pixels/cells and if all neighboring cells are zero then it is changed to zero.

noise = []
for i, e in enumerate(data):
    if arr[e[1],e[0] 1] == 0 and arr[e[1],e[0]-1] == 0 and arr[e[1]-1,e[0]] == 0 and arr[e[1] 1,e[0]] == 0 \
    and arr[e[1] 1,e[0] 1] == 0 and arr[e[1] 1,e[0]-1] == 0 and arr[e[1]-1,e[0] 1] == 0 and arr[e[1]-1,e[0]-1] == 0:
        noise.append(i)
data = np.delete(data, noise, axis = 0) 

Next, I want to separate the array into two sub arrays where sub array 1 is the x,y coordinates (column, row) of the first line and sub array 2 is the x,y coordinates of the second line. To do this, I first made a loop which records the positions of the end points of the two lines. I did this using a similar loop to the one I used to find and delete the single pixels/ noise.

Finally, once I have my array of end point coordinates, I made a loop which starts at one endpoint, checks in what direction the next pixel is, appends the coordinates, then repeats. Below you can find the loop I used to do this.

allfibers = []
end_points = np.array(end_points)
for i, e in enumerate(end_points):
    fiber = []
    row = data[end_points[i]][1]
    column = data[end_points[i]][0]
    fiber.append([row,column])
    _ = 0
    z = f'start -> row, column = {row}, {column}'
    while True:
        print(z)
        if arr[row][column 1] == 1 and z !='left': #right of pix
            fiber.append([row,column 1])
            column  = 1 
            z = 'right'
        elif arr[row][column-1] == 1 and z !='right': #left of pix
            fiber.append([row,column-1]) 
            column -= 1
            z = 'left'
        elif arr[row 1][column] == 1 and z !='down': #above pix
            fiber.append([row 1,column])
            row  = 1 
            z = 'up'
        elif arr[row-1][column] == 1 and z !='up': #below pix
            fiber.append([row-1,column])
            row -= 1
            z = 'down'
        if (np.any(endpoint_coord) == np.all([row,column]) or np.any(endpoint_coord) == 
        np.all([row,column-1]) \
        or np.any(endpoint_coord) == np.all([row-1,column])) and _ > 1:
            break
        _  = 1
    allfibers.append(np.array(fiber))
data_type = np.dtype(np.int64)
allfibers = np.array(allfibers, dtype=data_type)

print(allfibers)
`

In this code directly above lies the problem. The program returns this:

[[[1 4]
  [2 4]
  [3 4]
  [4 4]]

 [[4 7]
  [5 7]
  [6 7]
  [7 7]]

 [[8 4]
  [7 4]
  [6 4]
  [5 4]]

 [[8 7]
  [7 7]
  [6 7]
  [5 7]]]

This problem is not there there are 4 sub arrays and only 2 lines in the original array. Because each fiber has two endpoints this is expected and can easily be handled later on. The problem is that the lengths don't match. I do not know why this is the case. If anyone has any ideas about how to fix this please let me know. Also I am relatively new to this so forgive me if the explanation isn't the best and please let me know if there is anything I should clarify.

CodePudding user response:

If you don't mind using pre-built function, you could use the scipy library:

import numpy as np
from scipy.signal import convolve2d
from scipy.ndimage import label 

## Example matrix
arr = [...]

## Check if neighboring cells are zero using a 2d convolution:
# The kernel
ker = np.array([[0,1,0],
                [1,0,1],
                [0,1,0]])

res = convolve2d(arr,ker,mode='same')

# Eliminate the noise
res = np.int32((res>0)&(arr>0))

# Using label your can segment an image and since an image is basically a matrix:
lab = label(res,ker)

# Get the coordinate of each line.
coord = []
for ii in range(lab[1]):
    coord.append(np.vstack(np.where(lab[0]==(ii 1))))

And the output is a list of numpy array, one array per line:

[array([[1, 2, 3, 4, 5, 6, 7, 8],
        [4, 4, 4, 4, 4, 4, 4, 4]], dtype=int64),
 array([[4, 5, 6, 7, 8],
        [7, 7, 7, 7, 7]], dtype=int64)]

Here I use two function:

convolve2d: compute the 2d convolution between arr and ker. The option mode='same' return a matrix with the same shape as the original matrix.

label: Segment a matrix, the neighboring cells that have to be considered are define by the kernel ker.

If you also want to consider diagonal line, then your could simply change the kernel.

  • Related