1

I'm trying to enumerate through a 2D numpy array of shape (512, 512), which holds the pixel values of an image. So basically it's an array representing width and height in pixel values for the image. I'm trying to enumerate through each element to output: [y_index, x_index, pixel_value]. I need these 3 output values to be stored in an array (either the existing one or a new one, whichever is more efficient to execute). So the input array would have a shape of (512, 512), and if I'm not mistaken, the output array would have an array shape (262144, 3). 262144 is the total number of pixels in a 512x512 matrix. And 3 because there are 3 columns, for 3 pieces of data that I need to extract: pixel value, y coordinate, x coordinate. So basically I want to have an array of pixel values and their y, x coordinates.

In the code below, I used ndenumerate to enumerate through the numpy array (img) of pixel values (512, 512). But I'm struggling on how to store the output values in an array. I created coordinates array to store the output values, but my attempt at it with the last line is clearly incorrect to achieve the desired effect. So how to solve this?

img = as_np_array[:, :, 0]
img = img.reshape(512, 512)
coordinates = np.empty([262,144, 3])
for index, x in np.ndenumerate(img):
    coordinates = np.append(coordinates, [[x], index[0], index[1]])

Also the other challenge I'm facing is, to execute this code, my Intel Core i7 2.7GHz (4 Cores) processor takes about 7-10 minutes (possibly more at times) to execute. Is there a more efficient code that can execute faster?

Any help would be greatly appreciated.

Hazzaldo
  • 515
  • 1
  • 8
  • 24
  • Can't you use three variables for pixel value, x coordinate and y coordinate. In that case, you can use the existing array, and `ycoord, xcoord = numpy.mgrid[0:img.shape[0],0:img.shape[1]]`. – 9769953 Sep 05 '19 at 05:29
  • Thank you for your response. Sorry, but I didn't understand your particular format of answer. Basically I need an array output with 3 columns: `pixel value`, and its `x` & `y` coordinates. Reason I need that format specifically is because I need to then save it as a CSV file to have that specific data format/structure. You have `ycoord`, `xcoord` but I need everything in one array output. – Hazzaldo Sep 05 '19 at 12:57
  • Not necessarily: you could also create a double loop over the x- and y-coordinates, and then output a line of x, y, pixel_value to the CSV file. In which case, you neither need that large a 2D array, nor my solution, but just something like `for x in range(512): for y in range(512): csv.write(x, y, img[y,x])`. – 9769953 Sep 05 '19 at 13:01
  • Many thanks for this suggestion. I'm just trying out this code right now. I tried this code as a test run with a small array example: `array2 = np.array([[1,1,1], [2,2,2], [3,3,3]]) with open('csv_test.csv', 'w', newline='') as f: thewriter = csv.writer(f) thewriter.writerow(['x_coord', 'y_coord', 'pixel_value']) for y in np.nditer(array2): for x in np.nditer(y): thewriter.writerow([x, y, array2[y,x]])`, but I got the error: `index 3 is out of bounds for axis 0 with size 3`. Not sure why is that? Is `np.nditer` the issue or is it something else? – Hazzaldo Sep 05 '19 at 13:59
  • 1
    Because `np.nditer` steps through the flattened array, which is larger than one dimension. Also, your code doesn't not reflect what I wrote. I step through the dimensions (shape) of the array; you step through the array itself, and use the values *inside* the to index the array: `for y in np.nditer(array2): ... array2[y,x]`. That's not going to work (except in some very special cases). – 9769953 Sep 05 '19 at 14:07
  • That makes sense with regards to `np.nditer`. I realise now, after looking at examples of `np.nditer`, how it exactly works. I didn't quite understand its documentation alone very well. With regards to the solution, I used `for index, pix in np.ndenumerate(img):`, and simply extracted the data to be written to a CSV file now and it works like a treat. I've got exactly what I want now. Thank you very much for your help. – Hazzaldo Sep 05 '19 at 16:26
  • You can self answer your question with your solution, so that at least, it shows this problem has found a solution. (If you answer it, you can also remove your edit to your question about the duplicate, since it has been unlocked again.) – 9769953 Sep 06 '19 at 07:22

2 Answers2

1

You could use numpy.indices to do this. What you want ultimately is image_data with y, x indices and the corresponding pixels (px). There are three columns in image_data.

row, col = np.indices(img.shape)
y, x, px = row.flatten(), col.flatten(), img.flatten()
image_data = np.array([y, x, px]).T

Detailed Example:

img = np.arange(20).reshape(5, 4)

def process_image_data(img):
    row, col = np.indices(img.shape)
    return (row.flatten(), col.flatten(), img.flatten())

y, x, px = process_image_data(img)
CypherX
  • 7,019
  • 3
  • 25
  • 37
0

The solution that worked for me is this:

with open('img_pixel_coor1.csv', 'w', newline='') as f:
    headernames = ['y_coord', 'x_coord', 'pixel_value']
    thewriter = csv.DictWriter(f, fieldnames=headernames)
    thewriter.writeheader()     
    for index, pix in np.ndenumerate(img):
        thewriter.writerow({'y_coord' : index[0], 'x_coord' : index[1], 'pixel_value' : pix})
Hazzaldo
  • 515
  • 1
  • 8
  • 24