Search code examples
numpymathnumpy-ndarray

Randomly selecting indices in a 2D numpy array, understanding ChatGPT solution


I asked ChatGPT to help me to randomly select pixels in an image loaded as numpy array. The solution it gave me is actually working good, but I'm struggling to understand how it works:

from PIL import Image
import numpy as np

img = Image.open('image.png')
pix = np.array(img)
random_pixels = np.random.choice(pix.shape[0]*pix.shape[1], pix.shape[0]*pix.shape[1], replace=False)
selected_pixels = []
for p in random_pixels:
    x = p // pix.shape[1]
    y = p % pix.shape[1]
    selected_pixels.append((x, y))

I do not understand how the integer division and the modulo operators applied on the image width are actually able to return all the coordinates.


Solution

  • Start with a small array that you can actually examine

    In [403]: pix=np.arange(12).reshape(3,4)
    In [404]: pix
    Out[404]: 
    array([[ 0,  1,  2,  3],
           [ 4,  5,  6,  7],
           [ 8,  9, 10, 11]])
    
    In [405]: random_pixels = np.random.choice(pix.shape[0]*pix.shape[1], pix.shape[0]*pix.shape[1], replace=False)
         ...: print(random_pixels)
         ...: selected_pixels = []
         ...: for p in random_pixels:
         ...:     x = p // pix.shape[1]
         ...:     y = p % pix.shape[1]
         ...:     print(p,x,y)
         ...:     selected_pixels.append((x, y))
         ...:     
    

    The array is (3,4) shape, and that choices has created at random shuffle of values 0 to 11.

    [ 5  6  9  4  2  8 11 10  0  7  1  3]
    

    The iteration takes value, p, and produces a x,y coordinate from that.

    5 1 1
    6 1 2
    9 2 1
    4 1 0
    2 0 2
    8 2 0
    11 2 3
    10 2 2
    0 0 0
    7 1 3
    1 0 1
    3 0 3
    

    Actually I didn't need to print the x,y, since those are already collected in

    In [406]: selected_pixels
    Out[406]: 
    [(1, 1),
     (1, 2),
     (2, 1),
     (1, 0),
     (0, 2),
     (2, 0),
     (2, 3),
     (2, 2),
     (0, 0),
     (1, 3),
     (0, 1),
     (0, 3)]
    

    You should be able to work out how the integer division and modulus convert the p to x and y. You don't need to run that in loop to do that. Pick any p and any shape.