TheHeadlessSourceMan
TheHeadlessSourceMan

Reputation: 747

Numpy where not giving expected shape

The problem is fairly simple. Given a 256x256 grayscale image, I want to return a color image with colors based on a threshold.

So I'm thinking:

img=whatever # 2D array of floats representing grayscale image
threshold=0.5
color1=[1.0,0.0,0.0]
color2=[0.0,0.0,1.0]
newImg=np.where(img>threshold,color1,color2)

Yet I get the infamous: "ValueError: operands could not be broadcast together with shapes (500,500) (3,) (3,)"

Huh? I was really expecting that to give an array shaped (500,500,3). Why didn't it combine them??

Upvotes: 4

Views: 5146

Answers (2)

Kaden Penner
Kaden Penner

Reputation: 54

EDIT: I realize that I originally misinterpreted the original array dimensions as user2357112 pointed out.

To add an additional solution to your original problem that does not require numpy, use:

newImg = [[color1 if (cell > threshold) else color2 for cell in row] for row in img]

Upvotes: 1

user2357112
user2357112

Reputation: 281538

You're misunderstanding how numpy.where works. It looks like you might be thinking that for True cells of img>threshold, where picks the entirety of color1 as a value, and for False cells, it picks the entirety of color2. Whatever it was you were thinking, that's not how it works.

numpy.where broadcasts the arguments together, and then for each cell of the first argument, picks the corresponding cell of either the second or third argument. To produce a shape-(500, 500, 3) result, the arguments would have to broadcast together to a shape of (500, 500, 3). Your inputs aren't broadcasting-compatible with each other at all.

One way to make the broadcasting work would be to add an extra length-1 dimension to the end of img>threshold:

newImg=np.where((img>threshold)[..., None],color1,color2)

If you're new to broadcasting, it may help to use numpy.broadcast_arrays to see what the result of broadcasting multiple arrays together looks like.

Upvotes: 8

Related Questions