Reputation: 1632
I am trying to iterate over the pixels in an image, but rather vertically instead of the normal horizontal way. Here is an example of a small-sized image I might have (I have images where the size is in the hundreds):
"""
Note: X represents pixels
Sample Image (3 x 4):
X X X X
X X X X
X X X X
"""
Clearly, to iterate over this image horizontally, it is easy to do so, as I have done here:
import itertools
width = range(3)
height = range(4)
print("Pixel positions:")
for pixel in itertools.product(width, height):
print(*pixel)
Output:
Pixel positions:
0 0
0 1
0 2
0 3
1 0
1 1
1 2
1 3
2 0
2 1
2 2
2 3
These are the index positions of the pixels in the image (assume it as a large 2D list of pixels) but iterated horizontally. I want to be able to do the same but vertically. Is there an itertools function that allows me to do the same but column-wise? Here are the indexes for this sample image:
Column-wise:
0 0
1 0
2 0
0 1
1 1
2 1
0 2
1 2
2 2
0 3
1 3
2 3
I have attempted to reverse the positions with print(*pixel[::-1])
, however, this results in certain index positions that are out of range such as the last one from 2 3
to 3 2
. 3 2
is not valid as there aren't 3 rows (0, 1, 2 only). The same goes for other positions as well.
I would like a solution without the use of non-built-in libraries. Itertools is fine as I am using it for something else in my program.
Upvotes: 0
Views: 339
Reputation: 1662
Try this code:
width = range(3)
height = range(4)
print("Pixel positions:")
for x in height:
for y in width:
print(y, x)
Output:
Pixel positions:
0 0
1 0
2 0
0 1
1 1
2 1
0 2
1 2
2 2
0 3
1 3
2 3
To iterate horizontally just swap the two for-loops:
width = range(3)
height = range(4)
print("Pixel positions:")
for y in width:
for x in height:
print(y, x)
Performance comparison:
$ python -m timeit -n 100 '
width = range(1000)
height = range(1000)
for pixel in ((x, y) for y in height for x in width):
pass
'
100 loops, best of 3: 104 msec per loop
Nested for-loop is about 8x faster:
$ python -m timeit -n 100 '
width = range(1000)
height = range(1000)
for y in width:
for x in height:
pass
'
100 loops, best of 3: 12.7 msec per loop
When also creating a tuple containing the result coordinates, the code is still 2x faster. But it is questionable if creating a tuple containing the coordinates is required for the task at hand.
$ python -m timeit -n 100 '
width = range(1000)
height = range(1000)
for y in width:
for x in height:
(x, y)
'
100 loops, best of 3: 52.5 msec per loop
Upvotes: 2
Reputation: 98378
According to the documentation, itertools.product(width, height)
is equal to:
((x, y) for x in width for y in height)
If you want to iterate column-wise, just swap the inner loops:
for pixel in ((x, y) for y in height for x in width):
print(*pixel)
0 0
1 0
2 0
0 1
1 1
2 1
0 2
1 2
2 2
0 3
1 3
2 3
Upvotes: 1