While the answer by @AJNeufeld correctly explains the shortcomings regarding normal Python in your code, there is indeed a faster way using numpy.
First, you can build a mask of all pixels that have the value 1:
mask = (img == [1, 1, 1]).all(axis=-1)
This mask is already the same as the output of your generateArray.
Executing your function takes about 720 ms ± 17.9 ms on my machine with some image file I had lying around (PNG, 471 x 698 pixels), whereas the generation of this mask is a hundred times faster at 7.37 ms ± 96.6 µs.
Now we construct two images, one completely black and one completely white:
black = np.zeros_like(img)
white = np.ones_like(img)
And then you can use numpy.where to conditionally on the mask use those two images:
img_bw = np.where(mask[:,:,None], white, black)
The weird looking slicing with None just makes sure that the mask has the right dimensionality (i.e. three values per pixel, instead of just one).
Putting it all together:
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
def to_bw(img):
"""Return a black and white copy of `img`.
Pixels which are white in the original image stay white,
all other pixels are turned black.
"""
mask = (img == [1, 1, 1]).all(axis=-1)
black = np.zeros_like(img)
white = np.ones_like(img)
return np.where(mask[:,:,None], white, black)
if __name__ == "__main__":
img = mpimg.imread('./Training/Image1.png')
img_bw = to_bw(img)
plt.imshow(img_bw)
plt.show()
The whole to_bw function only takes 14 ms ± 324 µs.