1

Given an array of [x,y] as follows, I'd like to return a new array with the average of the 3x3 sub-arrays. E.g. the following array:

image = [[7, 4, 0, 1], 
         [5, 6, 2, 2], 
         [6, 10, 7, 8], 
         [1, 4, 2, 0]]

Should return

new_image = [[5, 4],
            [4, 4]]

I've managed to get this far at which point I can get the new array as a list of the form:

new_image = [5,4,4,4]

This is my approach:

h = list(range(1,len(image)-1))
w = list(range(1,len(image[0])-1))

def square_sum(image,i,j):
    sum = image[i-1][j-1] + image[i-1][j] + image[i][j-1] + image[i+1][j] + image[i][j+1] + image[i+1][j+1] + image[i][j] + image[i-1][j+1] + image[i+1][j-1] 
    return sum//9

new_image = []

for i in h:
    for j in w:
        new_image.append(square_sum(image,i,j))
return(new_image)

So my question is how can I get my output to be an array of arrays instead of just a list. (I've realised it's a lot easier to do this with Numpy but would like to see how I could go about solving it in line with the above).

Itamar Mushkin
  • 2,803
  • 2
  • 16
  • 32
Rock1432
  • 167
  • 1
  • 11
  • I don't understand how any of these values average to 5 or 4 – Nicolas Gervais Jun 14 '20 at 13:58
  • @NicolasGervais I've edited the question to explain - it's the 3x3 averages. – Itamar Mushkin Jun 14 '20 at 13:59
  • Hi, as in the average of the 3x3 sub arrays surrounding each element in the original array. E.g. take [1,1] = 6 in the original array. The sum of the 3x3 sub array with 6 as the centre is 47. Therefore, average is 5. – Rock1432 Jun 14 '20 at 14:01
  • This might be relevant - https://stackoverflow.com/questions/43086557/convolve2d-just-by-using-numpy (using 3x3 convolving filter where every value is 1/9). – alani Jun 14 '20 at 14:04

4 Answers4

1

You must manually create both the outer and inner lists:

new_image = []

for i in h:
    new_image.append([])  # at each height, add a new inner list
    for j in w:
        new_image[-1].append(square_sum(image,i,j))
        #         ^ append to the last create inner list

Patterns of the form for ... in ...: some_list.append(...) usually are suitable to being written as a list comprehension. Both layers can be expressed at once by a nested comprehension:

 #           v outer layer                                 v
 new_image = [[square_sum(image,i,j) for j in w] for i in h]
 #            ^ inner layer                    ^
MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119
1

You can replace the final loop with a list comprehension:

new_image = [[square_sum(image,i,j) for j in w] for i in h]

In your example, it returns:

[[5, 4], [4, 4]]
Itamar Mushkin
  • 2,803
  • 2
  • 16
  • 32
1

Since we know number of elements in each row we can keep appending row wise rather than element wise to new_image. Code below:

image = [[7, 4, 0, 1], 
         [5, 6, 2, 2], 
         [6, 10, 7, 8], 
         [1, 4, 2, 0]]

h = list(range(1,len(image)-1))
w = list(range(1,len(image[0])-1))

def square_sum(image,i,j):
    sum = image[i-1][j-1] + image[i-1][j] + image[i][j-1] + image[i+1][j] + image[i][j+1] + image[i+1][j+1] + image[i][j] + image[i-1][j+1] + image[i+1][j-1] 
    return sum//9

new_image = []

for i in h:
    temp_row = []
    for j in w:
        temp_row.append(square_sum(image,i,j))
    new_image.append(temp_row)
Equinox
  • 6,483
  • 3
  • 23
  • 32
1

If you are willing to use scipy, you can do a convolution with a 1/9 kernel:

from scipy.signal import convolve2d


image = [[7, 4, 0, 1], 
         [5, 6, 2, 2], 
         [6, 10, 7, 8], 
         [1, 4, 2, 0]]


kernel = np.ones([3,3]) / 9

convolve2d(image, kernel, mode='valid').astype(int)
warped
  • 8,947
  • 3
  • 22
  • 49