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.