0

I am comparing two slices of the same array. The two slices are the same, except they are offset in the [1] axis. I compare these two slices and return their minimum repeatedly in a while loop.

My expectation: The size of the arrays stay the same relative to each other, shrinking by the value of "offset"

What happens instead: One of the arrays shrinks in size relative to the other in the second iteration, shrinking by more than the value of "offset"

As I am using the same offset value to compare them, and as (x-y) - 0 = x - (0 + y), these values must be the same. For the first iteration, they are the same, but for the second iteration, they are not, as you can see from the printed output.

I thought that the problem might be related to pass-by-value issues, so I tried using copy.deepcopy, but this is not correcting the problem either. I also thought there might be a quirk in indexing overflow indices, so I set height and width to one less, just in case, but that produced no effect either. I am wondering if i might have a fundamental misunderstanding of how slicing or advanced indexing works.

Here is the printed output:

Slice 1: offset value: 1    height, width: 999 1332
Slice 2: offset value: 1    height, width: 999 1332
Slice 1: offset value: 2    height, width: 999 1331
Slice 2: offset value: 2    height, width: 999 1330

Here is the error I get, It triggers on the second iteration of the while loop:

    image = np.minimum(slice1, slice2)

ValueError: operands could not be broadcast together with shapes (999,1331) (999,1330)

Here is my code:

def horizontal_smear(image, distance):

    height = len(image) - 1
    width  = len(image[0] - 1)
    offset = 1

    while offset < distance /2:

        slice1 = copy.deepcopy(image[0 : height, 0 : (width - offset)])
        print ("Slice 1: offset value:", offset, "   height, width:", len(slice1), len(slice1[0]))        
        slice2 = copy.deepcopy(image[0 : height, offset : width])
        print ("Slice 2: offset value:", offset, "   height, width:", len(slice2), len(slice2[0]))        

        image = np.minimum(slice1, slice2)
        offset *= 2

    return image
owlnut
  • 1
  • 1

2 Answers2

0

This resolves the coding error preventing the function from working properly. It does not explain the underlying mechanism of the error:

in the while loop, image shrinks, so that each subsequent copy of slice1 and slice2 has less source data to draw from, but "height" and "width" remain fixed. As slice 2 is further to the right than slice 1, this pushes it out of indexing range. (This likely has something to do with why its indices shrink, but I do not know how numpy handles out-of-range data.)

Changing the line image = np.minimum(slice1, slice2) to

image[0:height, 0:(width - offset)] = np.minimum(slice1, slice2) fixes the problem.

owlnut
  • 1
  • 1
0

Your second slice runs off the end of the shrunken image array. The problem is that your code is rebinding image to successively smaller arrays, but your width variable remains the same (one less than the original size). You probably need to be updating width inside the loop.

# move the width line from here
offset = 1

while offset < distance /2:
    width = len(image[0] - 1)   # to here

    ...

Some more detail on why your code wound up with the exact error it did: When you slice off the end of a container in Python (including Numpy arrays, which don't always behave the same as other types), you get a smaller result than you might have been expecting, and no error. Here's an example with lists:

a = [1, 2, 3]
b = a[0:2] # len(b) is 2
c = a[2:4] # len(c) is unexpectedly 1!

The slice to make c results in a one-element list because there are no more elements after index 2, even though the slice notation might have lead you to expect the result to have two elements (from indexes 2-3).

Blckknght
  • 100,903
  • 11
  • 120
  • 169