Question

I'm having trouble calculating a summed area table (https://en.wikipedia.org/wiki/Summed_area_table) in Python. The most obvious algorithm involves updating list elements in place while referencing already written elements...but something about the in-place update seems to be confusing Python.

Here's some sample code:

def compute_summed_area_table(image):
    # image is a 2-dimensional array containing ints or floats, with at least 1 element.
    height = len(image)
    width = len(image[0])
    new_image = [([0.0] * width)] * height # Create an empty summed area table
    for row in range(0, height):
        for col in range(0, width):
            if (row > 0) and (col > 0):
                new_image[row][col] = image[row][col] + \
                    new_image[row][col - 1] + new_image[row - 1][col] - \
                    new_image[row - 1][col - 1]
            elif row > 0:
                new_image[row][col] = image[row][col] + new_image[row - 1][col]
            elif col > 0:
                new_image[row][col] = image[row][col] + new_image[row][col - 1]
            else:
                new_image[row][col] = image[row][col]
    # Note that two-pass code gives the same kind of results, e.g.:
    #    for row in range(0, height):
    #        for col in range(0, width):
    #            if col > 0:
    #                new_image[row][col] = image[row][col] + new_image[row][col - 1]
    #            else:
    #                new_image[row][col] = image[row][col]
    #    for row in range(0, height):
    #        for col in range(0, height):
    #            if row > 0:
    #                new_image[row][col] += new_image[row - 1][col]
    return new_image


small_image = [[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]]
small_sat = compute_summed_area_table(small_image)
print(small_sat)

Based on my own manual calculation (subject to error), this test code should give something like: [[1, 3, 6, 10, 15], [7, 16, 27, 40, 55], [18, 39, 63, 90, 120], [34, 72, 114, 160, 210], [55, 115, 180, 250, 325]]

Instead, it gives: [[55, 61, 68, 76, 85], [55, 61, 68, 76, 85], [55, 61, 68, 76, 85], [55, 61, 68, 76, 85], [55, 61, 68, 76, 85]]

It's obviously updating every single row during each row iteration, but I'm not sure exactly why or how. Does anyone know precisely what's going wrong? Is there another way to do an in-place update? If not, how would you approach this?

Was it helpful?

Solution

It is because of

new_image = [([0.0] * width)] * height

You are not creating a two dimensional list of dimensions width and height, instead you are creating a list of height items, and all the elements in that list point to a list of size width (They all are pointing to the same list). To fix this problem

new_image = [[0.0] * width for _ in range(height)]

Consider this example,

a = [[0] * 3] * 2
a[0][0] = 1
print a

a = [[0] * 3 for _ in range(2)]
a[0][0] = 1
print a

Output

[[1, 0, 0], [1, 0, 0]]
[[1, 0, 0], [0, 0, 0]]

In the first case, a[0] and a[1] were pointing to the same list. So, changing the element at 0, changes element at 1 also.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top