Reputation: 81
I am trying to write a code that can generate an checker board pattern. The final image size should be 100 x 100
, the checker board size 5 x 5
, such that each box has dimensions h/5
and w/5
. The code I have is wrong:
from PIL import Image, ImageDraw
h = 500
w = 500
img = Image.new("RGB", (h,w), (255, 0, 0)) # create a new 15x15 image
pixels = img.load() # create the pixel map
print("1")
for i in range (h):
for j in range(w):
if ((i + j)%2) != 0:
im = Image.new('RGB', (h//5, w//5), 'black')
else:
draw = ImageDraw.Draw(img, "RGBA")
draw.rectangle(((h//5, w//5), (i+.5, j+.5)), fill="blue")
print ("done")
img.show()
Upvotes: 2
Views: 3603
Reputation: 18925
I had the feeling, that accessing single pixels in Pillow using all those nested loops isn't the best idea performance-wise.
So, my idea would be to set up a small (m, n)
checker using (nested) lists, build a Pillow Image
object from that using putdata
, and simply resize
it to the desired size using the Image.NEAREST
resampling filter. I added some flexibility for choosing colors and image modes.
from itertools import chain
from math import ceil
from PIL import Image
m, n = (5, 5) # Checker dimension (x, y)
w, h = (100, 100) # Final image width and height
c1 = 0 # (224, 64, 64) # First color
c2 = 255 # (128, 128, 128) # Second color
mode = 'L' if isinstance(c1, int) else 'RGB' # Mode from first color
# Generate pixel-wise checker, even x dimension
if m % 2 == 0:
pixels = [[c1, c2] for i in range(int(m/2))] + \
[[c2, c1] for i in range(int(m/2))]
pixels = [list(chain(*pixels)) for i in range(ceil(n/2))]
# Generate pixel-wise checker, odd x dimension
else:
pixels = [[c1, c2] for i in range(ceil(m*n/2))]
# Generate final Pillow-compatible pixel values
pixels = list(chain(*pixels))[:(m*n)]
# Generate Pillow image from pixel values, resize to final image size, and save
checker = Image.new(mode, (m, n))
checker.putdata(pixels)
checker = checker.resize((w, h), Image.NEAREST)
checker.save('checker.png')
For the shown configuration, the output would be:
Switching to RGB, and altering m
, w
, and h
, we might get something like this:
As already pointed out in the other answers, if w
or h
are not whole integer factors of m
or n
, then you'll get somehow distorted output (m = n = 5
, w = h = 102
):
----------------------------------------
System information
----------------------------------------
Platform: Windows-10-10.0.16299-SP0
Python: 3.9.1
Pillow: 8.1.2
----------------------------------------
Upvotes: 2
Reputation: 477
I know it's already been answered, here's a way to loop over it differently
from PIL import Image
h = 500
w = 500
# You can also easily set the number of squares per row
number_of_square_across = 10
# You can also easily set the colors
color_one = (0, 0, 0)
color_two = (0, 0, 255)
length_of_square = h/number_of_square_across
length_of_two_squares = h/number_of_square_across*2
img = Image.new("RGB", (h, w), (255, 0, 0)) # create a new 15x15 image
pixels = img.load() # create the pixel map
for i in range(h):
# for every 100 pixels out of the total 500
# if its the first 50 pixels
if (i % length_of_two_squares) >= length_of_square:
for j in range(w):
if (j % length_of_two_squares) < length_of_square:
pixels[i,j] = color_one
else:
pixels[i,j] = color_two
# else its the second 50 pixels
else:
for j in range(w):
if (j % length_of_two_squares) >= length_of_square:
pixels[i,j] = color_one
else:
pixels[i,j] = color_two
print("done")
img.show()
Upvotes: 2
Reputation: 390
For anyone who reads this in the future and is looking for a general solution to make a checker board see here:
M, N = 10, 10
arr = [[0 for _ in range(N)] for _ in range(M)] # an M by N array
for i in range(M):
for j in range(N):
if (i&1)^(j&1): # if (i is odd and j is even) or (j is odd and i is even)
arr[i][j] = 1 # change the pixel from white to black
Solution tailored specifically to the OP's inquiry see here:
from PIL import Image, ImageDraw
h = 500
w = 500
img = Image.new("RGB", (h,w), (255, 0, 0)) # create a new 15x15 image
pixels = img.load() # create the pixel map
print ("1")
for i in range (h):
for j in range(w):
if (i&1)^(j&1):
pixels[i,j] = (0, 0, 0)
else:
pixels[i,j] = (0, 0, 255)
print ("done")
img.show()
# BIGGER BOX SIZE
from PIL import Image, ImageDraw
h = 500
w = 500
img = Image.new("RGB", (h,w), (255, 0, 0)) # create a new 15x15 image
pixels = img.load() # create the pixel map
print ("1")
box_size = 25
for i in range (0, h, box_size):
for j in range(0, w, box_size):
y, x = i // box_size, j // box_size
if (y&1)^(x&1):
for di in range(box_size):
for dj in range(box_size):
pixels[i+di,j+dj] = (0, 0, 0)
else:
for di in range(box_size):
for dj in range(box_size):
pixels[i+di,j+dj] = (0, 0, 255)
print ("done")
img.show()
This will get you the checker pattern for an array.
Upvotes: 1