Reputation: 11
I have an image that I'd like to break up into 30px by 30px blocks. Then, I'd like to average each of the r,g, and b values of the pixels. So for example, a 900px by 900px would breaken up into 900 blocks (each 30px by 30px). Then I'd like to take the average of the r,g, and b values in each block. In the end, I'd like an array of 900 three-dimensional vectors, each representing the average r,g,b value of their respective block.
I've tried using numpy and pillow to break up the blocks, but I don't seem to be splicing my pixel array correctly.
import numpy as np
from PIL import Image
item_image = Image.open("1.jpg")
pixel_array = np.asarray(item_image)
width, height = item_image.size
blocks = []
BLOCK_WIDTH = 30
BLOCK_HEIGHT = 30
row_start = 0
row_end = BLOCK_HEIGHT
column_start = 0
column_end = BLOCK_WIDTH
print(len(pixel_array))
while row_end < height:
while column_end < width:
row = slice(row_start, row_end)
col = slice(column_start, column_end)
blocks.append(pixel_array[ row , col ])
column_start += BLOCK_WIDTH
column_end += BLOCK_WIDTH
row_start += BLOCK_HEIGHT
row_end += BLOCK_HEIGHT
averaged_blocks = []
for i in range(BLOCK_HEIGHT):
for j in range(BLOCK_WIDTH):
averaged_blocks.append(np.mean(blocks[i][j], axis = 0))
I'm pretty new at working with images, so if anyone has any recommendations or suggestions I'd greatly appreciate it!
Upvotes: 1
Views: 316
Reputation: 53164
This is pretty trivial in Imagemagick. All you need to do is scale the image down to 30x30 pixels. Scale averages the blocks of 30x30 non-overlapping pixels. (Or use -filter box -resize in place of -scale). Then just list the resulting image's pixel values using txt: output format.
Create 900x900 pixel horizontal gradient:
convert -size 900x900 gradient: -rotate 90 grad.png
Scale the image and list each pixel:
convert grad.png -scale 30x30 txt:
# ImageMagick pixel enumeration: 30,30,65535,gray
coords: (16-bit rgb values) hex values percent
0,0: (1057,0,64478) #04210000FBDE srgb(2%,0%,98%)
1,0: (3244,0,62291) #0CAC0000F353 srgb(5%,0%,95%)
2,0: (5431,0,60104) #15370000EAC8 srgb(8%,0%,92%)
3,0: (7618,0,57917) #1DC20000E23D srgb(12%,0%,88%)
4,0: (9805,0,55730) #264D0000D9B2 srgb(15%,0%,85%)
5,0: (11992,0,53543) #2ED80000D127 srgb(18%,0%,82%)
6,0: (14179,0,51356) #37630000C89C srgb(22%,0%,78%)
7,0: (16366,0,49169) #3FEE0000C011 srgb(25%,0%,75%)
8,0: (18552,0,46983) #48780000B787 srgb(28%,0%,72%)
9,0: (20739,0,44796) #51030000AEFC srgb(32%,0%,68%)
10,0: (22926,0,42609) #598E0000A671 srgb(35%,0%,65%)
11,0: (25113,0,40422) #621900009DE6 srgb(38%,0%,62%)
12,0: (27300,0,38235) #6AA40000955B srgb(42%,0%,58%)
13,0: (29487,0,36048) #732F00008CD0 srgb(45%,0%,55%)
14,0: (31674,0,33861) #7BBA00008445 srgb(48%,0%,52%)
15,0: (33861,0,31674) #844500007BBA srgb(52%,0%,48%)
16,0: (36048,0,29487) #8CD00000732F srgb(55%,0%,45%)
17,0: (38235,0,27300) #955B00006AA4 srgb(58%,0%,42%)
18,0: (40422,0,25113) #9DE600006219 srgb(62%,0%,38%)
19,0: (42609,0,22926) #A6710000598E srgb(65%,0%,35%)
20,0: (44796,0,20739) #AEFC00005103 srgb(68%,0%,32%)
21,0: (46983,0,18552) #B78700004878 srgb(72%,0%,28%)
22,0: (49169,0,16366) #C01100003FEE srgb(75%,0%,25%)
23,0: (51356,0,14179) #C89C00003763 srgb(78%,0%,22%)
24,0: (53543,0,11992) #D12700002ED8 srgb(82%,0%,18%)
25,0: (55730,0,9805) #D9B20000264D srgb(85%,0%,15%)
26,0: (57917,0,7618) #E23D00001DC2 srgb(88%,0%,12%)
27,0: (60104,0,5431) #EAC800001537 srgb(92%,0%,8%)
28,0: (62291,0,3244) #F35300000CAC srgb(95%,0%,5%)
29,0: (64478,0,1057) #FBDE00000421 srgb(98%,0%,2%)
0,1: (1057,0,64478) #04210000FBDE srgb(2%,0%,98%)
1,1: (3244,0,62291) #0CAC0000F353 srgb(5%,0%,95%)
2,1: (5431,0,60104) #15370000EAC8 srgb(8%,0%,92%)
3,1: (7618,0,57917) #1DC20000E23D srgb(12%,0%,88%)
4,1: (9805,0,55730) #264D0000D9B2 srgb(15%,0%,85%)
5,1: (11992,0,53543) #2ED80000D127 srgb(18%,0%,82%)
6,1: (14179,0,51356) #37630000C89C srgb(22%,0%,78%)
7,1: (16366,0,49169) #3FEE0000C011 srgb(25%,0%,75%)
8,1: (18552,0,46983) #48780000B787 srgb(28%,0%,72%)
9,1: (20739,0,44796) #51030000AEFC srgb(32%,0%,68%)
10,1: (22926,0,42609) #598E0000A671 srgb(35%,0%,65%)
11,1: (25113,0,40422) #621900009DE6 srgb(38%,0%,62%)
12,1: (27300,0,38235) #6AA40000955B srgb(42%,0%,58%)
13,1: (29487,0,36048) #732F00008CD0 srgb(45%,0%,55%)
14,1: (31674,0,33861) #7BBA00008445 srgb(48%,0%,52%)
15,1: (33861,0,31674) #844500007BBA srgb(52%,0%,48%)
16,1: (36048,0,29487) #8CD00000732F srgb(55%,0%,45%)
17,1: (38235,0,27300) #955B00006AA4 srgb(58%,0%,42%)
18,1: (40422,0,25113) #9DE600006219 srgb(62%,0%,38%)
19,1: (42609,0,22926) #A6710000598E srgb(65%,0%,35%)
20,1: (44796,0,20739) #AEFC00005103 srgb(68%,0%,32%)
21,1: (46983,0,18552) #B78700004878 srgb(72%,0%,28%)
22,1: (49169,0,16366) #C01100003FEE srgb(75%,0%,25%)
23,1: (51356,0,14179) #C89C00003763 srgb(78%,0%,22%)
24,1: (53543,0,11992) #D12700002ED8 srgb(82%,0%,18%)
25,1: (55730,0,9805) #D9B20000264D srgb(85%,0%,15%)
26,1: (57917,0,7618) #E23D00001DC2 srgb(88%,0%,12%)
27,1: (60104,0,5431) #EAC800001537 srgb(92%,0%,8%)
28,1: (62291,0,3244) #F35300000CAC srgb(95%,0%,5%)
29,1: (64478,0,1057) #FBDE00000421 srgb(98%,0%,2%)
.
.
.
0,28: (1057,0,64478) #04210000FBDE srgb(2%,0%,98%)
1,28: (3244,0,62291) #0CAC0000F353 srgb(5%,0%,95%)
2,28: (5431,0,60104) #15370000EAC8 srgb(8%,0%,92%)
3,28: (7618,0,57917) #1DC20000E23D srgb(12%,0%,88%)
4,28: (9805,0,55730) #264D0000D9B2 srgb(15%,0%,85%)
5,28: (11992,0,53543) #2ED80000D127 srgb(18%,0%,82%)
6,28: (14179,0,51356) #37630000C89C srgb(22%,0%,78%)
7,28: (16366,0,49169) #3FEE0000C011 srgb(25%,0%,75%)
8,28: (18552,0,46983) #48780000B787 srgb(28%,0%,72%)
9,28: (20739,0,44796) #51030000AEFC srgb(32%,0%,68%)
10,28: (22926,0,42609) #598E0000A671 srgb(35%,0%,65%)
11,28: (25113,0,40422) #621900009DE6 srgb(38%,0%,62%)
12,28: (27300,0,38235) #6AA40000955B srgb(42%,0%,58%)
13,28: (29487,0,36048) #732F00008CD0 srgb(45%,0%,55%)
14,28: (31674,0,33861) #7BBA00008445 srgb(48%,0%,52%)
15,28: (33861,0,31674) #844500007BBA srgb(52%,0%,48%)
16,28: (36048,0,29487) #8CD00000732F srgb(55%,0%,45%)
17,28: (38235,0,27300) #955B00006AA4 srgb(58%,0%,42%)
18,28: (40422,0,25113) #9DE600006219 srgb(62%,0%,38%)
19,28: (42609,0,22926) #A6710000598E srgb(65%,0%,35%)
20,28: (44796,0,20739) #AEFC00005103 srgb(68%,0%,32%)
21,28: (46983,0,18552) #B78700004878 srgb(72%,0%,28%)
22,28: (49169,0,16366) #C01100003FEE srgb(75%,0%,25%)
23,28: (51356,0,14179) #C89C00003763 srgb(78%,0%,22%)
24,28: (53543,0,11992) #D12700002ED8 srgb(82%,0%,18%)
25,28: (55730,0,9805) #D9B20000264D srgb(85%,0%,15%)
26,28: (57917,0,7618) #E23D00001DC2 srgb(88%,0%,12%)
27,28: (60104,0,5431) #EAC800001537 srgb(92%,0%,8%)
28,28: (62291,0,3244) #F35300000CAC srgb(95%,0%,5%)
29,28: (64478,0,1057) #FBDE00000421 srgb(98%,0%,2%)
0,29: (1057,0,64478) #04210000FBDE srgb(2%,0%,98%)
1,29: (3244,0,62291) #0CAC0000F353 srgb(5%,0%,95%)
2,29: (5431,0,60104) #15370000EAC8 srgb(8%,0%,92%)
3,29: (7618,0,57917) #1DC20000E23D srgb(12%,0%,88%)
4,29: (9805,0,55730) #264D0000D9B2 srgb(15%,0%,85%)
5,29: (11992,0,53543) #2ED80000D127 srgb(18%,0%,82%)
6,29: (14179,0,51356) #37630000C89C srgb(22%,0%,78%)
7,29: (16366,0,49169) #3FEE0000C011 srgb(25%,0%,75%)
8,29: (18552,0,46983) #48780000B787 srgb(28%,0%,72%)
9,29: (20739,0,44796) #51030000AEFC srgb(32%,0%,68%)
10,29: (22926,0,42609) #598E0000A671 srgb(35%,0%,65%)
11,29: (25113,0,40422) #621900009DE6 srgb(38%,0%,62%)
12,29: (27300,0,38235) #6AA40000955B srgb(42%,0%,58%)
13,29: (29487,0,36048) #732F00008CD0 srgb(45%,0%,55%)
14,29: (31674,0,33861) #7BBA00008445 srgb(48%,0%,52%)
15,29: (33861,0,31674) #844500007BBA srgb(52%,0%,48%)
16,29: (36048,0,29487) #8CD00000732F srgb(55%,0%,45%)
17,29: (38235,0,27300) #955B00006AA4 srgb(58%,0%,42%)
18,29: (40422,0,25113) #9DE600006219 srgb(62%,0%,38%)
19,29: (42609,0,22926) #A6710000598E srgb(65%,0%,35%)
20,29: (44796,0,20739) #AEFC00005103 srgb(68%,0%,32%)
21,29: (46983,0,18552) #B78700004878 srgb(72%,0%,28%)
22,29: (49169,0,16366) #C01100003FEE srgb(75%,0%,25%)
23,29: (51356,0,14179) #C89C00003763 srgb(78%,0%,22%)
24,29: (53543,0,11992) #D12700002ED8 srgb(82%,0%,18%)
25,29: (55730,0,9805) #D9B20000264D srgb(85%,0%,15%)
26,29: (57917,0,7618) #E23D00001DC2 srgb(88%,0%,12%)
27,29: (60104,0,5431) #EAC800001537 srgb(92%,0%,8%)
28,29: (62291,0,3244) #F35300000CAC srgb(95%,0%,5%)
29,29: (64478,0,1057) #FBDE00000421 srgb(98%,0%,2%)
Upvotes: 1
Reputation: 207818
In general you want to avoid copying large images around, or chunks of images because it is slow. It is often preferable to process as you go, rather than build a new data structure to process later.
So, with that in mind:
#!/usr/bin/env python3
from PIL import Image
import numpy as np
BLKSIZE=30
# Load image into Numpy array
im = np.array(Image.open('image.png').convert('RGB'))
for y in range(0, 900, BLKSIZE):
for x in range(0, 900, BLKSIZE):
view = im[y:y+BLKSIZE, x:x+BLKSIZE]
Rmean = np.mean(view[...,0])
Gmean = np.mean(view[...,1])
Bmean = np.mean(view[...,2])
print(f'Block {y},{x}, R:{Rmean:.2f}, G:{Gmean:.2f}, B:{Bmean:.2f}')
Sample Output - using Fred's image (@fmw42)
Block 0,0, R:4.13, G:4.13, B:4.13
Block 0,30, R:12.60, G:12.60, B:12.60
Block 0,60, R:21.13, G:21.13, B:21.13
Block 0,90, R:29.63, G:29.63, B:29.63
Block 0,120, R:38.13, G:38.13, B:38.13
Block 0,150, R:46.70, G:46.70, B:46.70
Block 0,180, R:55.13, G:55.13, B:55.13
Block 0,210, R:63.73, G:63.73, B:63.73
Block 0,240, R:72.13, G:72.13, B:72.13
Block 0,270, R:80.73, G:80.73, B:80.73
Block 0,300, R:89.17, G:89.17, B:89.17
Block 0,330, R:97.73, G:97.73, B:97.73
Block 0,360, R:106.23, G:106.23, B:106.23
Block 0,390, R:114.73, G:114.73, B:114.73
Block 0,420, R:123.27, G:123.27, B:123.27
Block 0,450, R:131.73, G:131.73, B:131.73
Block 0,480, R:140.27, G:140.27, B:140.27
Block 0,510, R:148.77, G:148.77, B:148.77
Block 0,540, R:157.27, G:157.27, B:157.27
Block 0,570, R:165.83, G:165.83, B:165.83
Block 0,600, R:174.27, G:174.27, B:174.27
Block 0,630, R:182.87, G:182.87, B:182.87
Block 0,660, R:191.27, G:191.27, B:191.27
Block 0,690, R:199.87, G:199.87, B:199.87
Block 0,720, R:208.30, G:208.30, B:208.30
Block 0,750, R:216.87, G:216.87, B:216.87
Block 0,780, R:225.37, G:225.37, B:225.37
Block 0,810, R:233.87, G:233.87, B:233.87
Block 0,840, R:242.40, G:242.40, B:242.40
Block 0,870, R:250.87, G:250.87, B:250.87
Block 30,0, R:4.13, G:4.13, B:4.13
Block 30,30, R:12.60, G:12.60, B:12.60
Block 30,60, R:21.13, G:21.13, B:21.13
...
...
Block 870,750, R:216.87, G:216.87, B:216.87
Block 870,780, R:225.37, G:225.37, B:225.37
Block 870,810, R:233.87, G:233.87, B:233.87
Block 870,840, R:242.40, G:242.40, B:242.40
Block 870,870, R:250.87, G:250.87, B:250.87
Upvotes: 1
Reputation: 207818
As you say you are open to suggestions, you could achieve what you ask in the shell with one line of ImageMagick which is installed on most Linux distros and is available for macOS and Windows.
So, in shell or Command Prompt, take an image, split it into 30x30 tiles, average contents of each tile by resizing to 1x1, append all 1x1 means to a new single row image and print each pixel of that image when represented as 8-bit in text format:
magick image.png -crop 30x30 -resize 1x1\! +append -depth 8 txt:
Sample Output
# ImageMagick pixel enumeration: 900,1,65535,rgb
0,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
1,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
2,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
3,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
4,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
5,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
6,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
7,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
8,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
9,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
10,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
11,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
12,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
13,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
14,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
15,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
16,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
17,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
18,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
19,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
20,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
21,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
22,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
23,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
24,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
25,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
26,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
27,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
28,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
29,0: (82.2696,63142.9,82.2696) #00F600 rgb(0,246,0)
30,0: (254.322,58412.4,254.322) #01E301 rgb(1,227,1)
31,0: (254.322,58412.4,254.322) #01E301 rgb(1,227,1)
32,0: (254.322,58412.4,254.322) #01E301 rgb(1,227,1)
Upvotes: 1
Reputation: 2046
There is some logical fault in the row_start and row_end variables. You dont need to use 2 variables for start and end.
Please make use of the below code and replace it in place of the while loop.
blocks=[]
while(row_start < height):
col_start = 0
while(col_start < width):
patch = pixel_array[row_start:row_start+30,col_start:col_start+30]
#print(patch.shape)
blocks.append(patch)
col_start+=30
#print(row_start,col_start)
row_start+=30
Now the blocks array will have all the 900 patches of size 30,30,3. I have hard coded the value 30, to extract the patch. Change the value to make it dynamic according to the use case.
Upvotes: 0