Carl Shiles
Carl Shiles

Reputation: 13

Broadcasting into views of Numpy arrays

I am working with images through numpy. I want to set a chunk of the image to its average color. I am able to do this, but I have to re-index the array, when I would like to use the original view to do this. In other words, I would like to use that 4th line of code, but I'm stuck with the 3rd one.

I have read a few posts about the as_strided function, but it is confusing to me, and I was hoping there might be a simpler solution. So is there a way to slightly modify that last line of code to do what I want?

box = im[x-dx:x+dx, y-dy:y+dy, :]
avg = block(box) #returns a 1D numpy array with 3 values
im[x-dx:x+dx, y-dy:y+dy, :] = avg[None,None,:] #sets box to average color
#box = avg[None,None,:] #does not affect original array

Upvotes: 1

Views: 60

Answers (2)

John1024
John1024

Reputation: 113934

Gray-scale Images

This will set a chunk of an array to its average (mean) value:

im[2:4, 2:4] = im[2:4, 2:4].mean()

For example:

In [9]: im
Out[9]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])

In [10]: im[2:4, 2:4] = im[2:4, 2:4].mean()

In [11]: im
Out[11]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 12, 12],
       [12, 13, 12, 12]])

Color Images

Suppose that we want to average over each component of color separately:

In [22]: im = np.arange(48).reshape((4,4,3))

In [23]: im
Out[23]: 
array([[[ 0,  1,  2],
        [ 3,  4,  5],
        [ 6,  7,  8],
        [ 9, 10, 11]],

       [[12, 13, 14],
        [15, 16, 17],
        [18, 19, 20],
        [21, 22, 23]],

       [[24, 25, 26],
        [27, 28, 29],
        [30, 31, 32],
        [33, 34, 35]],

       [[36, 37, 38],
        [39, 40, 41],
        [42, 43, 44],
        [45, 46, 47]]])

In [24]: im[2:4, 2:4, :] = im[2:4, 2:4, :].mean(axis=0).mean(axis=0)[np.newaxis, np.newaxis, :]

In [25]: im
Out[25]: 
array([[[ 0,  1,  2],
        [ 3,  4,  5],
        [ 6,  7,  8],
        [ 9, 10, 11]],

       [[12, 13, 14],
        [15, 16, 17],
        [18, 19, 20],
        [21, 22, 23]],

       [[24, 25, 26],
        [27, 28, 29],
        [37, 38, 39],
        [37, 38, 39]],

       [[36, 37, 38],
        [39, 40, 41],
        [37, 38, 39],
        [37, 38, 39]]])

Upvotes: 1

user2357112
user2357112

Reputation: 281683

box = blah

just reassigns the box variable. The array that the box variable previously referred to is unaffected. This is not what you want.

box[:] = blah

is a slice assignment. It modifies the contents of the array. This is what you want.

Note that slice assignment is dependent on the syntactic form of the statement. The fact that box was assigned by box = im[stuff] does not make further assignments to box slice assignments. This is similar to how if you do

l = [1, 2, 3]
b = l[2]
b = 0

the assignment to b doesn't affect l.

Upvotes: 1

Related Questions