2

I have the following 2D-numpy array:

matrix = np.zeros((250, 250))

Now, at various coordinates, I want to replace not just the coordinate value but its local vicinity too with a smaller array. As exemplary replacement we can take a diamond:

import skimage.morphology
star = skimage.morphology.diamond(3)  # small array / replacement

coords_r = np.random.randint(0, 250, 20)  # row coordinates
coords_c = np.random.randint(0, 250, 20)  # column coordinates

I came up with the following rather sloppy way and was wondering if there was a simpler / more elegant solution. Furthermore, this method will overwrite if two objects are close enough:

max_r, max_c = matrix.shape
obj = star
half_obj = int((star.shape[0])/2)

for r, c in zip(coords_r, coords_c):
    
    curr_obj = obj
    start_r = r-half_obj-1
    end_r = r+half_obj
    start_c = c-half_obj-1
    end_c = c+half_obj
    
    # Check if on corners
    if r-half_obj-1 < 0:
        start_r = 0
        curr_obj = curr_obj[-r:, :]
    if r+half_obj > matrix.shape[0]:
        end_r = max_r
        curr_obj = curr_obj[:max_r-start_r, :]
    if c-half_obj-1 < 0:
        start_c = 0
        curr_obj = curr_obj[:, -c:]
    if c+half_obj > matrix.shape[1]:
        end_c = max_c
        curr_obj = curr_obj[:, :max_c-start_c]
        
    matrix[start_r:end_r, start_c:end_c] = curr_obj

Thanks in advance.

4 Answers 4

1

You need to take better advantage of numpy slicing. As far as I understand the two random arrays coords_r, coords_c are the center coordinates around which you want to place your stars. I would

  1. convert these to list of rectangular crop coordinates
  2. loop over the coordinates and place the star in each slice

Something like

def center_to_bbox(coords, star_size):
    coords_x, coords_y = coords
    x1, y1, x2, y2 = coords_x - star_size, coords_y - star_size, coords_x + star_size + 1, 
    coords_y + star_size + 1,
    bboxes =(x1, y1, x2, y2)
    return bboxes
x_coords = np.random.randint(0, 250 - 3, 20)  
y_coords = np.random.randint(0, 250 - 3 , 20)
x1, y1, x2, y2 = bboxes
for x1_, y1_, x2_, y2_ in zip(x1, y1, x2, y2):
    matrix[y1_:y2_, x1_:x2_] = star

Note also that you might as well subtract the dimension of the star so you don't have to compensate for it at the boundaries later

Sign up to request clarification or add additional context in comments.

Comments

1

It seems that you might want to work with scipy sparse matrices. Just define small matrices and add them to the bigger matrix. lil_matrix seems to be the suitable format you're looking for.

Edit: @iantonuk I was thinking of the following which works well while adding/assembling matrices, but not while replacing entries.

from scipy.sparse import coo_matrix
data1 = ((1.0,2.0,3.0),([0,1,2],[0,1,2]))
mat1  = coo_matrix(data1,shape=(3,3))
print(mat1.todense())
data2 = ((2.0,3.0),([1,2],[1,2]))
mat2  = coo_matrix(data2,shape=(3,3))
print(mat2.todense())
mat3  = mat1 + mat2
print(mat3.todense())

1 Comment

a sample of doing that would be valuable
0

I asked similar question some time ago: Add small image to the canvas as numpy arrays

Here is my solution to your problem:

matrix_size = 250
star_size = 3

matrix = np.ones((matrix_size, matrix_size))
star = 1 - skimage.morphology.diamond(star_size)

coords_r = np.random.randint(0, matrix_size, 20)  # row coordinates
coords_c = np.random.randint(0, matrix_size, 20)  # column coordinates

for r, c in zip(coords_r, coords_c):
    matrix[max(r - star_size, 0):r + star_size + 1, max(c - star_size, 0):c + star_size + 1] *= star[max(star_size - r, 0):star_size + matrix_size - r, max(star_size - c, 0):star_size + matrix_size - c]
matrix = 1-matrix

And this is what I get: enter image description here

1 Comment

there isn't really a point to do multiplication or all of the form gymnastics to end up doing in un-vectorized way
0

Here's how easy you can do it in vectorized way:

def put_rounds(image:np.array, ptsx, ptsy):
    xm1, x, xp1 = (ptsx-1,ptsx,ptsx+1)
    ym1, y, yp1 = (ptsy-1,ptsy,ptsy+1)

    #make a round, r=3 or diamond pattern or whatever you need
    ptsx3 = np.dstack((xm1, xm1, ptsx,xm1,ptsx, xp1, ptsx,xm1, xp1)).flatten()
    ptsy3 = np.dstack((ym1, yp1, ym1,ptsy,ptsy, ptsy,yp1, yp1, yp1)).flatten()

    #this at least 7.5-12 times faster then loops(at least 50+ times faster on torch)
    image[ptsy3, ptsx3] = np.array([255,255,0])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.